1 //===-- strstr_fuzz.cpp ---------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 /// Fuzzing test for llvm-libc strstr implementation.
11 //===----------------------------------------------------------------------===//
13 #include "src/string/strlen.h"
14 #include "src/string/strstr.h"
18 // Simple loop to compare two strings up to a size n.
19 static int simple_memcmp(const char *left
, const char *right
, size_t n
) {
20 for (; n
&& *left
== *right
; ++left
, ++right
, --n
)
22 return n
? *left
- *right
: 0;
25 // The general structure is to take the value of the first byte, set size1 to
26 // that value, and add the null terminator. size2 will then contain the rest of
28 // For example, with inputs (data={2, 6, 4, 8, 0}, size=5):
30 // data1: {2, 6} + '\0' = {2, 6, '\0'}
31 // size2: size - size1 = 3
32 // data2: {4, 8, '\0'}
33 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data
, size_t size
) {
34 // Verify the size is at least 1 and the data is null terminated.
35 if (!size
|| data
[size
- 1] != '\0')
37 const size_t size1
= (data
[0] <= size
? data
[0] : size
);
38 // The first size will always be at least 1 since
39 // we need to append the null terminator. The second size
40 // needs to be checked since it must also contain the null
42 if (size
- size1
== 0)
45 // Copy the data into a new container.
46 uint8_t *container
= new uint8_t[size1
+ 1];
51 for (i
= 0; i
< size1
; ++i
)
52 container
[i
] = data
[i
];
53 container
[size1
] = '\0'; // Add null terminator to container.
55 const char *needle
= reinterpret_cast<const char *>(container
);
56 const char *haystack
= reinterpret_cast<const char *>(data
+ i
);
57 const char *result
= LIBC_NAMESPACE::strstr(haystack
, needle
);
59 // A null terminator may exist earlier in each, so this needs to be recorded.
60 const size_t haystack_size
= LIBC_NAMESPACE::strlen(haystack
);
61 const size_t needle_size
= LIBC_NAMESPACE::strlen(needle
);
64 // The needle is in the haystack.
65 // 1. Verify that the result matches the needle.
66 if (simple_memcmp(needle
, result
, needle_size
) != 0)
69 const char *haystack_ptr
= haystack
;
70 // 2. Verify that the result is the first occurrence of the needle.
71 for (; haystack_ptr
!= result
; ++haystack_ptr
) {
72 if (simple_memcmp(needle
, haystack_ptr
, needle_size
) == 0)
73 __builtin_trap(); // There was an earlier occurrence of the needle.
76 // No result was found. Verify that the needle doesn't exist within the
78 for (size_t i
= 0; i
+ needle_size
< haystack_size
; ++i
) {
79 if (simple_memcmp(needle
, haystack
+ i
, needle_size
) == 0)
80 __builtin_trap(); // There was an earlier occurrence of the needle.