blob: ec4c9641f0556a22fb1fa5942540bc936a04b02f [file] [log] [blame]
Andrew Scull2b5fbad2019-04-05 13:55:56 +01001/*
2 * Copyright 2019 The Hafnium Authors.
3 *
Andrew Walbrane959ec12020-06-17 15:01:09 +01004 * 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.
Andrew Scull2b5fbad2019-04-05 13:55:56 +01007 */
8
9#include "hf/std.h"
10
David Brazdil74e9c3b2019-08-28 11:09:08 +010011#include "hf/check.h"
Karl Meakin48368642024-07-16 13:36:01 +010012#include "hf/panic.h"
Andrew Scull2b5fbad2019-04-05 13:55:56 +010013
14/* Declare unsafe functions locally so they are not available globally. */
15void *memset(void *s, int c, size_t n);
Karl Meakin6027b4f2024-07-04 13:11:26 +010016void *memcpy(void *restrict dst, const void *src, size_t n);
Andrew Scull8fbd7ee2019-04-05 14:36:34 +010017void *memmove(void *dst, const void *src, size_t n);
Andrew Scull2b5fbad2019-04-05 13:55:56 +010018
19void memset_s(void *dest, rsize_t destsz, int ch, rsize_t count)
20{
Daniel Boulby8adf7482021-09-22 15:12:44 +010021 if (dest == NULL || destsz > RSIZE_MAX) {
22 panic("memset_s failed as either dest == NULL "
23 "or destsz > RSIZE_MAX.\n");
24 }
Andrew Scull2b5fbad2019-04-05 13:55:56 +010025
Andrew Walbrane52006c2019-10-22 18:01:28 +010026 /*
27 * Clang analyzer doesn't like us calling unsafe memory functions, so
28 * make it ignore this call.
29 */
Daniel Boulby8adf7482021-09-22 15:12:44 +010030 // NOLINTNEXTLINE
31 memset(dest, ch, (count <= destsz ? count : destsz));
Andrew Scull2b5fbad2019-04-05 13:55:56 +010032}
Andrew Sculla1aa2ba2019-04-05 11:49:02 +010033
Karl Meakin48368642024-07-16 13:36:01 +010034/* Check the preconditions for memcpy and panic if they are not upheld. */
35void memcpy_check_preconditions(void *dest, rsize_t destsz, const void *src,
36 rsize_t count, size_t alignment)
Andrew Sculla1aa2ba2019-04-05 11:49:02 +010037{
38 uintptr_t d = (uintptr_t)dest;
39 uintptr_t s = (uintptr_t)src;
40
Karl Meakin48368642024-07-16 13:36:01 +010041 if (dest == NULL) {
42 panic("memcpy: dest == NULL\n");
43 }
44 if (src == NULL) {
45 panic("memcpy: src == NULL\n");
46 }
Andrew Sculla1aa2ba2019-04-05 11:49:02 +010047
David Brazdil2246abe2019-08-23 12:21:06 +010048 /* Check count <= destsz <= RSIZE_MAX. */
Karl Meakin48368642024-07-16 13:36:01 +010049 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 }
Andrew Sculla1aa2ba2019-04-05 11:49:02 +010056
David Brazdil2246abe2019-08-23 12:21:06 +010057 /*
58 * Buffer overlap test.
59 * case a) `d < s` implies `s >= d+count`
60 * case b) `d > s` implies `d >= s+count`
61 */
Karl Meakin48368642024-07-16 13:36:01 +010062 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
77void memcpy_s(void *dest, rsize_t destsz, const void *src, rsize_t count)
78{
79 memcpy_check_preconditions(dest, destsz, src, count, 1);
Andrew Sculla1aa2ba2019-04-05 11:49:02 +010080
Daniel Boulby8adf7482021-09-22 15:12:44 +010081 /*
82 * Clang analyzer doesn't like us calling unsafe memory functions, so
83 * make it ignore this call.
84 */
85 // NOLINTNEXTLINE
Andrew Sculla1aa2ba2019-04-05 11:49:02 +010086 memcpy(dest, src, count);
Andrew Sculla1aa2ba2019-04-05 11:49:02 +010087}
Andrew Scull8fbd7ee2019-04-05 14:36:34 +010088
89void memmove_s(void *dest, rsize_t destsz, const void *src, rsize_t count)
90{
Karl Meakin48368642024-07-16 13:36:01 +010091 if (dest == NULL) {
92 panic("memove: dest == NULL\n");
93 }
94 if (src == NULL) {
95 panic("memove: src == NULL\n");
96 }
Andrew Scull8fbd7ee2019-04-05 14:36:34 +010097
David Brazdil2246abe2019-08-23 12:21:06 +010098 /* Check count <= destsz <= RSIZE_MAX. */
Karl Meakin48368642024-07-16 13:36:01 +010099 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 }
Andrew Scull8fbd7ee2019-04-05 14:36:34 +0100106
Daniel Boulby8adf7482021-09-22 15:12:44 +0100107 /*
108 * Clang analyzer doesn't like us calling unsafe memory functions, so
109 * make it ignore this call.
110 */
111 // NOLINTNEXTLINE
Andrew Scull8fbd7ee2019-04-05 14:36:34 +0100112 memmove(dest, src, count);
Andrew Scull8fbd7ee2019-04-05 14:36:34 +0100113}
Andrew Scull55baca62019-04-05 14:56:20 +0100114
David Brazdil2246abe2019-08-23 12:21:06 +0100115/**
David Brazdil74e9c3b2019-08-28 11:09:08 +0100116 * 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 */
122void *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/**
David Brazdil2246abe2019-08-23 12:21:06 +0100140 * 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 */
Andrew Scull55baca62019-04-05 14:56:20 +0100146size_t strnlen_s(const char *str, size_t strsz)
147{
Andrew Scull55baca62019-04-05 14:56:20 +0100148 if (str == NULL) {
149 return 0;
150 }
151
David Brazdil2246abe2019-08-23 12:21:06 +0100152 for (size_t i = 0; i < strsz; ++i) {
153 if (str[i] == '\0') {
154 return i;
155 }
Andrew Scull55baca62019-04-05 14:56:20 +0100156 }
157
David Brazdil2246abe2019-08-23 12:21:06 +0100158 /* NULL character not found. */
159 return strsz;
Andrew Scull55baca62019-04-05 14:56:20 +0100160}