libexpr: fix --debugger --ignore-try
a65e9e5828did not inform `tryEval` that (as far as it's concerned) `state.debug` moved to `state.errors.debug` and changed types. this resulted in the REPL erroneously coming up, that REPL having a non-debug state, and segfaulting after that REPL exited. it's probably good that `state.debug` isn't mutated by `--ignore-try` anymore. Change-Id: I1918e93edacd626452aa423fc2eb825080738835 Fixes:a65e9e5828("libexpr: extract eval error creation into new type") Signed-off-by: Dusk Banks <me@bb010g.com> (cherry picked from commit6a583136b7)
This commit is contained in:
committed by
eldritch horrors
parent
d2b1af70ee
commit
5fa27057b2
@@ -0,0 +1,9 @@
|
||||
---
|
||||
synopsis: "Fix `--debugger --ignore-try`"
|
||||
issues: []
|
||||
cls: [2440]
|
||||
category: "Fixes"
|
||||
credits: ["bb010g"]
|
||||
---
|
||||
|
||||
When in debug mode (e.g. from using the `--debugger` flag), enabling [`ignore-try`](@docroot@/command-ref/conf-file.md#conf-ignore-try) once again properly disables debug REPLs within [`builtins.tryEval`](@docroot@/language/builtins.md#builtins-tryEval) calls. Previously, a debug REPL would be started as if `ignore-try` was disabled, but that REPL wouldn't actually be in debug mode, and upon exiting the REPL the evaluating process would segfault.
|
||||
+25
-20
@@ -10,6 +10,7 @@
|
||||
#include "lix/libexpr/json-to-value.hh"
|
||||
#include "lix/libstore/names.hh"
|
||||
#include "lix/libstore/path-references.hh"
|
||||
#include "lix/libutil/finally.hh"
|
||||
#include "lix/libutil/processes.hh"
|
||||
#include "lix/libstore/store-api.hh"
|
||||
#include "lix/libexpr/value-to-json.hh"
|
||||
@@ -640,29 +641,33 @@ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Va
|
||||
{
|
||||
auto attrs = state.ctx.buildBindings(2);
|
||||
|
||||
std::optional<MaintainCount<int>> trylevel;
|
||||
std::unique_ptr<DebugState> savedDebug;
|
||||
if (state.ctx.debug) {
|
||||
trylevel.emplace(state.ctx.debug->trylevel);
|
||||
if (evalSettings.ignoreExceptionsDuringTry) {
|
||||
/* to prevent starting the repl from exceptions withing a tryEval, null it. */
|
||||
savedDebug = std::move(state.ctx.debug);
|
||||
{
|
||||
std::optional<MaintainCount<int>> trylevel;
|
||||
DebugState * savedDebug = nullptr;
|
||||
Finally resetDebug([&] {
|
||||
if (savedDebug) {
|
||||
state.ctx.errors.debug = savedDebug;
|
||||
}
|
||||
});
|
||||
if (state.ctx.errors.debug != nullptr) {
|
||||
trylevel.emplace(state.ctx.errors.debug->trylevel);
|
||||
if (evalSettings.ignoreExceptionsDuringTry) {
|
||||
/* to prevent starting the repl from exceptions within a tryEval, null it. */
|
||||
savedDebug = state.ctx.errors.debug;
|
||||
state.ctx.errors.debug = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
state.forceValue(*args[0], pos);
|
||||
attrs.insert(state.ctx.s.value, args[0]);
|
||||
attrs.alloc("success").mkBool(true);
|
||||
} catch (AssertionError & e) {
|
||||
attrs.alloc(state.ctx.s.value).mkBool(false);
|
||||
attrs.alloc("success").mkBool(false);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
state.forceValue(*args[0], pos);
|
||||
attrs.insert(state.ctx.s.value, args[0]);
|
||||
attrs.alloc("success").mkBool(true);
|
||||
} catch (AssertionError & e) {
|
||||
attrs.alloc(state.ctx.s.value).mkBool(false);
|
||||
attrs.alloc("success").mkBool(false);
|
||||
}
|
||||
|
||||
// restore the debugRepl pointer if we saved it earlier.
|
||||
if (savedDebug)
|
||||
state.ctx.debug = std::move(savedDebug);
|
||||
|
||||
v.mkAttrs(attrs);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
@args --debugger --ignore-try
|
||||
|
||||
we don't enter a debug repl through tryEval
|
||||
nix-repl> (builtins.tryEval ((x: throw "foo") 1)).success
|
||||
false
|
||||
|
||||
no segfault either
|
||||
nix-repl> :quit
|
||||
@@ -187,5 +187,6 @@ REPL_TEST(stack_vars);
|
||||
REPL_TEST(errors);
|
||||
REPL_TEST(idempotent);
|
||||
REPL_TEST(debug_frames);
|
||||
REPL_TEST(debug_ignore_try);
|
||||
|
||||
}; // namespace nix
|
||||
|
||||
Reference in New Issue
Block a user