blob: 925f6ceb3e3dfb316258dc2b2f72f0f440b1edc4 [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"
Andrew Scull2b5fbad2019-04-05 13:55:56 +010012
13/* Declare unsafe functions locally so they are not available globally. */
14void *memset(void *s, int c, size_t n);
Karl Meakin6027b4f2024-07-04 13:11:26 +010015void *memcpy(void *restrict dst, const void *src, size_t n);
Andrew Scull8fbd7ee2019-04-05 14:36:34 +010016void *memmove(void *dst, const void *src, size_t n);
Andrew Scull2b5fbad2019-04-05 13:55:56 +010017
18void memset_s(void *dest, rsize_t destsz, int ch, rsize_t count)
19{
Daniel Boulby8adf7482021-09-22 15:12:44 +010020 if (dest == NULL || destsz > RSIZE_MAX) {
21 panic("memset_s failed as either dest == NULL "
22 "or destsz > RSIZE_MAX.\n");
23 }
Andrew Scull2b5fbad2019-04-05 13:55:56 +010024
Andrew Walbrane52006c2019-10-22 18:01:28 +010025 /*
26 * Clang analyzer doesn't like us calling unsafe memory functions, so
27 * make it ignore this call.
28 */
Daniel Boulby8adf7482021-09-22 15:12:44 +010029 // NOLINTNEXTLINE
30 memset(dest, ch, (count <= destsz ? count : destsz));
Andrew Scull2b5fbad2019-04-05 13:55:56 +010031}
Andrew Sculla1aa2ba2019-04-05 11:49:02 +010032
33void 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
Karl Meakin8f046e42024-07-04 12:03:36 +010038 CHECK(dest != NULL);
39 CHECK(src != NULL);
Andrew Sculla1aa2ba2019-04-05 11:49:02 +010040
David Brazdil2246abe2019-08-23 12:21:06 +010041 /* Check count <= destsz <= RSIZE_MAX. */
Karl Meakin8f046e42024-07-04 12:03:36 +010042 CHECK(destsz <= RSIZE_MAX);
43 CHECK(count <= destsz);
Andrew Sculla1aa2ba2019-04-05 11:49:02 +010044
David Brazdil2246abe2019-08-23 12:21:06 +010045 /*
46 * Buffer overlap test.
47 * case a) `d < s` implies `s >= d+count`
48 * case b) `d > s` implies `d >= s+count`
49 */
Karl Meakin8f046e42024-07-04 12:03:36 +010050 CHECK(d != s);
51 CHECK(d < s || d >= (s + count));
52 CHECK(d > s || s >= (d + count));
Andrew Sculla1aa2ba2019-04-05 11:49:02 +010053
Daniel Boulby8adf7482021-09-22 15:12:44 +010054 /*
55 * Clang analyzer doesn't like us calling unsafe memory functions, so
56 * make it ignore this call.
57 */
58 // NOLINTNEXTLINE
Andrew Sculla1aa2ba2019-04-05 11:49:02 +010059 memcpy(dest, src, count);
Andrew Sculla1aa2ba2019-04-05 11:49:02 +010060}
Andrew Scull8fbd7ee2019-04-05 14:36:34 +010061
62void memmove_s(void *dest, rsize_t destsz, const void *src, rsize_t count)
63{
Karl Meakin8f046e42024-07-04 12:03:36 +010064 CHECK(dest != NULL);
65 CHECK(src != NULL);
Andrew Scull8fbd7ee2019-04-05 14:36:34 +010066
David Brazdil2246abe2019-08-23 12:21:06 +010067 /* Check count <= destsz <= RSIZE_MAX. */
Karl Meakin8f046e42024-07-04 12:03:36 +010068 CHECK(destsz <= RSIZE_MAX);
69 CHECK(count <= destsz);
Andrew Scull8fbd7ee2019-04-05 14:36:34 +010070
Daniel Boulby8adf7482021-09-22 15:12:44 +010071 /*
72 * Clang analyzer doesn't like us calling unsafe memory functions, so
73 * make it ignore this call.
74 */
75 // NOLINTNEXTLINE
Andrew Scull8fbd7ee2019-04-05 14:36:34 +010076 memmove(dest, src, count);
Andrew Scull8fbd7ee2019-04-05 14:36:34 +010077}
Andrew Scull55baca62019-04-05 14:56:20 +010078
David Brazdil2246abe2019-08-23 12:21:06 +010079/**
David Brazdil74e9c3b2019-08-28 11:09:08 +010080 * 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 */
86void *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/**
David Brazdil2246abe2019-08-23 12:21:06 +0100104 * 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 */
Andrew Scull55baca62019-04-05 14:56:20 +0100110size_t strnlen_s(const char *str, size_t strsz)
111{
Andrew Scull55baca62019-04-05 14:56:20 +0100112 if (str == NULL) {
113 return 0;
114 }
115
David Brazdil2246abe2019-08-23 12:21:06 +0100116 for (size_t i = 0; i < strsz; ++i) {
117 if (str[i] == '\0') {
118 return i;
119 }
Andrew Scull55baca62019-04-05 14:56:20 +0100120 }
121
David Brazdil2246abe2019-08-23 12:21:06 +0100122 /* NULL character not found. */
123 return strsz;
Andrew Scull55baca62019-04-05 14:56:20 +0100124}