Three lines
import bertini
bertini.System().to_classic_input() # Segmentation fault (core dumped)
Also crashes with variables present, as long as there are no functions:
S = bertini.System(); vg = bertini.VariableGroup(); vg.append(Variable('x'))
S.add_variable_group(vg)
S.to_classic_input() # Segmentation fault
The trigger is zero functions. A system with functions but no variable group is fine —
it raises a clean RuntimeError: SLP compile: a function references the variable 'x', which is not in the system's variable ordering, which is the behaviour one wants.
Cause
System::CoefficientBound<NumT>() (core/src/system/system.cpp:944) ends with
bound = max(f_vals.array().abs().maxCoeff(),
dh_dx.array().abs().maxCoeff(), bound);
With no functions, f_vals is an empty vector and dh_dx an empty matrix, and Eigen's
maxCoeff() on an empty array is undefined behaviour — it asserts in a debug build and
reads out of bounds in a release one.
DegreeBound(), immediately below it in the same file, already guards precisely this case:
auto degs = Degrees(Variables());
if (degs.empty())
return 0; // a system with no functions has no degree bound
CoefficientBound needs the same guard.
The Python path in is to_classic_input() → EmitConfig (io/classic_writer.hpp), which
emits coefficientbound: and so calls CoefficientBound<complex_dbl>(). But the bug is in
CoefficientBound itself, so any other caller reaching it with a function-less system
crashes too.
Expected
A function-less system is a legitimate object — bertini.System() constructs one, and
num_functions(), num_variables() and degrees() all answer for it correctly (0, 0,
[]). Its coefficient bound should be 0, matching DegreeBound()'s convention, and no
call reachable from Python should ever be able to segfault.
Found via
A downstream records layer that writes systems as classic-input text; a parse that silently
produced an empty system (filed separately) then handed that empty system back to
to_classic_input(), which crashed the interpreter rather than reporting anything.
Version: 3.5.0.dev0 (develop @ 8f0cd0f), Linux, Python 3.14.
Three lines
Also crashes with variables present, as long as there are no functions:
The trigger is zero functions. A system with functions but no variable group is fine —
it raises a clean
RuntimeError: SLP compile: a function references the variable 'x', which is not in the system's variable ordering, which is the behaviour one wants.Cause
System::CoefficientBound<NumT>()(core/src/system/system.cpp:944) ends withbound = max(f_vals.array().abs().maxCoeff(), dh_dx.array().abs().maxCoeff(), bound);With no functions,
f_valsis an empty vector anddh_dxan empty matrix, and Eigen'smaxCoeff()on an empty array is undefined behaviour — it asserts in a debug build andreads out of bounds in a release one.
DegreeBound(), immediately below it in the same file, already guards precisely this case:CoefficientBoundneeds the same guard.The Python path in is
to_classic_input()→EmitConfig(io/classic_writer.hpp), whichemits
coefficientbound:and so callsCoefficientBound<complex_dbl>(). But the bug is inCoefficientBounditself, so any other caller reaching it with a function-less systemcrashes too.
Expected
A function-less system is a legitimate object —
bertini.System()constructs one, andnum_functions(),num_variables()anddegrees()all answer for it correctly (0,0,[]). Its coefficient bound should be0, matchingDegreeBound()'s convention, and nocall reachable from Python should ever be able to segfault.
Found via
A downstream records layer that writes systems as classic-input text; a parse that silently
produced an empty system (filed separately) then handed that empty system back to
to_classic_input(), which crashed the interpreter rather than reporting anything.Version:
3.5.0.dev0(develop @ 8f0cd0f), Linux, Python 3.14.