From 6a765ed88fa289a9b7350e77af0e83a3d1532c69 Mon Sep 17 00:00:00 2001 From: Peter Limkilde Svendsen Date: Sun, 17 Nov 2024 16:18:14 +0000 Subject: [PATCH] Implement memmem() --- src/header/string/mod.rs | 36 +++++++++++++++++++ tests/Makefile | 1 + .../expected/bins_static/string/memmem.stderr | 0 .../expected/bins_static/string/memmem.stdout | 0 tests/string/memmem.c | 31 ++++++++++++++++ 5 files changed, 68 insertions(+) create mode 100644 tests/expected/bins_static/string/memmem.stderr create mode 100644 tests/expected/bins_static/string/memmem.stdout create mode 100644 tests/string/memmem.c diff --git a/src/header/string/mod.rs b/src/header/string/mod.rs index 6dd354619c..f7c19bffc7 100644 --- a/src/header/string/mod.rs +++ b/src/header/string/mod.rs @@ -88,6 +88,42 @@ pub unsafe extern "C" fn memcpy(s1: *mut c_void, s2: *const c_void, n: size_t) - s1 } +/// See . +/// +/// # Safety +/// The caller must ensure that: +/// - `haystack` is convertible to a `&[u8]` with length `haystacklen`, and +/// - `needle` is convertible to a `&[u8]` with length `needlelen`. +#[no_mangle] +pub unsafe extern "C" fn memmem( + haystack: *const c_void, + haystacklen: size_t, + needle: *const c_void, + needlelen: size_t, +) -> *mut c_void { + match needlelen { + // Required to satisfy spec (would otherwise cause .windows() to panic) + 0 => haystack.cast_mut(), + _ => { + // SAFETY: the caller is required to ensure that the provided + // pointers are valid. + let haystack_slice = + unsafe { slice::from_raw_parts(haystack.cast::(), haystacklen) }; + let needle_slice = unsafe { slice::from_raw_parts(needle.cast::(), needlelen) }; + + // At this point, .windows() will receive a nonzero `needlelen` and + // thus not panic. + match haystack_slice + .windows(needlelen) + .find(|&haystack_window| haystack_window == needle_slice) + { + Some(match_slice) => match_slice.as_ptr().cast_mut().cast(), + None => ptr::null_mut(), + } + } + } +} + #[no_mangle] pub unsafe extern "C" fn memmove(s1: *mut c_void, s2: *const c_void, n: size_t) -> *mut c_void { if s2 < s1 as *const c_void { diff --git a/tests/Makefile b/tests/Makefile index dcbcdf7614..c0bcb377f3 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -73,6 +73,7 @@ EXPECT_NAMES=\ stdlib/strtoul \ stdlib/system \ string/mem \ + string/memmem \ string/strcat \ string/strchr \ string/strcpy \ diff --git a/tests/expected/bins_static/string/memmem.stderr b/tests/expected/bins_static/string/memmem.stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/bins_static/string/memmem.stdout b/tests/expected/bins_static/string/memmem.stdout new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/string/memmem.c b/tests/string/memmem.c new file mode 100644 index 0000000000..c3ff546428 --- /dev/null +++ b/tests/string/memmem.c @@ -0,0 +1,31 @@ +#include +#include +#include +#include + +#include "test_helpers.h" + +int main(void) { + uint8_t haystack[] = {1, 1, 2, 1, 2, 3, 1, 2, 3, 4}; + uint8_t present_needle[] = {1, 2, 3}; + uint8_t absent_needle[] = {1, 2, 3, 4, 5}; + uint8_t long_needle[] = {1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1}; + + size_t haystacklen = sizeof(haystack); + size_t present_needlelen = sizeof(present_needle); + size_t absent_needlelen = sizeof(absent_needle); + size_t long_needlelen = sizeof(long_needle); + + uint8_t *present_needle_match_ptr = memmem(haystack, haystacklen, present_needle, present_needlelen); + assert(present_needle_match_ptr == haystack + 3); + + uint8_t *absent_needle_match_ptr = memmem(haystack, haystacklen, absent_needle, absent_needlelen); + assert(absent_needle_match_ptr == NULL); + + // Explicitly specified to return haystack for needlelen == 0. + uint8_t *zero_needle_match_ptr = memmem(haystack, haystacklen, present_needle, 0); + assert(zero_needle_match_ptr == haystack); + + uint8_t *long_needle_match_ptr = memmem(haystack, haystacklen, long_needle, long_needlelen); + assert(long_needle_match_ptr == NULL); +}