From 58bd4aa3cce46d2e054be1a197f8a17372159ed2 Mon Sep 17 00:00:00 2001 From: ph10 Date: Sat, 20 May 2017 14:28:11 +0000 Subject: [PATCH] Add a call to pcre2_dfa_match() to the fuzzer driver. --- src/pcre2_fuzzsupport.c | 85 ++++++++++++++++++++++++++++++----------- 1 file changed, 62 insertions(+), 23 deletions(-) diff --git a/src/pcre2_fuzzsupport.c b/src/pcre2_fuzzsupport.c index a2621cd..7e13b5e 100644 --- a/src/pcre2_fuzzsupport.c +++ b/src/pcre2_fuzzsupport.c @@ -19,6 +19,8 @@ Written by Philip Hazel, October 2016 #define MAX_MATCH_SIZE 1000 +#define DFA_WORKSPACE_COUNT 100 + #define ALLOWED_COMPILE_OPTIONS \ (PCRE2_ANCHORED|PCRE2_ALLOW_EMPTY_CLASS|PCRE2_ALT_BSUX|PCRE2_ALT_CIRCUMFLEX| \ PCRE2_ALT_VERBNAMES|PCRE2_AUTO_CALLOUT|PCRE2_CASELESS|PCRE2_DOLLAR_ENDONLY| \ @@ -33,9 +35,9 @@ Written by Philip Hazel, October 2016 (PCRE2_ANCHORED|PCRE2_ENDANCHORED|PCRE2_NOTBOL|PCRE2_NOTEOL|PCRE2_NOTEMPTY| \ PCRE2_NOTEMPTY_ATSTART|PCRE2_PARTIAL_HARD| \ PCRE2_PARTIAL_SOFT|PCRE2_NO_JIT) - -/* This is the callout function. Its only purpose is to halt matching if there -are more than 100 callouts, as one way of stopping too much time being spent on + +/* This is the callout function. Its only purpose is to halt matching if there +are more than 100 callouts, as one way of stopping too much time being spent on fruitless matches. The callout data is a pointer to the counter. */ static int callout_function(pcre2_callout_block *cb, void *callout_data) @@ -44,9 +46,9 @@ static int callout_function(pcre2_callout_block *cb, void *callout_data) *((uint32_t *)callout_data) += 1; return (*((uint32_t *)callout_data) > 100)? PCRE2_ERROR_CALLOUT : 0; } - -/* Putting in this apparently unnecessary prototype prevents gcc from giving a -"no previous prototype" warning when compiling at high warning level. */ + +/* Putting in this apparently unnecessary prototype prevents gcc from giving a +"no previous prototype" warning when compiling at high warning level. */ int LLVMFuzzerTestOneInput(const unsigned char *, size_t); @@ -59,12 +61,13 @@ uint32_t match_options; pcre2_match_data *match_data = NULL; pcre2_match_context *match_context = NULL; size_t match_size; +int dfa_workspace[DFA_WORKSPACE_COUNT]; int r1, r2; int i; if (size < 1) return 0; -/* Limiting the length of the subject for matching stops fruitless searches +/* Limiting the length of the subject for matching stops fruitless searches in large trees taking too much time. */ match_size = (size > MAX_MATCH_SIZE)? MAX_MATCH_SIZE : size; @@ -134,7 +137,7 @@ for (i = 0; i < 2; i++) code = pcre2_compile((PCRE2_SPTR)data, (PCRE2_SIZE)size, compile_options, &errorcode, &erroroffset, NULL); - + /* Compilation succeeded */ if (code != NULL) @@ -169,8 +172,8 @@ for (i = 0; i < 2; i++) return 0; } (void)pcre2_set_match_limit(match_context, 100); - (void)pcre2_set_depth_limit(match_context, 100); - (void)pcre2_set_callout(match_context, callout_function, &callout_count); + (void)pcre2_set_depth_limit(match_context, 100); + (void)pcre2_set_callout(match_context, callout_function, &callout_count); } /* Match twice, with and without options */ @@ -195,6 +198,42 @@ for (i = 0; i < 2; i++) errorcode = pcre2_match(code, (PCRE2_SPTR)data, (PCRE2_SIZE)match_size, 0, match_options, match_data, match_context); +#ifdef STANDALONE + if (errorcode >= 0) printf("Match returned %d\n", errorcode); else + { + unsigned char buffer[256]; + pcre2_get_error_message(errorcode, buffer, 256); + printf("Match failed: error %d: %s\n", errorcode, buffer); + } +#endif + + match_options = 0; /* For second time */ + } + + /* Match with DFA twice, with and without options */ + + match_options = save_match_options & ~PCRE2_NO_JIT; + for (j = 0; j < 2; j++) + { +#ifdef STANDALONE + printf("DFA match options %.8x", match_options); + printf("%s%s%s%s%s%s%s%s%s\n", + ((match_options & PCRE2_ANCHORED) != 0)? ",anchored" : "", + ((match_options & PCRE2_ENDANCHORED) != 0)? ",endanchored" : "", + ((match_options & PCRE2_NO_UTF_CHECK) != 0)? ",no_utf_check" : "", + ((match_options & PCRE2_NOTBOL) != 0)? ",notbol" : "", + ((match_options & PCRE2_NOTEMPTY) != 0)? ",notempty" : "", + ((match_options & PCRE2_NOTEMPTY_ATSTART) != 0)? ",notempty_atstart" : "", + ((match_options & PCRE2_NOTEOL) != 0)? ",noteol" : "", + ((match_options & PCRE2_PARTIAL_HARD) != 0)? ",partial_hard" : "", + ((match_options & PCRE2_PARTIAL_SOFT) != 0)? ",partial_soft" : ""); +#endif + + callout_count = 0; + errorcode = pcre2_dfa_match(code, (PCRE2_SPTR)data, + (PCRE2_SIZE)match_size, 0, match_options, match_data, match_context, + dfa_workspace, DFA_WORKSPACE_COUNT); + #ifdef STANDALONE if (errorcode >= 0) printf("Match returned %d\n", errorcode); else { @@ -210,7 +249,7 @@ for (i = 0; i < 2; i++) match_options = save_match_options; /* Reset for the second compile */ pcre2_code_free(code); } - + /* Compilation failed */ else @@ -253,30 +292,30 @@ for (i = 1; i < argc; i++) size_t readsize; unsigned char *buffer; FILE *f; - - /* Handle a literal string. Copy to an exact size buffer so that checks for + + /* Handle a literal string. Copy to an exact size buffer so that checks for overrunning work. */ - + if (argv[i][0] == '=') - { + { readsize = strlen(argv[i]) - 1; - printf("------ ------\n"); + printf("------ ------\n"); printf("Length = %lu\n", readsize); - printf("%.*s\n", (int)readsize, argv[i]+1); + printf("%.*s\n", (int)readsize, argv[i]+1); buffer = (unsigned char *)malloc(readsize); if (buffer == NULL) printf("** Failed to allocate %lu bytes of memory\n", readsize); else - { - memcpy(buffer, argv[i]+1, readsize); + { + memcpy(buffer, argv[i]+1, readsize); LLVMFuzzerTestOneInput(buffer, readsize); - free(buffer); - } + free(buffer); + } continue; - } + } /* Handle a string given in a file */ - + f = fopen(argv[i], "rb"); if (f == NULL) {