diff --git a/src/c2.c b/src/c2.c index 8f46f5e8..7f21b603 100644 --- a/src/c2.c +++ b/src/c2.c @@ -1521,6 +1521,10 @@ static const char *c2_condition_to_str2(const c2_ptr_t ptr) { return buf; } +const char *c2_lptr_to_str(const c2_lptr_t *ptr) { + return c2_condition_to_str2(ptr->ptr); +} + static inline bool c2_int_op(const c2_l_t *leaf, size_t ntargets, const int64_t *targets) { for (size_t i = 0; i < ntargets; ++i) { long long tgt = targets[i]; diff --git a/src/c2.h b/src/c2.h index 90a3dca1..bd02ee43 100644 --- a/src/c2.h +++ b/src/c2.h @@ -29,6 +29,7 @@ struct managed_win; typedef void (*c2_userdata_free)(void *); c2_lptr_t *c2_parse(c2_lptr_t **pcondlst, const char *pattern, void *data); +const char *c2_lptr_to_str(const c2_lptr_t *ptr); c2_lptr_t *c2_free_lptr(c2_lptr_t *lp, c2_userdata_free f); diff --git a/src/fuzzer/c2.c b/src/fuzzer/c2.c index 078116d4..044cf8e5 100644 --- a/src/fuzzer/c2.c +++ b/src/fuzzer/c2.c @@ -2,6 +2,7 @@ #include "c2.h" #include #include +#include #include "config.h" #include "log.h" @@ -14,7 +15,37 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { return 0; } c2_lptr_t *cond = c2_parse(NULL, (char *)data, NULL); - (void)cond; - (void)size; - return 0; // Values other than 0 and -1 are reserved for future use. -} \ No newline at end of file + if (!cond) { + return 0; + } + + // If we can parse it, we check if it roundtrips. + // Except when the input or the stringified condition has ':' at the second + // position, because that becomes a "legacy" pattern and is parsed differently. + char *str = strdup(c2_lptr_to_str(cond)); + c2_free_lptr(cond, NULL); + if (str[1] == ':') { + free(str); + return 0; + } + + c2_lptr_t *cond2 = c2_parse(NULL, str, NULL); + // The stringified condition could legitimately fail to parse, for example, + // "a=1 || b=2 || c=3 || ... ", when stringified, will be "((((((a=1 || b=2) || + // c=3) || ...)", which will fail to parse because of the parenthese nest level + // limit. + if (cond2 == NULL) { + free(str); + return 0; + } + + const char *str2 = c2_lptr_to_str(cond2); + c2_free_lptr(cond2, NULL); + if (strcmp(str, str2) != 0) { + fprintf(stderr, "Mismatch: %s != %s\n", str, str2); + abort(); + } + + free(str); + return 0; +}