blob: 4576118e024b60a19f7761dacc3a660538c6d9e8 [file] [log] [blame]
Andrew Scull2b5fbad2019-04-05 13:55:56 +01001/*
2 * Copyright 2019 The Hafnium Authors.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "hf/std.h"
18
David Brazdil74e9c3b2019-08-28 11:09:08 +010019#include "hf/check.h"
Andrew Scull2b5fbad2019-04-05 13:55:56 +010020
21/* Declare unsafe functions locally so they are not available globally. */
22void *memset(void *s, int c, size_t n);
Andrew Sculla1aa2ba2019-04-05 11:49:02 +010023void *memcpy(void *dst, const void *src, size_t n);
Andrew Scull8fbd7ee2019-04-05 14:36:34 +010024void *memmove(void *dst, const void *src, size_t n);
Andrew Scull2b5fbad2019-04-05 13:55:56 +010025
David Brazdil2246abe2019-08-23 12:21:06 +010026/*
27 * As per the C11 specification, mem*_s() operations fill the destination buffer
28 * if runtime constraint validation fails, assuming that `dest` and `destsz`
29 * are both valid.
30 */
31#define CHECK_OR_FILL(cond, dest, destsz, ch) \
32 do { \
33 if (!(cond)) { \
34 if ((dest) != NULL && (destsz) <= RSIZE_MAX) { \
35 memset_s((dest), (destsz), (ch), (destsz)); \
36 } \
37 panic("%s failed: " #cond, __func__); \
38 } \
39 } while (0)
40
41#define CHECK_OR_ZERO_FILL(cond, dest, destsz) \
42 CHECK_OR_FILL(cond, dest, destsz, '\0')
43
Andrew Scull2b5fbad2019-04-05 13:55:56 +010044void memset_s(void *dest, rsize_t destsz, int ch, rsize_t count)
45{
David Brazdil2246abe2019-08-23 12:21:06 +010046 CHECK_OR_FILL(dest != NULL, dest, destsz, ch);
Andrew Scull2b5fbad2019-04-05 13:55:56 +010047
David Brazdil2246abe2019-08-23 12:21:06 +010048 /* Check count <= destsz <= RSIZE_MAX. */
49 CHECK_OR_FILL(destsz <= RSIZE_MAX, dest, destsz, ch);
50 CHECK_OR_FILL(count <= destsz, dest, destsz, ch);
Andrew Scull2b5fbad2019-04-05 13:55:56 +010051
Andrew Walbrane52006c2019-10-22 18:01:28 +010052 /*
53 * Clang analyzer doesn't like us calling unsafe memory functions, so
54 * make it ignore this call.
55 */
56#ifndef __clang_analyzer__
Andrew Scull2b5fbad2019-04-05 13:55:56 +010057 memset(dest, ch, count);
Andrew Walbrane52006c2019-10-22 18:01:28 +010058#endif
Andrew Scull2b5fbad2019-04-05 13:55:56 +010059}
Andrew Sculla1aa2ba2019-04-05 11:49:02 +010060
61void memcpy_s(void *dest, rsize_t destsz, const void *src, rsize_t count)
62{
63 uintptr_t d = (uintptr_t)dest;
64 uintptr_t s = (uintptr_t)src;
65
David Brazdil2246abe2019-08-23 12:21:06 +010066 CHECK_OR_ZERO_FILL(dest != NULL, dest, destsz);
67 CHECK_OR_ZERO_FILL(src != NULL, dest, destsz);
Andrew Sculla1aa2ba2019-04-05 11:49:02 +010068
David Brazdil2246abe2019-08-23 12:21:06 +010069 /* Check count <= destsz <= RSIZE_MAX. */
70 CHECK_OR_ZERO_FILL(destsz <= RSIZE_MAX, dest, destsz);
71 CHECK_OR_ZERO_FILL(count <= destsz, dest, destsz);
Andrew Sculla1aa2ba2019-04-05 11:49:02 +010072
David Brazdil2246abe2019-08-23 12:21:06 +010073 /*
74 * Buffer overlap test.
75 * case a) `d < s` implies `s >= d+count`
76 * case b) `d > s` implies `d >= s+count`
77 */
78 CHECK_OR_ZERO_FILL(d != s, dest, destsz);
79 CHECK_OR_ZERO_FILL(d < s || d >= (s + count), dest, destsz);
80 CHECK_OR_ZERO_FILL(d > s || s >= (d + count), dest, destsz);
Andrew Sculla1aa2ba2019-04-05 11:49:02 +010081
Andrew Walbrane52006c2019-10-22 18:01:28 +010082#ifndef __clang_analyzer__
Andrew Sculla1aa2ba2019-04-05 11:49:02 +010083 memcpy(dest, src, count);
Andrew Walbrane52006c2019-10-22 18:01:28 +010084#endif
Andrew Sculla1aa2ba2019-04-05 11:49:02 +010085}
Andrew Scull8fbd7ee2019-04-05 14:36:34 +010086
87void memmove_s(void *dest, rsize_t destsz, const void *src, rsize_t count)
88{
David Brazdil2246abe2019-08-23 12:21:06 +010089 CHECK_OR_ZERO_FILL(dest != NULL, dest, destsz);
90 CHECK_OR_ZERO_FILL(src != NULL, dest, destsz);
Andrew Scull8fbd7ee2019-04-05 14:36:34 +010091
David Brazdil2246abe2019-08-23 12:21:06 +010092 /* Check count <= destsz <= RSIZE_MAX. */
93 CHECK_OR_ZERO_FILL(destsz <= RSIZE_MAX, dest, destsz);
94 CHECK_OR_ZERO_FILL(count <= destsz, dest, destsz);
Andrew Scull8fbd7ee2019-04-05 14:36:34 +010095
Andrew Walbrane52006c2019-10-22 18:01:28 +010096#ifndef __clang_analyzer__
Andrew Scull8fbd7ee2019-04-05 14:36:34 +010097 memmove(dest, src, count);
Andrew Walbrane52006c2019-10-22 18:01:28 +010098#endif
Andrew Scull8fbd7ee2019-04-05 14:36:34 +010099}
Andrew Scull55baca62019-04-05 14:56:20 +0100100
David Brazdil2246abe2019-08-23 12:21:06 +0100101/**
David Brazdil74e9c3b2019-08-28 11:09:08 +0100102 * Finds the first occurrence of character `ch` in the first `count` bytes of
103 * memory pointed to by `ptr`.
104 *
105 * Returns NULL if `ch` is not found.
106 * Panics if `ptr` is NULL (undefined behaviour).
107 */
108void *memchr(const void *ptr, int ch, size_t count)
109{
110 size_t i;
111 const unsigned char *p = (const unsigned char *)ptr;
112
113 CHECK(ptr != NULL);
114
115 /* Iterate over at most `strsz` characters of `str`. */
116 for (i = 0; i < count; ++i) {
117 if (p[i] == (unsigned char)ch) {
118 return (void *)(&p[i]);
119 }
120 }
121
122 return NULL;
123}
124
125/**
David Brazdil2246abe2019-08-23 12:21:06 +0100126 * Returns the length of the null-terminated byte string `str`, examining at
127 * most `strsz` bytes.
128 *
129 * If `str` is a NULL pointer, it returns zero.
130 * If a NULL character is not found, it returns `strsz`.
131 */
Andrew Scull55baca62019-04-05 14:56:20 +0100132size_t strnlen_s(const char *str, size_t strsz)
133{
Andrew Scull55baca62019-04-05 14:56:20 +0100134 if (str == NULL) {
135 return 0;
136 }
137
David Brazdil2246abe2019-08-23 12:21:06 +0100138 for (size_t i = 0; i < strsz; ++i) {
139 if (str[i] == '\0') {
140 return i;
141 }
Andrew Scull55baca62019-04-05 14:56:20 +0100142 }
143
David Brazdil2246abe2019-08-23 12:21:06 +0100144 /* NULL character not found. */
145 return strsz;
Andrew Scull55baca62019-04-05 14:56:20 +0100146}