Open RyanGlScott opened 1 year ago
A third option is that the rustc
API might offer a way to look up what the actual order of static initialization should be. After all, if you write this:
static A: Option<u32> = B;
static B: Option<u32> = Some(42);
Then rustc
has to check that B
must be initialized before it can initialize A
. Perhaps there is a programmatic way of doing this check?
crux-mir
is successfully able to verify this program:So far, so good. What happens if we rename the
static
values, however? This program should be equivalent to the first one, as we have simply swapped the names forA
andB
:But
crux-mir
fails to run this version of the program:Here is what I think is going on:
static
values (using thetransStatics
function),crucible-mir
will translate each of the statics that appear in thestatics :: Map DefId Static
field of aCollection
.statics
is keyed byDefId
s,crucible-mir
will iterate through thestatic
values according to the lexicographic ordering of their value names. In the examples above, this means thatA
will always be translated beforeB
, regardless of the relative ordering of eachstatic
value in the source code.A
's definition depends onB
, but we translateA
before we have translatedB
. Butcrucible-mir
translates a constant by fully evaluating its definition, so this means that we have to eagerly evaluateB
when translatingA
. BecauseB
hasn't been translated yet, no value has been written to its correspondingGlobalVar
, and this causes theAttempted to read uninitialized reference cell
failure seen above when attempting to read from theGlobalVar
.One possible solution here is to implement some sort of dependency analysis that allows
crucible-mir
to realize when onestatic
value is defined in terms of another. This would likely work well in the small example above, but I could envision this becoming tricky when the right-hand sides ofstatic
values are more complex.Another possible solution would be to make
crucible-mir
's translation ofstatic
values lazier. During simulation, ifcrucible-mir
encounters astatic
with aGlobalVar
that hasn't yet been written to, run the CFG for thestatic
's definition (computed with this code), write the result value to theGlobalVar
, and return that value to the simulator. On subsequent attempts to load thestatic
value, use the cached value in theGlobalVar
rather than recomputing the CFG. This idea is inspired bycrucible-llvm
's lazy translation of function CFGs (see https://github.com/GaloisInc/crucible/issues/995).