1 /*
2 * Copyright 2019 The Hafnium Authors.
3 *
4 * Use of this source code is governed by a BSD-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/BSD-3-Clause.
7 */
8
9 #include "hf/std.h"
10
11 #include "hf/check.h"
12 #include "hf/panic.h"
13
14 /* Declare unsafe functions locally so they are not available globally. */
15 void *memset(void *s, int c, size_t n);
16 void *memcpy(void *restrict dst, const void *src, size_t n);
17 void *memmove(void *dst, const void *src, size_t n);
18
memset_s(void * dest,rsize_t destsz,int ch,rsize_t count)19 void memset_s(void *dest, rsize_t destsz, int ch, rsize_t count)
20 {
21 if (dest == NULL || destsz > RSIZE_MAX) {
22 panic("memset_s failed as either dest == NULL "
23 "or destsz > RSIZE_MAX.\n");
24 }
25
26 /*
27 * Clang analyzer doesn't like us calling unsafe memory functions, so
28 * make it ignore this call.
29 */
30 // NOLINTNEXTLINE
31 memset(dest, ch, (count <= destsz ? count : destsz));
32 }
33
34 /* Check the preconditions for memcpy and panic if they are not upheld. */
memcpy_check_preconditions(void * dest,rsize_t destsz,const void * src,rsize_t count,size_t alignment)35 void memcpy_check_preconditions(void *dest, rsize_t destsz, const void *src,
36 rsize_t count, size_t alignment)
37 {
38 uintptr_t d = (uintptr_t)dest;
39 uintptr_t s = (uintptr_t)src;
40
41 if (dest == NULL) {
42 panic("memcpy: dest == NULL\n");
43 }
44 if (src == NULL) {
45 panic("memcpy: src == NULL\n");
46 }
47
48 /* Check count <= destsz <= RSIZE_MAX. */
49 if (destsz > RSIZE_MAX) {
50 panic("memcpy: destsz > RSIZE_MAX (%u > %u)\n", destsz,
51 RSIZE_MAX);
52 }
53 if (count > destsz) {
54 panic("memcpy: destsz > count (%u > %u)\n", destsz, count);
55 }
56
57 /*
58 * Buffer overlap test.
59 * case a) `d < s` implies `s >= d+count`
60 * case b) `d > s` implies `d >= s+count`
61 */
62 if (d == s || !(d < s || d >= (s + count)) ||
63 !(d > s || s >= (d + count))) {
64 panic("memcpy: dest and src overlap\n");
65 }
66
67 if (!is_aligned(dest, alignment)) {
68 panic("memcpy: dest not aligned (%p %% %u == %u)\n", dest,
69 alignment, d % alignment);
70 }
71 if (!is_aligned(src, alignment)) {
72 panic("memcpy: src not aligned (%p %% %u == %u)\n", src,
73 alignment, s % alignment);
74 }
75 }
76
memcpy_s(void * dest,rsize_t destsz,const void * src,rsize_t count)77 void memcpy_s(void *dest, rsize_t destsz, const void *src, rsize_t count)
78 {
79 memcpy_check_preconditions(dest, destsz, src, count, 1);
80
81 /*
82 * Clang analyzer doesn't like us calling unsafe memory functions, so
83 * make it ignore this call.
84 */
85 // NOLINTNEXTLINE
86 memcpy(dest, src, count);
87 }
88
memmove_s(void * dest,rsize_t destsz,const void * src,rsize_t count)89 void memmove_s(void *dest, rsize_t destsz, const void *src, rsize_t count)
90 {
91 if (dest == NULL) {
92 panic("memove: dest == NULL\n");
93 }
94 if (src == NULL) {
95 panic("memove: src == NULL\n");
96 }
97
98 /* Check count <= destsz <= RSIZE_MAX. */
99 if (destsz > RSIZE_MAX) {
100 panic("memmove: destsz > RSIZE_MAX (%u > %u)\n", destsz,
101 RSIZE_MAX);
102 }
103 if (count > destsz) {
104 panic("memmove: count > destsz (%u > %u)\n", count, destsz);
105 }
106
107 /*
108 * Clang analyzer doesn't like us calling unsafe memory functions, so
109 * make it ignore this call.
110 */
111 // NOLINTNEXTLINE
112 memmove(dest, src, count);
113 }
114
115 /**
116 * Finds the first occurrence of character `ch` in the first `count` bytes of
117 * memory pointed to by `ptr`.
118 *
119 * Returns NULL if `ch` is not found.
120 * Panics if `ptr` is NULL (undefined behaviour).
121 */
memchr(const void * ptr,int ch,size_t count)122 void *memchr(const void *ptr, int ch, size_t count)
123 {
124 size_t i;
125 const unsigned char *p = (const unsigned char *)ptr;
126
127 CHECK(ptr != NULL);
128
129 /* Iterate over at most `strsz` characters of `str`. */
130 for (i = 0; i < count; ++i) {
131 if (p[i] == (unsigned char)ch) {
132 return (void *)(&p[i]);
133 }
134 }
135
136 return NULL;
137 }
138
139 /**
140 * Returns the length of the null-terminated byte string `str`, examining at
141 * most `strsz` bytes.
142 *
143 * If `str` is a NULL pointer, it returns zero.
144 * If a NULL character is not found, it returns `strsz`.
145 */
strnlen_s(const char * str,size_t strsz)146 size_t strnlen_s(const char *str, size_t strsz)
147 {
148 if (str == NULL) {
149 return 0;
150 }
151
152 for (size_t i = 0; i < strsz; ++i) {
153 if (str[i] == '\0') {
154 return i;
155 }
156 }
157
158 /* NULL character not found. */
159 return strsz;
160 }
161