diff --git a/libc/fuzzing/string/strcmp_fuzz.cpp b/libc/fuzzing/string/strcmp_fuzz.cpp --- a/libc/fuzzing/string/strcmp_fuzz.cpp +++ b/libc/fuzzing/string/strcmp_fuzz.cpp @@ -13,31 +13,62 @@ #include #include -extern "C" int LLVMFuzzerTestTwoInputs(const uint8_t *data1, size_t size1, - const uint8_t *data2, size_t size2) { - // Verify each data source contains at least one character. - if (!size1 || !size2) +// The general structure is to take the value of the first byte, set size1 to +// that value, and add the null terminator. size2 will then contain the rest of +// the bytes in data. For example, with inputs ([2, 6, 4, 8, 0], 5): +// size1: data[0] = 2 +// data1: [2, 6] + '\0' = [2, 6, '\0'] +// size2: size - size1 = 3 +// data2: [4, 8, '\0'] +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + // Verify the size is at least 1. + if (!size) return 0; - // Verify that the final character is the null terminator. - if (data1[size1 - 1] != '\0' || data2[size2 - 1] != '\0') + + const size_t size1 = (data[0] <= size ? data[0] : size); + const size_t size2 = size - size1; + + // The first size will always be at least 1 since + // we need to append the null terminator. The second size + // needs to be checked since it must also contain the null + // terminator. + if (!size2) + return 0; + + // Copy the data into new containers. + // Add one for null terminator. + uint8_t *data1 = new uint8_t[size1 + 1]; + if (!data1) + __builtin_trap(); + size_t i; + for (i = 0; i < size1; ++i) + data1[i] = data[i]; + data1[size1] = '\0'; // Add null terminator to data1. + + uint8_t *data2 = new uint8_t[size2]; + if (!data2) + __builtin_trap(); + for (size_t j = 0; j < size2; ++i, ++j) + data2[j] = data[i]; + // Verify the second string is null-terminated. + if (data2[size2 - 1] != '\0') return 0; const char *s1 = reinterpret_cast(data1); const char *s2 = reinterpret_cast(data2); - const size_t minimum_size = size1 < size2 ? size1 : size2; - // Iterate through until either the minimum size is hit, // a character is the null terminator, or the first set // of differed bytes between s1 and s2 are found. // No bytes following a null byte should be compared. - size_t i; - for (i = 0; i < minimum_size; ++i) { - if (!s1[i] || s1[i] != s2[i]) + const size_t minimum_size = size1 < size2 ? size1 : size2; + size_t k; + for (k = 0; k < minimum_size; ++k) { + if (!s1[k] || s1[k] != s2[k]) break; } - int expected_result = s1[i] - s2[i]; + int expected_result = s1[k] - s2[k]; int actual_result = __llvm_libc::strcmp(s1, s2); // The expected result should be the difference between the first non-equal @@ -48,10 +79,13 @@ // Verify reversed operands. This should be the negated value of the previous // result, except of course if the previous result was zero. - expected_result = s2[i] - s1[i]; + expected_result = s2[k] - s1[k]; actual_result = __llvm_libc::strcmp(s2, s1); if (expected_result != actual_result) __builtin_trap(); + delete[] data1; + delete[] data2; + return 0; -} +} \ No newline at end of file