Skip to content

SIGILL (Illegal instruction) on process exit, triggered by merely instantiating Model() — ARM64 (Home Assistant Green) Environment #425

Description

@albiezw

SIGILL (Illegal instruction) on process exit, triggered by merely instantiating Model() — ARM64 (Home Assistant Green)
Environment
mip version: 1.17.6
Python: 3.13
Platform: aarch64 (ARM64) — Home Assistant Green (Amlogic-based SBC), running inside a Home Assistant add-on container
Installed via pip inside a Python venv
Minimal reproduction

This is as small as it gets — no variables, no constraints, no call to optimize():

python
from mip import Model
m = Model()
print("created")

Output:

created
Illegal instruction (core dumped)

"created" prints correctly, then the process is killed by the kernel with SIGILL right as the script ends — there is no Python traceback, since this happens below the level Python's own exception handling can catch.

A slightly larger reproduction that actually solves a trivial problem shows the same thing, just with solver output first:

python
from mip import Model, xsum, minimize, BINARY
m = Model()
x = m.add_var(var_type=BINARY)
m.objective = minimize(x)
m += x >= 0
m.optimize()
print(x.x)
Welcome to the CBC MILP Solver
Version: devel
Build Date: Mar 23 2026
Starting solution of the Linear programming relaxation problem using Primal Simplex
Coin0506I Presolve 0 (-1) rows, 0 (-1) columns and 0 (-1) elements
Clp0000I Optimal - objective value 0
Coin0511I After Postsolve, objective 0, infeasibilities - dual 0 (0), primal 0 (0)
Clp0032I Optimal objective 0 - 0 iterations time 0.002, Presolve 0.00, Idiot 0.00
Starting MIP optimization
Cbc3007W No integer variables
0.0
Illegal instruction (core dumped)

Since the crash already reproduces with just Model() and no solve, the actual optimization/solve path is irrelevant — the problem is tied purely to model instantiation and whatever gets torn down at process exit as a result.

This is not a Python-level object-lifecycle issue

This came out of debugging a much larger application (a day-ahead energy optimizer add-on) that was crashing silently on this hardware. Before isolating it to mip, I ruled out several unrelated causes, and then specifically tested whether normal Python object cleanup (refcounting / cyclic GC) was involved:

Not OpenBLAS/numpy CPU dispatch — forcing OPENBLAS_CORETYPE to both the auto-detected CORTEXA53 and the generic ARMV8 baseline made no difference to the original crash.
Not OpenSSL ARM crypto extensions — OPENSSL_armcap=0 made no difference either.
os._exit(0) immediately after use reliably avoids the crash. Calling os._exit(0) right after the model has been used skips the crash entirely, every time — in both the full application and this minimal reproduction.
Explicit del of the model and its variables does NOT avoid the crash — even though it doesn't raise immediately, the crash still occurs later, only at actual process exit.
Explicitly forcing gc.collect() right after del also does not avoid the crash — ruling out a simple reference-cycle-delays-collection explanation. The crash still only happens at process exit, regardless of Python-level reference counting or cyclic garbage collection.

Since neither explicit deletion nor forced garbage collection changes when the crash occurs — only skipping the entire exit sequence via os._exit() does — this points to something at the C/process level that runs unconditionally at exit (e.g., a native atexit() handler registered by the bundled Cbc library at initialization time), rather than a Python object destructor tied to the Model instance's lifetime.

Suspected cause

Model.del (in mip/model.py) does:

python
def del(self: "Model"):
del self.solver

but based on the testing above, this specific destructor doesn't appear to be what's crashing (since explicit del+gc.collect() don't trigger or avoid it). My current suspicion is a native-level exit hook registered when the bundled aarch64 Cbc shared library is loaded/initialized (i.e., at Model() construction time), which executes an instruction unsupported by this specific ARM64 core during its own process-exit cleanup path.

Question

Is there a known aarch64/ARM64-specific issue with the bundled Cbc library's process-exit cleanup (as opposed to per-object destruction)? Is there a way to disable or safely trigger that cleanup path early, or is a rebuilt/updated Cbc binary needed for this platform?

I don't have gdb available in this environment (couldn't install it), but I'm happy to run further diagnostics if that would help narrow this down further.

regards, Albert

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions