This revision was automatically updated to reflect the committed changes.
Closed by commit rG59237bb52c94: [lldb] Use a time-based timeout in
IRInterpreter (authored by JDevlieghere).
Herald added a subscriber: lldb-commits.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D102762/new/
https://reviews.llvm.org/D102762
Files:
lldb/include/lldb/Expression/IRInterpreter.h
lldb/include/lldb/Target/Target.h
lldb/source/Expression/IRInterpreter.cpp
lldb/source/Expression/LLVMUserExpression.cpp
lldb/test/API/commands/expression/ir-interpreter/TestIRInterpreter.py
Index: lldb/test/API/commands/expression/ir-interpreter/TestIRInterpreter.py
===================================================================
--- lldb/test/API/commands/expression/ir-interpreter/TestIRInterpreter.py
+++ lldb/test/API/commands/expression/ir-interpreter/TestIRInterpreter.py
@@ -12,6 +12,41 @@
class IRInterpreterTestCase(TestBase):
NO_DEBUG_INFO_TESTCASE = True
+ def time_expression(self, expr, options):
+ start = time.time()
+ res = self.target.EvaluateExpression(expr, options)
+ return res, time.time() - start
+
+ def test_interpreter_timeout(self):
+ """Test the timeout logic in the IRInterpreter."""
+ self.build()
+ self.target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
+ self.assertTrue(self.target, VALID_TARGET)
+
+ # A non-trivial infinite loop.
+ inf_loop = "for (unsigned i = 0; i < 100; ++i) --i; 1"
+ timeout_error = "Reached timeout while interpreting expression"
+ options = lldb.SBExpressionOptions()
+
+ # This is an IRInterpreter specific test, so disable the JIT.
+ options.SetAllowJIT(False)
+
+ # No timeout means a 500ms.
+ options.SetTimeoutInMicroSeconds(0)
+ res, duration_sec = self.time_expression(inf_loop, options)
+ self.assertIn(timeout_error, str(res.GetError()))
+
+ # Depending on the machine load the expression might take quite some
+ # time, so give the time a generous upper bound.
+ self.assertLess(duration_sec, 15)
+
+ # Try a simple one second timeout.
+ options.SetTimeoutInMicroSeconds(1000000)
+ res, duration_sec = self.time_expression(inf_loop, options)
+ self.assertIn(timeout_error, str(res.GetError()))
+ self.assertGreaterEqual(duration_sec, 1)
+ self.assertLess(duration_sec, 30)
+
def setUp(self):
# Call super's setUp().
TestBase.setUp(self)
Index: lldb/source/Expression/LLVMUserExpression.cpp
===================================================================
--- lldb/source/Expression/LLVMUserExpression.cpp
+++ lldb/source/Expression/LLVMUserExpression.cpp
@@ -120,7 +120,7 @@
IRInterpreter::Interpret(*module, *function, args, *m_execution_unit_sp,
interpreter_error, function_stack_bottom,
- function_stack_top, exe_ctx);
+ function_stack_top, exe_ctx, options.GetTimeout());
if (!interpreter_error.Success()) {
diagnostic_manager.Printf(eDiagnosticSeverityError,
@@ -233,7 +233,7 @@
eDiagnosticSeverityError,
"Couldn't complete execution; the thread "
"on which the expression was being run: 0x%" PRIx64
- " exited during its execution.",
+ " exited during its execution.",
expr_thread_id);
return execution_result;
} else if (execution_result != lldb::eExpressionCompleted) {
Index: lldb/source/Expression/IRInterpreter.cpp
===================================================================
--- lldb/source/Expression/IRInterpreter.cpp
+++ lldb/source/Expression/IRInterpreter.cpp
@@ -470,7 +470,8 @@
"Interpreter couldn't allocate memory";
static const char *memory_write_error = "Interpreter couldn't write to memory";
static const char *memory_read_error = "Interpreter couldn't read from memory";
-static const char *infinite_loop_error = "Interpreter ran for too many cycles";
+static const char *timeout_error =
+ "Reached timeout while interpreting expression";
static const char *too_many_functions_error =
"Interpreter doesn't handle modules with multiple function bodies.";
@@ -683,7 +684,8 @@
lldb_private::Status &error,
lldb::addr_t stack_frame_bottom,
lldb::addr_t stack_frame_top,
- lldb_private::ExecutionContext &exe_ctx) {
+ lldb_private::ExecutionContext &exe_ctx,
+ lldb_private::Timeout<std::micro> timeout) {
lldb_private::Log *log(GetLog(LLDBLog::Expressions));
if (log) {
@@ -722,11 +724,23 @@
frame.MakeArgument(&*ai, ptr);
}
- uint32_t num_insts = 0;
-
frame.Jump(&function.front());
- while (frame.m_ii != frame.m_ie && (++num_insts < 4096)) {
+ using clock = std::chrono::steady_clock;
+
+ // Compute the time at which the timeout has been exceeded.
+ std::optional<clock::time_point> end_time;
+ if (timeout && timeout->count() > 0)
+ end_time = clock::now() + *timeout;
+
+ while (frame.m_ii != frame.m_ie) {
+ // Timeout reached: stop interpreting.
+ if (end_time && clock::now() >= *end_time) {
+ error.SetErrorToGenericError();
+ error.SetErrorString(timeout_error);
+ return false;
+ }
+
const Instruction *inst = &*frame.m_ii;
LLDB_LOGF(log, "Interpreting %s", PrintValue(inst).c_str());
@@ -1571,11 +1585,5 @@
++frame.m_ii;
}
- if (num_insts >= 4096) {
- error.SetErrorToGenericError();
- error.SetErrorString(infinite_loop_error);
- return false;
- }
-
return false;
}
Index: lldb/include/lldb/Target/Target.h
===================================================================
--- lldb/include/lldb/Target/Target.h
+++ lldb/include/lldb/Target/Target.h
@@ -346,9 +346,16 @@
m_use_dynamic = dynamic;
}
- const Timeout<std::micro> &GetTimeout() const { return m_timeout; }
+ const Timeout<std::micro> &GetTimeout() const {
+ assert(m_timeout && m_timeout->count() > 0);
+ return m_timeout;
+ }
- void SetTimeout(const Timeout<std::micro> &timeout) { m_timeout = timeout; }
+ void SetTimeout(const Timeout<std::micro> &timeout) {
+ // Disallow setting a non-zero timeout.
+ if (timeout && timeout->count() > 0)
+ m_timeout = timeout;
+ }
const Timeout<std::micro> &GetOneThreadTimeout() const {
return m_one_thread_timeout;
Index: lldb/include/lldb/Expression/IRInterpreter.h
===================================================================
--- lldb/include/lldb/Expression/IRInterpreter.h
+++ lldb/include/lldb/Expression/IRInterpreter.h
@@ -11,6 +11,7 @@
#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/Timeout.h"
#include "lldb/lldb-public.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Pass.h"
@@ -44,7 +45,8 @@
lldb_private::Status &error,
lldb::addr_t stack_frame_bottom,
lldb::addr_t stack_frame_top,
- lldb_private::ExecutionContext &exe_ctx);
+ lldb_private::ExecutionContext &exe_ctx,
+ lldb_private::Timeout<std::micro> timeout);
private:
static bool supportsFunction(llvm::Function &llvm_function,
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits