LLVM: Interactive mode segfaults after runtime error
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
Mars |
Fix Released
|
Critical
|
Matt Giuca |
Bug Description
The interactive mode segfaults (sometimes, but repeatably) after a Mars error. After some fairly extensive analysis, I am becoming convinced that there is no "memory corruption" happening; there must be some weird interaction between Mercury and setjmp/longjmp.
For example, the following sequence segfaults:
?> error("x")
?> 1
Note that the segfault occurs on the call to show (at the instruction level, it is inside the actual compiled show:Int function). It is possible to get a few other instructions out, but eventually it will segfault. The longjmp puts it in a bad state.
This can be tested by writing Mercury wrappers around setjmp/longjmp, but it may not be possible to trigger it.
It might be prudent not to use them at all. Instead, either:
- Have @mars.throw_
- Use Mercury exceptions. Ensure that llvm.run_function does not say will_not_
- Try our luck with setcontext instead. This more advanced version of setjmp/longjmp seems to let you create separate stacks, so perhaps it won't mess with Mercury's stack unlike setjmp/longjmp.
Related branches
Changed in mars: | |
status: | Fix Committed → Fix Released |
There actually is a bug causing incorrect memory to be read. When a Mars statement fails in interactive mode, the environment (including the subscript map) is not updated, causing the same variable names to be reused on subsequent statements. The code in backend_ llvm.store_ global (which is used to write each local variable to an LLVM global) will be called with the name of an existing global, and LLVM will automatically generate a new unique name. However, the corresponding load_global will load from the old name, thus getting the value that was previously stored in the variable of the same name, usually with a different type.
This explains some very weird behaviour, such that if you throw an error with exactly 1 character:
?> a = error("X")
Runtime error: X
and then try to show an integer:
?> 42
Rather than segfaulting, it will print out the character in the error message:
X
This can be easily fixed; just make store_global delete any existing global if it finds one.