CP-SAT 9.15.6755: memory-safety regression building large models — `std::bad_alloc` via `repr(IntVar)` and heap corruption (0xC0000374) via `IntVar.Proto()` (works on 9.14)
What version of OR-Tools and what language are you using? Version: ortools 9.15.6755 (Python), regression vs 9.14.6206 and 9.12.4544 Language: Python 3.12.9
Which solver are you using (e.g. CP-SAT, Routing Solver, GLOP, BOP, Gurobi)
CP-SAT (ortools.sat.python.cp_model)
What operating system (Linux, Windows, ...) and version? Windows 10/11 x64 (also reproduced on Linux CI).
We build a moderately sized CP-SAT model (~16 000 variables) programmatically. The build code and input data are unchanged across ortools versions.
- On 9.12.4544 and 9.14.6206: the model builds and solves fine (peak working set ≈ 360 MB).
- On 9.15.6755: the build aborts.
The failure first appears as MemoryError: bad allocation (std::bad_alloc)
raised from a plain repr() / str() of an IntVar, executed inside an eager
debug f-string:
logger.debug(f"{volume_var=}") # volume_var: normal IntVar, domain [0, 40]At the moment of that crash the process working set is only ~140 MB, so this
is a single pathological allocation, not gradual growth. Inside a
ProcessPoolExecutor it surfaces as BrokenProcessPool.
It is not only repr()
We removed the offending log line — the crash just moved to the next eager
f"{var=}" site, and then to a third one in another module. We then
monkey‑patched __repr__/__str__ to a cheap <Cls id=...> on all 27
classes of ortools.sat.python.cp_model. Logging stopped crashing and the
build progressed further, but the process still died, now with heap
corruption:
Windows fatal exception: code 0xC0000374 # STATUS_HEAP_CORRUPTION
Current thread (most recent call first):
File ".../classes/vars.py", line 113 in _var_can_be_positive
domain = list(var.Proto().domain)
...In isolation, both repr(var) and var.Proto().domain behave correctly on 9.15
(e.g. new_int_var(0, 50, "v") → repr is short, Proto().domain == [0, 50]).
The failures only appear while building the full model, and manifest in
different forms (std::bad_alloc via repr, heap corruption via Proto()).
This strongly suggests an underlying memory-safety regression in the 9.15
CP-SAT / pybind layer for large models.
Repro / attachments
model_dump.pb—CpModelProto(≈1.8 MB, 16 027 variables) serialized on 9.14 at the failing construction step.mem_probe.py— benchmark showing common construction patterns (sum, min/max, multiplication, big domains, affine) do not regress in memory on 9.15 (negative evidence).repr_probe.py— rebuilds each variable from the proto in isolation andstr()s them; does not reproduce (domain alone is not the trigger).real_build_probe.py,min_repro_attempt.py— driver / attempts.
Note: because the crash is context-dependent (full model construction), the isolated scripts don’t reproduce it by themselves; the reliable reproduction is the full build. We’re happy to provide a runnable end-to-end reproducer or work with a maintainer to capture the exact triggering API-call sequence.
What did you expect to see?
Building the model succeeds on 9.15, as it does on 9.14 / 9.12; repr()/str()
and IntVar.Proto() remain safe.
What did you see instead?
std::bad_alloc (via repr) and, after neutralizing repr, STATUS_HEAP_CORRUPTION
(0xC0000374) via IntVar.Proto(), during model construction on 9.15.6755 only.
API notes (possibly related)
CpModel.protois now a nativecp_model_helper.CpModelProto;proto.ByteSize()andproto.ParseFromString()are gone (present on ≤9.14).str(IntVar)formatting is inconsistent for in-model variables (sometimesname(lb..ub), sometimes justname); some variables report an empty.name.
Workaround
Pin ortools to ~9.14.6206. Removing logging is not a reliable fix (the crash
reappears via IntVar.Proto()).
mem_probe.py min_repro_attempt.py model_dump.zip real_build_probe.py repr_probe.py
Source: google/or-tools