1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2024-09-19 23:03:53 -04:00

Merge pull request #9920 from 9999years/forbid-nested-debuggers

Forbid nested debuggers
This commit is contained in:
Théophane Hufschmitt 2024-03-05 06:58:29 +01:00 committed by GitHub
commit e164b39ee9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 53 additions and 12 deletions

View file

@ -0,0 +1,32 @@
---
synopsis: Nested debuggers are no longer supported
prs: 9920
---
Previously, evaluating an expression that throws an error in the debugger would
enter a second, nested debugger:
```
nix-repl> builtins.throw "what"
error: what
Starting REPL to allow you to inspect the current state of the evaluator.
Welcome to Nix 2.18.1. Type :? for help.
nix-repl>
```
Now, it just prints the error message like `nix repl`:
```
nix-repl> builtins.throw "what"
error:
… while calling the 'throw' builtin
at «string»:1:1:
1| builtins.throw "what"
| ^
error: what
```

View file

@ -336,13 +336,7 @@ ReplExitStatus NixRepl::mainLoop()
printMsg(lvlError, e.msg()); printMsg(lvlError, e.msg());
} }
} catch (EvalError & e) { } catch (EvalError & e) {
// in debugger mode, an EvalError should trigger another repl session. printMsg(lvlError, e.msg());
// when that session returns the exception will land here. No need to show it again;
// show the error for this repl session instead.
if (state->debugRepl && !state->debugTraces.empty())
showDebugTrace(std::cout, state->positions, state->debugTraces.front());
else
printMsg(lvlError, e.msg());
} catch (Error & e) { } catch (Error & e) {
printMsg(lvlError, e.msg()); printMsg(lvlError, e.msg());
} catch (Interrupted & e) { } catch (Interrupted & e) {

View file

@ -762,10 +762,24 @@ std::unique_ptr<ValMap> mapStaticEnvBindings(const SymbolTable & st, const Stati
return vm; return vm;
} }
/**
* Sets `inDebugger` to true on construction and false on destruction.
*/
class DebuggerGuard {
bool & inDebugger;
public:
DebuggerGuard(bool & inDebugger) : inDebugger(inDebugger) {
inDebugger = true;
}
~DebuggerGuard() {
inDebugger = false;
}
};
void EvalState::runDebugRepl(const Error * error, const Env & env, const Expr & expr) void EvalState::runDebugRepl(const Error * error, const Env & env, const Expr & expr)
{ {
// double check we've got the debugRepl function pointer. // Make sure we have a debugger to run and we're not already in a debugger.
if (!debugRepl) if (!debugRepl || inDebugger)
return; return;
auto dts = auto dts =
@ -792,6 +806,7 @@ void EvalState::runDebugRepl(const Error * error, const Env & env, const Expr &
auto se = getStaticEnv(expr); auto se = getStaticEnv(expr);
if (se) { if (se) {
auto vm = mapStaticEnvBindings(symbols, *se.get(), env); auto vm = mapStaticEnvBindings(symbols, *se.get(), env);
DebuggerGuard _guard(inDebugger);
auto exitStatus = (debugRepl)(ref<EvalState>(shared_from_this()), *vm); auto exitStatus = (debugRepl)(ref<EvalState>(shared_from_this()), *vm);
switch (exitStatus) { switch (exitStatus) {
case ReplExitStatus::QuitAll: case ReplExitStatus::QuitAll:

View file

@ -153,6 +153,7 @@ struct DebugTrace {
bool isError; bool isError;
}; };
class EvalState : public std::enable_shared_from_this<EvalState> class EvalState : public std::enable_shared_from_this<EvalState>
{ {
public: public:
@ -222,6 +223,7 @@ public:
*/ */
ReplExitStatus (* debugRepl)(ref<EvalState> es, const ValMap & extraEnv); ReplExitStatus (* debugRepl)(ref<EvalState> es, const ValMap & extraEnv);
bool debugStop; bool debugStop;
bool inDebugger = false;
int trylevel; int trylevel;
std::list<DebugTrace> debugTraces; std::list<DebugTrace> debugTraces;
std::map<const Expr*, const std::shared_ptr<const StaticEnv>> exprEnvs; std::map<const Expr*, const std::shared_ptr<const StaticEnv>> exprEnvs;

View file

@ -8,7 +8,6 @@
namespace nix { namespace nix {
namespace {
/** /**
* A helper for writing `boost::format` expressions. * A helper for writing `boost::format` expressions.
* *
@ -35,14 +34,13 @@ inline void formatHelper(F & f, const T & x, const Args & ... args)
/** /**
* Set the correct exceptions for `fmt`. * Set the correct exceptions for `fmt`.
*/ */
void setExceptions(boost::format & fmt) inline void setExceptions(boost::format & fmt)
{ {
fmt.exceptions( fmt.exceptions(
boost::io::all_error_bits ^ boost::io::all_error_bits ^
boost::io::too_many_args_bit ^ boost::io::too_many_args_bit ^
boost::io::too_few_args_bit); boost::io::too_few_args_bit);
} }
}
/** /**
* A helper for writing a `boost::format` expression to a string. * A helper for writing a `boost::format` expression to a string.