Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Assertion failure in free_callback_context via create_collation and missing PyErr_NoMemory in create_callback_context #146090

Copy link
Copy link
@devdanzin

Description

@devdanzin
Issue body actions

Crash report

What happened?

The interpreter will abort when running the following MRE.

Automated diagnosis:

Bug 1: When sqlite3_create_collation_v2() fails with SQLITE_BUSY, error cleanup at line 2201 calls free_callback_context(ctx) directly. But ctx has refcount=1 (set at creation, line 1064). free_callback_context asserts ctx->refcount == 0 (line 1076) -> crash in debug builds.

Fix: Use decref_callback_context(ctx) instead of free_callback_context(ctx).
File: Modules/_sqlite/connection.c, line 2201

Bug 2: create_callback_context returns NULL without exception when PyMem_Malloc fails. All 7 callers propagate NULLSystemError.

Fix: Add if (ctx == NULL) { return (callback_context *)PyErr_NoMemory(); }.
File: Modules/_sqlite/connection.c, line 1061

Full report (contains both bugs)

MRE 1:

import sqlite3

conn = sqlite3.connect(":memory:")
conn.create_collation("mycoll", lambda a, b: (a > b) - (a < b))
conn.execute("CREATE TABLE t(x TEXT)")
for i in range(100):
    conn.execute("INSERT INTO t VALUES (?)", (f"item_{i:03d}",))
conn.commit()

cursor = conn.execute("SELECT x FROM t ORDER BY x COLLATE mycoll")
next(cursor)

# Replace the collation while the statement is active -> SQLITE_BUSY
# -> free_callback_context(ctx) with refcount=1 -> assertion failure
try:
    conn.create_collation("mycoll", lambda a, b: 0)
except sqlite3.OperationalError:
    pass  # We never get here in debug builds — assertion fires first

MRE 2:

import sqlite3, _testcapi

conn = sqlite3.connect(":memory:")
_testcapi.set_nomemory(1, 0)
try:
    conn.set_trace_callback(lambda s: None)
except (MemoryError, SystemError):
    pass
finally:
    _testcapi.remove_mem_hooks()

Backtrace 1:

python: ./Modules/_sqlite/connection.c:1076: void free_callback_context(callback_context *): Assertion `ctx->refcount == 0' failed.

Program received signal SIGABRT, Aborted.

#0  __pthread_kill_implementation (threadid=<optimized out>, signo=6, no_tid=0) at ./nptl/pthread_kill.c:44
#1  __pthread_kill_internal (threadid=<optimized out>, signo=6) at ./nptl/pthread_kill.c:89
#2  __GI___pthread_kill (threadid=<optimized out>, signo=signo@entry=6) at ./nptl/pthread_kill.c:100
#3  0x00007ffff7c45e2e in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26
#4  0x00007ffff7c28888 in __GI_abort () at ./stdlib/abort.c:77
#5  0x00007ffff7c287f0 in __assert_fail_base (fmt=<optimized out>, assertion=<optimized out>, file=<optimized out>, line=<optimized out>, function=<optimized out>) at ./assert/assert.c:118
#6  0x00007ffff7c3c19f in __assert_fail (assertion=<optimized out>, file=<optimized out>, line=<optimized out>, function=<optimized out>) at ./assert/assert.c:127
#7  0x00007ffff72e678f in free_callback_context (ctx=ctx@entry=0x7ffff74af940) at ./Modules/_sqlite/connection.c:1076
#8  0x00007ffff72e765b in pysqlite_connection_create_collation_impl (self=0x7ffff75b6450, cls=0x555555f5ec50, name=0x7ffff74e6688 "mycoll", callable=0x7ffff74f0a10)
    at ./Modules/_sqlite/connection.c:2201
#9  pysqlite_connection_create_collation (self=0x7ffff75b6450, cls=0x555555f5ec50, args=0x7fffffffb5e0, nargs=nargs@entry=2, kwnames=0x0) at ./Modules/_sqlite/clinic/connection.c.h:1289
#10 0x00005555556b6e0b in method_vectorcall_FASTCALL_KEYWORDS_METHOD (func=func@entry=0x7ffff7343350, args=args@entry=0x7fffffffb5d8, nargsf=nargsf@entry=9223372036854775811,
    kwnames=kwnames@entry=0x0) at Objects/descrobject.c:381
#11 0x00005555556a2ebe in _PyObject_VectorcallTstate (tstate=0x555555d99c08 <_PyRuntime+360664>, callable=0x7ffff7343350, args=0x7fffffffb5d8, nargsf=9223372036854775811, kwnames=0x0)
    at ./Include/internal/pycore_call.h:144
#12 0x000055555583f859 in _Py_VectorCallInstrumentation_StackRefSteal (callable=..., arguments=0x7ffff7fa7078, total_args=total_args@entry=3, kwnames=kwnames@entry=...,
    call_instrumentation=false, frame=frame@entry=0x7ffff7fa7020, this_instr=0x555555f392f8, tstate=0x555555d99c08 <_PyRuntime+360664>) at Python/ceval.c:775
#13 0x000055555584a8e4 in _PyEval_EvalFrameDefault (tstate=tstate@entry=0x555555d99c08 <_PyRuntime+360664>, frame=<optimized out>, frame@entry=0x7ffff7fa7020, throwflag=throwflag@entry=0)
    at Python/generated_cases.c.h:1838
#14 0x000055555583f08b in _PyEval_EvalFrame (tstate=0x555555d99c08 <_PyRuntime+360664>, frame=0x7ffff7fa7020, throwflag=0) at ./Include/internal/pycore_ceval.h:118
#15 _PyEval_Vector (tstate=tstate@entry=0x555555d99c08 <_PyRuntime+360664>, func=func@entry=0x7ffff7466690, locals=locals@entry=0x7ffff746a4b0, args=args@entry=0x0,
    argcount=argcount@entry=0, kwnames=kwnames@entry=0x0) at Python/ceval.c:2130
#16 0x000055555583ee1e in PyEval_EvalCode (co=co@entry=0x555555f390f0, globals=globals@entry=0x7ffff746a4b0, locals=locals@entry=0x7ffff746a4b0) at Python/ceval.c:686
#17 0x00005555559c8f8e in run_eval_code_obj (tstate=0x555555d99c08 <_PyRuntime+360664>, co=co@entry=0x555555f390f0, globals=globals@entry=0x7ffff746a4b0, locals=locals@entry=0x7ffff746a4b0)
    at Python/pythonrun.c:1368
#18 0x00005555559c8adb in run_mod (mod=mod@entry=0x555555f45cc8, filename=filename@entry=0x7ffff74f8040, globals=globals@entry=0x7ffff746a4b0, locals=locals@entry=0x7ffff746a4b0,
    flags=0x7fffffffc910, arena=arena@entry=0x7ffff74dac20, interactive_src=0x0, generate_new_source=0) at Python/pythonrun.c:1471

Backtrace 2:

Fatal Python error: _Py_CheckFunctionResult: a function returned NULL without setting an exception
Python runtime state: initialized
object address  : 0x7ffff75ac520
object refcount : 1
object type     : 0x555555d05978
object type name: MemoryError
object repr     :
lost sys.stderr

Current thread 0x00007ffff7e8b780 [python] (most recent call first):
  File "/home/danzin/crashers/sqlite_oom1.py", line 6 in <module>

Extension modules: _testcapi (total: 1)

Program received signal SIGABRT, Aborted.

#0  __pthread_kill_implementation (threadid=<optimized out>, signo=6, no_tid=0) at ./nptl/pthread_kill.c:44
#1  __pthread_kill_internal (threadid=<optimized out>, signo=6) at ./nptl/pthread_kill.c:89
#2  __GI___pthread_kill (threadid=<optimized out>, signo=signo@entry=6) at ./nptl/pthread_kill.c:100
#3  0x00007ffff7c45e2e in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26
#4  0x00007ffff7c28888 in __GI_abort () at ./stdlib/abort.c:77
#5  0x0000555555993a4d in fatal_error_exit (status=3064086, status@entry=-1) at Python/pylifecycle.c:3341
#6  0x0000555555993737 in fatal_error (fd=2, header=header@entry=1, prefix=prefix@entry=0x555555ac7235 "_Py_CheckFunctionResult",
    msg=msg@entry=0x555555ac724d "a function returned NULL without setting an exception", status=status@entry=-1) at Python/pylifecycle.c:3571
#7  0x0000555555991ca4 in _Py_FatalErrorFunc (func=0x555555ac7235 "_Py_CheckFunctionResult", msg=0x555555ac724d "a function returned NULL without setting an exception")
    at Python/pylifecycle.c:3587
#8  0x00005555556a2d05 in _Py_CheckFunctionResult (tstate=<optimized out>, callable=<optimized out>, result=<optimized out>, where=<optimized out>) at Objects/call.c:43
#9  0x000055555583f859 in _Py_VectorCallInstrumentation_StackRefSteal (callable=..., arguments=0x7ffff7fa7078, total_args=total_args@entry=2, kwnames=kwnames@entry=...,
    call_instrumentation=false, frame=frame@entry=0x7ffff7fa7020, this_instr=0x7ffff756d9ea, tstate=0x555555d99c08 <_PyRuntime+360664>) at Python/ceval.c:775
#10 0x000055555584a8e4 in _PyEval_EvalFrameDefault (tstate=tstate@entry=0x555555d99c08 <_PyRuntime+360664>, frame=<optimized out>, frame@entry=0x7ffff7fa7020, throwflag=throwflag@entry=0)
    at Python/generated_cases.c.h:1838
#11 0x000055555583f08b in _PyEval_EvalFrame (tstate=0x555555d99c08 <_PyRuntime+360664>, frame=0x7ffff7fa7020, throwflag=0) at ./Include/internal/pycore_ceval.h:118
#12 _PyEval_Vector (tstate=tstate@entry=0x555555d99c08 <_PyRuntime+360664>, func=func@entry=0x7ffff7466690, locals=locals@entry=0x7ffff746a4b0, args=args@entry=0x0,
    argcount=argcount@entry=0, kwnames=kwnames@entry=0x0) at Python/ceval.c:2130
#13 0x000055555583ee1e in PyEval_EvalCode (co=co@entry=0x7ffff756d8a0, globals=globals@entry=0x7ffff746a4b0, locals=locals@entry=0x7ffff746a4b0) at Python/ceval.c:686
#14 0x00005555559c8f8e in run_eval_code_obj (tstate=0x555555d99c08 <_PyRuntime+360664>, co=co@entry=0x7ffff756d8a0, globals=globals@entry=0x7ffff746a4b0, locals=locals@entry=0x7ffff746a4b0)
    at Python/pythonrun.c:1368
#15 0x00005555559c8adb in run_mod (mod=mod@entry=0x555555f3f5b0, filename=filename@entry=0x7ffff74e8580, globals=globals@entry=0x7ffff746a4b0, locals=locals@entry=0x7ffff746a4b0,
    flags=0x7fffffffc950, arena=arena@entry=0x7ffff74dad40, interactive_src=0x0, generate_new_source=0) at Python/pythonrun.c:1471

Found using cpython-review-toolkit with Claude Opus 4.6, using the /cpython-review-toolkit:explore Modules/_sqlite/ all deep command.

CPython versions tested on:

CPython main branch

Operating systems tested on:

Linux

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

Python 3.15.0a7+ (heads/main:e0f7c1097e1, Mar 17 2026, 18:10:52) [Clang 21.1.2 (2ubuntu6)]

Linked PRs

Reactions are currently unavailable

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.13bugs and security fixesbugs and security fixes3.14bugs and security fixesbugs and security fixes3.15pre-release feature fixes, bugs and security fixespre-release feature fixes, bugs and security fixesextension-modulesC modules in the Modules dirC modules in the Modules dirtopic-sqlite3type-crashA hard crash of the interpreter, possibly with a core dumpA hard crash of the interpreter, possibly with a core dump
    No fields configured for issues without a type.

    Projects

    Status
    Done
    Show more project fields

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      Morty Proxy This is a proxified and sanitized view of the page, visit original site.