From 702aa3f99a0637f41e17706b27b7eebc9322468c Mon Sep 17 00:00:00 2001 From: Stan Ulbrych Date: Wed, 25 Feb 2026 21:38:47 +0000 Subject: [PATCH 1/2] Vary compiler flags in fuzz_pycompile --- Modules/_xxtestfuzz/fuzzer.c | 51 ++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/Modules/_xxtestfuzz/fuzzer.c b/Modules/_xxtestfuzz/fuzzer.c index 0cbe10c79ab4a6..0245c8130945c4 100644 --- a/Modules/_xxtestfuzz/fuzzer.c +++ b/Modules/_xxtestfuzz/fuzzer.c @@ -516,8 +516,8 @@ static int fuzz_pycompile(const char* data, size_t size) { return 0; } - // Need 2 bytes for parameter selection - if (size < 2) { + // Need 3 bytes for parameter selection + if (size < 3) { return 0; } @@ -529,25 +529,42 @@ static int fuzz_pycompile(const char* data, size_t size) { unsigned char optimize_idx = (unsigned char) data[1]; int optimize = optimize_vals[optimize_idx % NUM_OPTIMIZE_VALS]; + // Use third byte to determine compiler flags to use. + unsigned char flags_byte = (unsigned char) data[2]; + PyCompilerFlags flags = _PyCompilerFlags_INIT; + if (flags_byte & 0x01) { + flags.cf_flags |= PyCF_SOURCE_IS_UTF8; + } + if (flags_byte & 0x02) { + flags.cf_flags |= PyCF_DONT_IMPLY_DEDENT; + } + if (flags_byte & 0x04) { + flags.cf_flags |= PyCF_ONLY_AST; + } + if (flags_byte & 0x08) { + flags.cf_flags |= PyCF_IGNORE_COOKIE; + } + if (flags_byte & 0x10) { + flags.cf_flags |= PyCF_TYPE_COMMENTS; + } + if (flags_byte & 0x20) { + flags.cf_flags |= PyCF_ALLOW_TOP_LEVEL_AWAIT; + } + if (flags_byte & 0x40) { + flags.cf_flags |= PyCF_ALLOW_INCOMPLETE_INPUT; + } + if (flags_byte & 0x80) { + flags.cf_flags |= PyCF_OPTIMIZED_AST; + } + char pycompile_scratch[MAX_PYCOMPILE_TEST_SIZE]; // Create a NUL-terminated C string from the remaining input - memcpy(pycompile_scratch, data + 2, size - 2); + memcpy(pycompile_scratch, data + 3, size - 3); // Put a NUL terminator just after the copied data. (Space was reserved already.) - pycompile_scratch[size - 2] = '\0'; - - // XXX: instead of always using NULL for the `flags` value to - // `Py_CompileStringExFlags`, there are many flags that conditionally - // change parser behavior: - // - // #define PyCF_TYPE_COMMENTS 0x1000 - // #define PyCF_ALLOW_TOP_LEVEL_AWAIT 0x2000 - // #define PyCF_ONLY_AST 0x0400 - // - // It would be good to test various combinations of these, too. - PyCompilerFlags *flags = NULL; - - PyObject *result = Py_CompileStringExFlags(pycompile_scratch, "", start, flags, optimize); + pycompile_scratch[size - 3] = '\0'; + + PyObject *result = Py_CompileStringExFlags(pycompile_scratch, "", start, &flags, optimize); if (result == NULL) { /* Compilation failed, most likely from a syntax error. If it was a SystemError we abort. There's no non-bug reason to raise a From 2418cbd1412b008623bab97b64aebda6397936f0 Mon Sep 17 00:00:00 2001 From: Stan Ulbrych Date: Mon, 9 Mar 2026 22:24:10 +0000 Subject: [PATCH 2/2] Drop `PyCF_SOURCE_IS_UTF8` --- Modules/_xxtestfuzz/fuzzer.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/Modules/_xxtestfuzz/fuzzer.c b/Modules/_xxtestfuzz/fuzzer.c index 0245c8130945c4..e396a41386021a 100644 --- a/Modules/_xxtestfuzz/fuzzer.c +++ b/Modules/_xxtestfuzz/fuzzer.c @@ -533,27 +533,24 @@ static int fuzz_pycompile(const char* data, size_t size) { unsigned char flags_byte = (unsigned char) data[2]; PyCompilerFlags flags = _PyCompilerFlags_INIT; if (flags_byte & 0x01) { - flags.cf_flags |= PyCF_SOURCE_IS_UTF8; - } - if (flags_byte & 0x02) { flags.cf_flags |= PyCF_DONT_IMPLY_DEDENT; } - if (flags_byte & 0x04) { + if (flags_byte & 0x02) { flags.cf_flags |= PyCF_ONLY_AST; } - if (flags_byte & 0x08) { + if (flags_byte & 0x04) { flags.cf_flags |= PyCF_IGNORE_COOKIE; } - if (flags_byte & 0x10) { + if (flags_byte & 0x08) { flags.cf_flags |= PyCF_TYPE_COMMENTS; } - if (flags_byte & 0x20) { + if (flags_byte & 0x10) { flags.cf_flags |= PyCF_ALLOW_TOP_LEVEL_AWAIT; } - if (flags_byte & 0x40) { + if (flags_byte & 0x20) { flags.cf_flags |= PyCF_ALLOW_INCOMPLETE_INPUT; } - if (flags_byte & 0x80) { + if (flags_byte & 0x40) { flags.cf_flags |= PyCF_OPTIMIZED_AST; }