Initialize interpolation index in interp_profile (fixes nondeterministic solve)#170
Merged
Merged
Conversation
interp_profile passed the local integer ind to eval_neville_polynom without initializing it. ind is the in/out warm-start window index; on the first call it was read uninitialized (and could drive an out-of-bounds read of the grid array), making the interpolated background profiles depend on stack garbage and the whole solve non-deterministic run to run. Set ind = 0 before the loop in both copies of interp_profile. Verified on the ql-balance f_6_2 case: - valgrind memcheck: 22 "uninitialised value" reads in eval_neville_polynom (origin: interp_profile ind) -> 0. - 5/5 fresh single-thread runs now produce byte-identical EB.dat; before, run-to-run EB differed by ~7e-4 relative.
This was referenced Jul 1, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
interp_profile(in bothQL-Balance/src/base/wave_code_data_64bit.f90andKiLCA/interface/wave_code_data_64bit.f90) declares a local integerindand passes it toeval_neville_polynomwithout initializing it:indis the in/out warm-start window index for the interpolation. On the first call it is read uninitialized. Ineval_neville_polynom(KiLCA/interp/interp.h) the guardif (*ind < 0 || *ind > dim-1) *ind = dim/2;only catches out-of-range garbage; in-range garbage flows throughfind_index_for_interp, and out-of-range garbage triggers an out-of-bounds read of the grid arrayxg[*ind].Because
interp_profileinterpolates the initial background profiles (q, n, Ti, Te, ...) onto the balance grid, this seeds a stack-garbage-dependent perturbation that propagates through the entire linear solve. The result is a solve that is not reproducible run to run for identical inputs, even single-threaded.This is a pre-existing bug on
main, independent of the fortnum migration. It is a major contributor to the ql-balance / KiLCA golden-record instability seen in the fortnum PR stack (#144).Fix
Initialize
ind = 0before the loop in both copies ofinterp_profile.0is a valid warm-start window index; the interpolation is otherwise unchanged.Verification
Case: ql-balance golden
f_6_2(m=6, n=2). Comparison quantity:flre/linear-data/m_6_n_2_flab_[1,0]/EB.dat.Fails on main
valgrind --tool=memcheck --track-origins=yeson the unfixed binary:Run-to-run (same binary, same inputs,
OMP_NUM_THREADS=1):EB.datdiffers at the first data value; max ~7e-4 relative.Passes after fix
valgrindon the fixed binary: the 22 uninitialised-value reads ineval_neville_polynomare gone (remaining 1 error is an unrelated strcpy over-read, fixed separately).5 fresh single-thread runs,
EB.datmd5:All byte-identical.
Notes