Skip to content

Missing PyErr_NoMemory in _zoneinfo load_data and ts_to_local #146092

@devdanzin

Description

@devdanzin

Crash report

What happened?

It's possible to cause assertion errors due to calls returning NULL on OOM in _zoneinfo.

Automated diagnosis:

Multiple PyMem_Malloc/PyMem_Calloc calls in load_data (including ts_to_local at line 2130) return NULL on OOM and goto error without setting an exception. The caller returns NULL without exception → assertion failure.

File: Modules/_zoneinfo.c, lines 1029-1137 (load_data), 2130 (ts_to_local)

MRE for load_data:

import _testcapi, sys

for mod in ["zoneinfo", "_zoneinfo"]:
    if mod in sys.modules:
        del sys.modules[mod]

for n in range(1, 50):
    for mod in ["zoneinfo", "_zoneinfo"]:
        if mod in sys.modules:
            del sys.modules[mod]
    print(n)
    _testcapi.set_nomemory(n, 0)
    try:
        from zoneinfo import ZoneInfo
        z = ZoneInfo("UTC")
        _testcapi.remove_mem_hooks()
        break
    except MemoryError:
        _testcapi.remove_mem_hooks()

MRE for ts_to_local:

import _testcapi
from zoneinfo import ZoneInfo

# Warm up imports — we only want OOM during zone construction
_ = ZoneInfo("UTC")
del _

# Clear cache so America/New_York gets re-loaded from TZif data
ZoneInfo.clear_cache()

# Persistent failure from allocation #9 onward.
# Early allocs (import machinery, arg parsing) succeed;
# the PyMem_Malloc in load_data/ts_to_local fails.
_testcapi.set_nomemory(9, 0)

z = ZoneInfo("America/New_York")  # crashes: assertion `obj != NULL'

Backtrace:

python: ./Include/internal/pycore_stackref.h:554: _PyStackRef PyStackRef_FromPyObjectSteal(PyObject *): Assertion `obj != NULL' 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  0x000055555587fd55 in PyStackRef_FromPyObjectSteal (obj=<optimized out>) at ./Include/internal/pycore_stackref.h:554
#8  0x0000555555842cd0 in _PyEval_EvalFrameDefault (tstate=tstate@entry=0x555555d99c08 <_PyRuntime+360664>, frame=<optimized out>, frame@entry=0x7ffff7fa70a0, throwflag=throwflag@entry=0)
    at Python/generated_cases.c.h:292
#9  0x000055555583f08b in _PyEval_EvalFrame (tstate=0x555555d99c08 <_PyRuntime+360664>, frame=0x7ffff7fa70a0, throwflag=0) at ./Include/internal/pycore_ceval.h:118
#10 _PyEval_Vector (tstate=0x555555d99c08 <_PyRuntime+360664>, func=0x7ffff75e9190, locals=0x0, args=0x7fffffffb310, argcount=2, kwnames=0x0) at Python/ceval.c:2130
#11 0x00005555556a2ebe in _PyObject_VectorcallTstate (tstate=0x555555d99c08 <_PyRuntime+360664>, callable=callable@entry=0x7ffff75e9190, args=args@entry=0x7fffffffb310,
    nargsf=nargsf@entry=2, kwnames=kwnames@entry=0x0) at ./Include/internal/pycore_call.h:144
#12 0x00005555556a625a in object_vacall (tstate=tstate@entry=0x555555d99c08 <_PyRuntime+360664>, base=base@entry=0x0, callable=callable@entry=0x7ffff75e9190,
    vargs=vargs@entry=0x7fffffffb460) at Objects/call.c:823
#13 0x00005555556a5f0b in PyObject_CallMethodObjArgs (obj=0x7ffff75b08c0, name=0x555555d57470 <_PyRuntime+88384>) at Objects/call.c:960
#14 0x000055555595136b in import_find_and_load (tstate=tstate@entry=0x555555d99c08 <_PyRuntime+360664>, abs_name=abs_name@entry=0x7ffff74f86d0) at Python/import.c:4125
#15 0x0000555555950f66 in PyImport_ImportModuleLevelObject (name=name@entry=0x7ffff74f86d0, globals=globals@entry=0x7ffff746a4b0, locals=locals@entry=0x7ffff746a4b0,
    fromlist=0x7ffff7477cf0, level=level@entry=0) at Python/import.c:4241
#16 0x00005555558f7265 in _PyEval_ImportNameWithImport (tstate=tstate@entry=0x555555d99c08 <_PyRuntime+360664>, import_func=0x7ffff75be9f0, globals=globals@entry=0x7ffff746a4b0,
    locals=locals@entry=0x7ffff746a4b0, name=name@entry=0x7ffff74f86d0, fromlist=fromlist@entry=0x7ffff7477cf0, level=0x555555d49188 <_PyRuntime+30296>) at Python/ceval.c:2975
#17 0x00005555558848bf in _PyEval_ImportName (tstate=tstate@entry=0x555555d99c08 <_PyRuntime+360664>, builtins=0x7ffff75be930, globals=0x7ffff746a4b0, locals=0x7ffff746a4b0,
    name=0x7ffff74f86d0, fromlist=0x7ffff7477cf0, level=0x555555d49188 <_PyRuntime+30296>) at Python/ceval.c:2954
#18 0x000055555586141a 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:6460
#19 0x000055555583f08b in _PyEval_EvalFrame (tstate=0x555555d99c08 <_PyRuntime+360664>, frame=0x7ffff7fa7020, throwflag=0) at ./Include/internal/pycore_ceval.h:118
#20 _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
#21 0x000055555583ee1e in PyEval_EvalCode (co=co@entry=0x555555f3baf0, globals=globals@entry=0x7ffff746a4b0, locals=locals@entry=0x7ffff746a4b0) at Python/ceval.c:686
#22 0x00005555559c8f8e in run_eval_code_obj (tstate=0x555555d99c08 <_PyRuntime+360664>, co=co@entry=0x555555f3baf0, globals=globals@entry=0x7ffff746a4b0, locals=locals@entry=0x7ffff746a4b0)
    at Python/pythonrun.c:1368
#23 0x00005555559c8adb in run_mod (mod=mod@entry=0x555555f43b30, 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/_zoneinfo.c 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.13bugs and security fixes3.14bugs and security fixes3.15new features, bugs and security fixesinterpreter-core(Objects, Python, Grammar, and Parser dirs)type-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