Skip to content

_sre: out-of-bounds read in the SRE code validator for IN opcode with skip < 2 #160814

Open

Description

@DmitryTD

Crash report

_sre.compile() validates the raw code list it gets. For the IN opcode, the validator reads out of bounds when the skip operand is 0 or 1.

Found with a fuzzer.

import _sre
_sre.compile("x", 0, [13, 0, 1], 0, {}, ())

The code list is [SRE_OP_IN, skip=0, SRE_OP_SUCCESS] (13 is SRE_OP_IN, 1 is SRE_OP_SUCCESS).

==19==ERROR: AddressSanitizer: SEGV on unknown address 0x50d400012c80 (pc 0x555b6ecddef2 bp 0x7fff9102de70 sp 0x7fff9102de10 T0)
==19==The signal is caused by a READ memory access.
    #0 in _validate_inner Modules/_sre/sre.c:2218:30
    #1 in _validate_outer Modules/_sre/sre.c:2461:12
    #2 in _validate Modules/_sre/sre.c:2467:9
    #3 in _sre_compile_impl Modules/_sre/sre.c:1849:10
    #4 in _sre_compile Modules/_sre/clinic/sre.c.h:1147:20
    ...

SUMMARY: AddressSanitizer: SEGV Modules/_sre/sre.c:2218:30 in _validate_inner
==19==ABORTING

The crash is the code[skip-2] read in the SRE_OP_IN branch of _validate_inner(). The code is:

https://github.com/python/cpython/blob/e35424611f8/Modules/_sre/sre.c#L2214-L2220

GET_SKIP;
/* Stop 1 before the end; we check the FAILURE below */
if (_validate_charset(code, code+skip-2))
    FAIL;
if (code[skip-2] != SRE_OP_FAILURE)
    FAIL;
code += skip-1;

GET_SKIP checks only that skip is not too big (not past the end of the code). It does not check that skip is too small. When skip is 0 or 1, skip - 2 is a wrong index, so code[skip-2] reads out of bounds.

I did not find a way to reproduce this with the public re module. It looks like its compiler always emits skip >= 2 for IN.

A possible fix is to reject skip < 2 right after GET_SKIP:

GET_SKIP;
if (skip < 2)
    FAIL;

CPython versions tested on:

CPython main branch

Operating systems tested on:

Linux

Output from running 'python -VV' on the command line:

Python 3.16.0a1+dev (heads/main:e35424611f8, Oct 28 2026, 10:25:37) [Clang 18.1.8 ]

Linked PRs

Activity

  1. added
    type-crashA hard crash of the interpreter, possibly with a core dump
    on Oct 28, 2026
  2. picnixz commented on Oct 28, 2026

    @picnixz
    Member

    Is it possible to hit this with the public API only? or is it found by fuzzing?

  3. DmitryTD commented on Oct 28, 2026

    @DmitryTD
    Author

    Found via fuzzing _sre.compile() directly. I tried to reproduce this by calling the public API, but I couldn’t.

  4. picnixz commented on Oct 28, 2026

    @picnixz
    Member

    Yeah, I don't think it's actually necessary to fix but since we already do validation of opcodes, we could fix this (as the validation is unlikely to affect performance)

  5. added a commit that references this issue on Oct 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    extension-modulesC modules in the Modules dirtopic-regextype-crashA hard crash of the interpreter, possibly with a core dump

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions