Title: Assertion failure in `free_callback_context` via `create_collation` and missing `PyErr_NoMemory` in `create_callback_context` · Issue #146090 · python/cpython · GitHub
Open Graph Title: Assertion failure in `free_callback_context` via `create_collation` and missing `PyErr_NoMemory` in `create_callback_context` · Issue #146090 · python/cpython
X Title: Assertion failure in `free_callback_context` via `create_collation` and missing `PyErr_NoMemory` in `create_callback_context` · Issue #146090 · python/cpython
Description: 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) dir...
Open Graph Description: 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 2...
X Description: 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 2...
Opengraph URL: https://github.com/python/cpython/issues/146090
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"Assertion failure in `free_callback_context` via `create_collation` and missing `PyErr_NoMemory` in `create_callback_context`","articleBody":"# Crash report\n\n### What happened?\n\nThe interpreter will abort when running the following MRE.\n\n### Automated diagnosis:\n\nBug 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-\u003erefcount == 0` (line 1076) -\u003e crash in debug builds.\n\nFix: Use `decref_callback_context(ctx)` instead of `free_callback_context(ctx)`.\nFile: `Modules/_sqlite/connection.c`, line 2201\n\nBug 2: `create_callback_context` returns `NULL` without exception when `PyMem_Malloc` fails. All 7 callers propagate `NULL` → `SystemError`.\n\nFix: Add if (ctx == NULL) { return (callback_context *)PyErr_NoMemory(); }.\nFile: `Modules/_sqlite/connection.c`, line 1061\n\n[Full report](https://gist.github.com/devdanzin/69aff7ff2d64ce8c7c21622f7f36e84c) (contains both bugs)\n\nMRE 1:\n```python\nimport sqlite3\n\nconn = sqlite3.connect(\":memory:\")\nconn.create_collation(\"mycoll\", lambda a, b: (a \u003e b) - (a \u003c b))\nconn.execute(\"CREATE TABLE t(x TEXT)\")\nfor i in range(100):\n conn.execute(\"INSERT INTO t VALUES (?)\", (f\"item_{i:03d}\",))\nconn.commit()\n\ncursor = conn.execute(\"SELECT x FROM t ORDER BY x COLLATE mycoll\")\nnext(cursor)\n\n# Replace the collation while the statement is active -\u003e SQLITE_BUSY\n# -\u003e free_callback_context(ctx) with refcount=1 -\u003e assertion failure\ntry:\n conn.create_collation(\"mycoll\", lambda a, b: 0)\nexcept sqlite3.OperationalError:\n pass # We never get here in debug builds — assertion fires first\n```\n\nMRE 2:\n```python\nimport sqlite3, _testcapi\n\nconn = sqlite3.connect(\":memory:\")\n_testcapi.set_nomemory(1, 0)\ntry:\n conn.set_trace_callback(lambda s: None)\nexcept (MemoryError, SystemError):\n pass\nfinally:\n _testcapi.remove_mem_hooks()\n```\n\n\nBacktrace 1:\n```\npython: ./Modules/_sqlite/connection.c:1076: void free_callback_context(callback_context *): Assertion `ctx-\u003erefcount == 0' failed.\n\nProgram received signal SIGABRT, Aborted.\n\n#0 __pthread_kill_implementation (threadid=\u003coptimized out\u003e, signo=6, no_tid=0) at ./nptl/pthread_kill.c:44\n#1 __pthread_kill_internal (threadid=\u003coptimized out\u003e, signo=6) at ./nptl/pthread_kill.c:89\n#2 __GI___pthread_kill (threadid=\u003coptimized out\u003e, signo=signo@entry=6) at ./nptl/pthread_kill.c:100\n#3 0x00007ffff7c45e2e in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26\n#4 0x00007ffff7c28888 in __GI_abort () at ./stdlib/abort.c:77\n#5 0x00007ffff7c287f0 in __assert_fail_base (fmt=\u003coptimized out\u003e, assertion=\u003coptimized out\u003e, file=\u003coptimized out\u003e, line=\u003coptimized out\u003e, function=\u003coptimized out\u003e) at ./assert/assert.c:118\n#6 0x00007ffff7c3c19f in __assert_fail (assertion=\u003coptimized out\u003e, file=\u003coptimized out\u003e, line=\u003coptimized out\u003e, function=\u003coptimized out\u003e) at ./assert/assert.c:127\n#7 0x00007ffff72e678f in free_callback_context (ctx=ctx@entry=0x7ffff74af940) at ./Modules/_sqlite/connection.c:1076\n#8 0x00007ffff72e765b in pysqlite_connection_create_collation_impl (self=0x7ffff75b6450, cls=0x555555f5ec50, name=0x7ffff74e6688 \"mycoll\", callable=0x7ffff74f0a10)\n at ./Modules/_sqlite/connection.c:2201\n#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\n#10 0x00005555556b6e0b in method_vectorcall_FASTCALL_KEYWORDS_METHOD (func=func@entry=0x7ffff7343350, args=args@entry=0x7fffffffb5d8, nargsf=nargsf@entry=9223372036854775811,\n kwnames=kwnames@entry=0x0) at Objects/descrobject.c:381\n#11 0x00005555556a2ebe in _PyObject_VectorcallTstate (tstate=0x555555d99c08 \u003c_PyRuntime+360664\u003e, callable=0x7ffff7343350, args=0x7fffffffb5d8, nargsf=9223372036854775811, kwnames=0x0)\n at ./Include/internal/pycore_call.h:144\n#12 0x000055555583f859 in _Py_VectorCallInstrumentation_StackRefSteal (callable=..., arguments=0x7ffff7fa7078, total_args=total_args@entry=3, kwnames=kwnames@entry=...,\n call_instrumentation=false, frame=frame@entry=0x7ffff7fa7020, this_instr=0x555555f392f8, tstate=0x555555d99c08 \u003c_PyRuntime+360664\u003e) at Python/ceval.c:775\n#13 0x000055555584a8e4 in _PyEval_EvalFrameDefault (tstate=tstate@entry=0x555555d99c08 \u003c_PyRuntime+360664\u003e, frame=\u003coptimized out\u003e, frame@entry=0x7ffff7fa7020, throwflag=throwflag@entry=0)\n at Python/generated_cases.c.h:1838\n#14 0x000055555583f08b in _PyEval_EvalFrame (tstate=0x555555d99c08 \u003c_PyRuntime+360664\u003e, frame=0x7ffff7fa7020, throwflag=0) at ./Include/internal/pycore_ceval.h:118\n#15 _PyEval_Vector (tstate=tstate@entry=0x555555d99c08 \u003c_PyRuntime+360664\u003e, func=func@entry=0x7ffff7466690, locals=locals@entry=0x7ffff746a4b0, args=args@entry=0x0,\n argcount=argcount@entry=0, kwnames=kwnames@entry=0x0) at Python/ceval.c:2130\n#16 0x000055555583ee1e in PyEval_EvalCode (co=co@entry=0x555555f390f0, globals=globals@entry=0x7ffff746a4b0, locals=locals@entry=0x7ffff746a4b0) at Python/ceval.c:686\n#17 0x00005555559c8f8e in run_eval_code_obj (tstate=0x555555d99c08 \u003c_PyRuntime+360664\u003e, co=co@entry=0x555555f390f0, globals=globals@entry=0x7ffff746a4b0, locals=locals@entry=0x7ffff746a4b0)\n at Python/pythonrun.c:1368\n#18 0x00005555559c8adb in run_mod (mod=mod@entry=0x555555f45cc8, filename=filename@entry=0x7ffff74f8040, globals=globals@entry=0x7ffff746a4b0, locals=locals@entry=0x7ffff746a4b0,\n flags=0x7fffffffc910, arena=arena@entry=0x7ffff74dac20, interactive_src=0x0, generate_new_source=0) at Python/pythonrun.c:1471\n```\n\nBacktrace 2:\n```\nFatal Python error: _Py_CheckFunctionResult: a function returned NULL without setting an exception\nPython runtime state: initialized\nobject address : 0x7ffff75ac520\nobject refcount : 1\nobject type : 0x555555d05978\nobject type name: MemoryError\nobject repr :\nlost sys.stderr\n\nCurrent thread 0x00007ffff7e8b780 [python] (most recent call first):\n File \"/home/danzin/crashers/sqlite_oom1.py\", line 6 in \u003cmodule\u003e\n\nExtension modules: _testcapi (total: 1)\n\nProgram received signal SIGABRT, Aborted.\n\n#0 __pthread_kill_implementation (threadid=\u003coptimized out\u003e, signo=6, no_tid=0) at ./nptl/pthread_kill.c:44\n#1 __pthread_kill_internal (threadid=\u003coptimized out\u003e, signo=6) at ./nptl/pthread_kill.c:89\n#2 __GI___pthread_kill (threadid=\u003coptimized out\u003e, signo=signo@entry=6) at ./nptl/pthread_kill.c:100\n#3 0x00007ffff7c45e2e in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26\n#4 0x00007ffff7c28888 in __GI_abort () at ./stdlib/abort.c:77\n#5 0x0000555555993a4d in fatal_error_exit (status=3064086, status@entry=-1) at Python/pylifecycle.c:3341\n#6 0x0000555555993737 in fatal_error (fd=2, header=header@entry=1, prefix=prefix@entry=0x555555ac7235 \"_Py_CheckFunctionResult\",\n msg=msg@entry=0x555555ac724d \"a function returned NULL without setting an exception\", status=status@entry=-1) at Python/pylifecycle.c:3571\n#7 0x0000555555991ca4 in _Py_FatalErrorFunc (func=0x555555ac7235 \"_Py_CheckFunctionResult\", msg=0x555555ac724d \"a function returned NULL without setting an exception\")\n at Python/pylifecycle.c:3587\n#8 0x00005555556a2d05 in _Py_CheckFunctionResult (tstate=\u003coptimized out\u003e, callable=\u003coptimized out\u003e, result=\u003coptimized out\u003e, where=\u003coptimized out\u003e) at Objects/call.c:43\n#9 0x000055555583f859 in _Py_VectorCallInstrumentation_StackRefSteal (callable=..., arguments=0x7ffff7fa7078, total_args=total_args@entry=2, kwnames=kwnames@entry=...,\n call_instrumentation=false, frame=frame@entry=0x7ffff7fa7020, this_instr=0x7ffff756d9ea, tstate=0x555555d99c08 \u003c_PyRuntime+360664\u003e) at Python/ceval.c:775\n#10 0x000055555584a8e4 in _PyEval_EvalFrameDefault (tstate=tstate@entry=0x555555d99c08 \u003c_PyRuntime+360664\u003e, frame=\u003coptimized out\u003e, frame@entry=0x7ffff7fa7020, throwflag=throwflag@entry=0)\n at Python/generated_cases.c.h:1838\n#11 0x000055555583f08b in _PyEval_EvalFrame (tstate=0x555555d99c08 \u003c_PyRuntime+360664\u003e, frame=0x7ffff7fa7020, throwflag=0) at ./Include/internal/pycore_ceval.h:118\n#12 _PyEval_Vector (tstate=tstate@entry=0x555555d99c08 \u003c_PyRuntime+360664\u003e, func=func@entry=0x7ffff7466690, locals=locals@entry=0x7ffff746a4b0, args=args@entry=0x0,\n argcount=argcount@entry=0, kwnames=kwnames@entry=0x0) at Python/ceval.c:2130\n#13 0x000055555583ee1e in PyEval_EvalCode (co=co@entry=0x7ffff756d8a0, globals=globals@entry=0x7ffff746a4b0, locals=locals@entry=0x7ffff746a4b0) at Python/ceval.c:686\n#14 0x00005555559c8f8e in run_eval_code_obj (tstate=0x555555d99c08 \u003c_PyRuntime+360664\u003e, co=co@entry=0x7ffff756d8a0, globals=globals@entry=0x7ffff746a4b0, locals=locals@entry=0x7ffff746a4b0)\n at Python/pythonrun.c:1368\n#15 0x00005555559c8adb in run_mod (mod=mod@entry=0x555555f3f5b0, filename=filename@entry=0x7ffff74e8580, globals=globals@entry=0x7ffff746a4b0, locals=locals@entry=0x7ffff746a4b0,\n flags=0x7fffffffc950, arena=arena@entry=0x7ffff74dad40, interactive_src=0x0, generate_new_source=0) at Python/pythonrun.c:1471\n```\n\nFound using [cpython-review-toolkit](https://github.com/devdanzin/cpython-review-toolkit) with Claude Opus 4.6, using the `/cpython-review-toolkit:explore Modules/_sqlite/ all deep` command.\n\n\n### CPython versions tested on:\n\nCPython main branch\n\n### Operating systems tested on:\n\nLinux\n\n### Output from running 'python -VV' on the command line:\n\nPython 3.15.0a7+ (heads/main:e0f7c1097e1, Mar 17 2026, 18:10:52) [Clang 21.1.2 (2ubuntu6)]\n\n\u003c!-- gh-linked-prs --\u003e\n### Linked PRs\n* gh-146569\n* gh-146595\n* gh-146596\n\u003c!-- /gh-linked-prs --\u003e\n","author":{"url":"https://github.com/devdanzin","@type":"Person","name":"devdanzin"},"datePublished":"2026-03-17T21:29:17.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":5},"url":"https://github.com/146090/cpython/issues/146090"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:2f5bc163-fa57-ede2-5e22-ab85421f13bb |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | E5B0:208250:7C53B0:A635FE:6A514F83 |
| html-safe-nonce | 1bd23721d166aa58513ef617941ca71687743b02a6ff69e0809be3b3ea1079b9 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJFNUIwOjIwODI1MDo3QzUzQjA6QTYzNUZFOjZBNTE0RjgzIiwidmlzaXRvcl9pZCI6Ijg2NjY4MTkyMzI4NDYxMzkyNjciLCJyZWdpb25fZWRnZSI6ImlhZCIsInJlZ2lvbl9yZW5kZXIiOiJpYWQifQ== |
| visitor-hmac | dab84da0c588f4ccc0658386344df8ba8a21a3dbf78c15201a29684be9fed893 |
| hovercard-subject-tag | issue:4091299262 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/python/cpython/146090/issue_layout |
| twitter:image | https://opengraph.githubassets.com/8a016445c9b5524d9f47a00dd16991c9eb8cc199f05412c8affaa453dc88a277/python/cpython/issues/146090 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/8a016445c9b5524d9f47a00dd16991c9eb8cc199f05412c8affaa453dc88a277/python/cpython/issues/146090 |
| og:image:alt | 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 2... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | devdanzin |
| hostname | github.com |
| expected-hostname | github.com |
| None | 6f17634ed2af1d116850bcea6c63a70a4d72970f33ade1dd3eef3764b7e16994 |
| turbo-cache-control | no-preview |
| go-import | github.com/python/cpython git https://github.com/python/cpython.git |
| octolytics-dimension-user_id | 1525981 |
| octolytics-dimension-user_login | python |
| octolytics-dimension-repository_id | 81598961 |
| octolytics-dimension-repository_nwo | python/cpython |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 81598961 |
| octolytics-dimension-repository_network_root_nwo | python/cpython |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 511bff6ea06e144ed085ff736aea4c6404987b00 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width