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 
13 /* Declare unsafe functions locally so they are not available globally. */
14 void *memset(void *s, int c, size_t n);
15 void *memcpy(void *restrict dst, const void *src, size_t n);
16 void *memmove(void *dst, const void *src, size_t n);
17 
memset_s(void * dest,rsize_t destsz,int ch,rsize_t count)18 void memset_s(void *dest, rsize_t destsz, int ch, rsize_t count)
19 {
20 	if (dest == NULL || destsz > RSIZE_MAX) {
21 		panic("memset_s failed as either dest == NULL "
22 		      "or destsz > RSIZE_MAX.\n");
23 	}
24 
25 	/*
26 	 * Clang analyzer doesn't like us calling unsafe memory functions, so
27 	 * make it ignore this call.
28 	 */
29 	// NOLINTNEXTLINE
30 	memset(dest, ch, (count <= destsz ? count : destsz));
31 }
32 
memcpy_s(void * dest,rsize_t destsz,const void * src,rsize_t count)33 void memcpy_s(void *dest, rsize_t destsz, const void *src, rsize_t count)
34 {
35 	uintptr_t d = (uintptr_t)dest;
36 	uintptr_t s = (uintptr_t)src;
37 
38 	CHECK(dest != NULL);
39 	CHECK(src != NULL);
40 
41 	/* Check count <= destsz <= RSIZE_MAX. */
42 	CHECK(destsz <= RSIZE_MAX);
43 	CHECK(count <= destsz);
44 
45 	/*
46 	 * Buffer overlap test.
47 	 * case a) `d < s` implies `s >= d+count`
48 	 * case b) `d > s` implies `d >= s+count`
49 	 */
50 	CHECK(d != s);
51 	CHECK(d < s || d >= (s + count));
52 	CHECK(d > s || s >= (d + count));
53 
54 	/*
55 	 * Clang analyzer doesn't like us calling unsafe memory functions, so
56 	 * make it ignore this call.
57 	 */
58 	// NOLINTNEXTLINE
59 	memcpy(dest, src, count);
60 }
61 
memmove_s(void * dest,rsize_t destsz,const void * src,rsize_t count)62 void memmove_s(void *dest, rsize_t destsz, const void *src, rsize_t count)
63 {
64 	CHECK(dest != NULL);
65 	CHECK(src != NULL);
66 
67 	/* Check count <= destsz <= RSIZE_MAX. */
68 	CHECK(destsz <= RSIZE_MAX);
69 	CHECK(count <= destsz);
70 
71 	/*
72 	 * Clang analyzer doesn't like us calling unsafe memory functions, so
73 	 * make it ignore this call.
74 	 */
75 	// NOLINTNEXTLINE
76 	memmove(dest, src, count);
77 }
78 
79 /**
80  * Finds the first occurrence of character `ch` in the first `count` bytes of
81  * memory pointed to by `ptr`.
82  *
83  * Returns NULL if `ch` is not found.
84  * Panics if `ptr` is NULL (undefined behaviour).
85  */
memchr(const void * ptr,int ch,size_t count)86 void *memchr(const void *ptr, int ch, size_t count)
87 {
88 	size_t i;
89 	const unsigned char *p = (const unsigned char *)ptr;
90 
91 	CHECK(ptr != NULL);
92 
93 	/* Iterate over at most `strsz` characters of `str`. */
94 	for (i = 0; i < count; ++i) {
95 		if (p[i] == (unsigned char)ch) {
96 			return (void *)(&p[i]);
97 		}
98 	}
99 
100 	return NULL;
101 }
102 
103 /**
104  * Returns the length of the null-terminated byte string `str`, examining at
105  * most `strsz` bytes.
106  *
107  * If `str` is a NULL pointer, it returns zero.
108  * If a NULL character is not found, it returns `strsz`.
109  */
strnlen_s(const char * str,size_t strsz)110 size_t strnlen_s(const char *str, size_t strsz)
111 {
112 	if (str == NULL) {
113 		return 0;
114 	}
115 
116 	for (size_t i = 0; i < strsz; ++i) {
117 		if (str[i] == '\0') {
118 			return i;
119 		}
120 	}
121 
122 	/* NULL character not found. */
123 	return strsz;
124 }
125