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