GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Assertion failure in `free_callback_context` via `create_collation` and missing `PyErr_NoMemory` in `create_callback_context` · Issue #146090 · python/cpython

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

New issue
Copy link
New issue
Copy link
Closed
#146569
Closed
Assertion failure in free_callback_context via create_collation and missing PyErr_NoMemory in create_callback_context#146090
#146569
Copy link
Labels
3.13only security fixesonly security fixes3.14bugs and security fixesbugs and security fixes3.15bugs and security fixesbugs 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

Description

@devdanzin
devdanzin
opened on Mar 17, 2026
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 NULL → SystemError.

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

  • gh-146090: fix memory management of internal sqlite3 callback contexts #146569
  • [3.14] gh-146090: fix memory management of internal sqlite3 callback contexts (GH-146569) #146595
  • [3.13] gh-146090: fix memory management of internal sqlite3 callback contexts (GH-146569) #146596

Activity

  1. devdanzin
    added
    type-crashA hard crash of the interpreter, possibly with a core dumpA hard crash of the interpreter, possibly with a core dump
    extension-modulesC modules in the Modules dirC modules in the Modules dir
    topic-sqlite3
    on Mar 17, 2026
  2. github-project-automation
    added this to sqlite3 issueson Mar 17, 2026
  3. picnixz commented on Mar 17, 2026

    @picnixz
    picnixz
    on Mar 17, 2026
    Member
    More actions

    I think this one is on me. I added the refcount logic here and in the tests I said that coverage was missing so this likely caused this issue to slip.

  4. picnixz
    self-assigned this
    on Mar 17, 2026
  5. picnixz commented on Mar 17, 2026

    @picnixz
    picnixz
    on Mar 17, 2026
    Member
    More actions

    I will try to address this in the next two weeks. I am away this week but I may address it while travelling.

  6. devdanzin commented on Mar 18, 2026

    @devdanzin
    devdanzin
    on Mar 18, 2026
    MemberAuthor
    More actions

    The full report presents another crash, please let me know if I should open another issue for it.

  7. vstinner commented on Mar 18, 2026

    @vstinner
    vstinner
    on Mar 18, 2026
    Member
    More actions

    @picnixz plans to write a PR to fix this issue.

    I confirm that the proposed fix works as expected:

    diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c
    index af63271b9fd..76df1089ebb 100644
    --- a/Modules/_sqlite/connection.c
    +++ b/Modules/_sqlite/connection.c
    @@ -2198,7 +2198,7 @@ pysqlite_connection_create_collation_impl(pysqlite_Connection *self,
              * the context before returning.
              */
             if (callable != Py_None) {
    -            free_callback_context(ctx);
    +            decref_callback_context(ctx);
             }
             set_error_from_db(self->state, self->db);
             return NULL;
  8. serhiy-storchaka
    added a parent issue on Mar 18, 2026
    • Umbrella issue: bugs found using cpython-review-toolkit #146102
  9. serhiy-storchaka
    added
    3.13only security fixesonly security fixes
    3.14bugs and security fixesbugs and security fixes
    3.15bugs and security fixesbugs and security fixes
    on Mar 18, 2026
  10. picnixz commented on Mar 18, 2026

    @picnixz
    picnixz
    on Mar 18, 2026
    Member
    More actions

    please let me know if I should open another issue for it

    No, it's fine. Just rename the issue and add the two bugs in that issue (that is, bugs concerning custom refcounting in sqlite3)

  11. devdanzin
    changed the title [-]Assertion failure in `free_callback_context` via `create_collation`[/-] [+]Assertion failure in `free_callback_context` via `create_collation` and missing `PyErr_NoMemory` in `create_callback_context`[/+] on Mar 19, 2026
  12. picnixz
    added a commit that references this issue on Mar 28, 2026

    pythongh-146090: fix memory management of SQLite3 callback contexts

    67703c7
  13. picnixz
    removed their assignment
    on Mar 28, 2026
  14. picnixz
    linked a pull request that will close this issuegh-146090: fix memory management of internal `sqlite3` callback contexts #146569on Mar 28, 2026
  15. picnixz
    added a commit that references this issue on Mar 29, 2026

    gh-146090: fix memory management of internal `sqlite3` callback conte…

    aa66807
  16. picnixz
    closed this as completedin #146569on Mar 29, 2026
  17. github-project-automation
    moved this to Done in sqlite3 issueson Mar 29, 2026
  18. miss-islington
    added 2 commits that reference this issue on Mar 29, 2026

    pythongh-146090: fix memory management of internal `sqlite3` callback…

    a0192ad

    pythongh-146090: fix memory management of internal `sqlite3` callback…

    1b5bd8e
  19. picnixz
    added 2 commits that reference this issue on Mar 29, 2026

    [3.13] gh-146090: fix memory management of internal `sqlite3` callbac…

    6fdf084

    [3.14] gh-146090: fix memory management of internal `sqlite3` callbac…

    1458ea0
  20. maurycy
    added a commit that references this issue on Mar 30, 2026

    Merge remote-tracking branch 'upstream/main' into tachyon-ndjson-kole…

    6a0ea81
  21. clin1234
    added a commit that references this issue on Apr 16, 2026

    pythongh-146090: fix memory management of internal `sqlite3` callback…

    77666cc
  22. ljfp
    added a commit that references this issue on Apr 25, 2026

    pythongh-146090: fix memory management of internal `sqlite3` callback…

    5448ac0
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

    3.13only security fixesonly security fixes3.14bugs and security fixesbugs and security fixes3.15bugs and security fixesbugs 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

    Projects

    • sqlite3 issues
      Status
      Done
      Show more project fields

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

    You are visitor 01402503 — GeezerVison does not store the pages you look up.
    Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.