Custom recognizer crashes LLDB

I’m trying to follow the guide with only a minor change:

class FChdirRecognizer:
    def get_recognized_arguments(self, frame):
        if frame.name != 'fchdir':
            return []

        fd = frame.EvaluateExpression("$arg1").unsigned
        value = lldb.target.CreateValueFromExpression("fd", f"(int){fd}")  # <-- appears to cause the crash
        return [value]

Then adding the recognizer:

(lldb) version
lldb-1300.0.42.3
Swift version 5.5.2-dev

(lldb) frame recognizer add -l LLDBScripts.FChdirRecognizer -n fchdir -s libsystem_kernel.dylib

However, that leads a crash within Xcode 13.2.1:

Message from debugger: The LLDB RPC server has crashed. You may need to manually terminate your process. The crash log is located in ~/Library/Logs/DiagnosticReports and has a prefix ‘lldb-rpc-server’. Please file a bug and attach the most recent crash log.

From the crashlog:

Crashed Thread:        6  <lldb.process.internal-state(pid=88192)>

Exception Type:        EXC_BAD_ACCESS (SIGSEGV)
Exception Codes:       KERN_INVALID_ADDRESS at 0x0000000000000000
Exception Note:        EXC_CORPSE_NOTIFY

Termination Signal:    Segmentation fault: 11
Termination Reason:    Namespace SIGNAL, Code 0xb
Terminating Process:   exc handler [88172]

...

Thread 6 Crashed:: <lldb.process.internal-state(pid=88192)>
0   com.apple.LLDB.framework      	0x000000010f2c73c8 lldb_private::ScriptedStackFrameRecognizer::RecognizeFrame(std::__1::shared_ptr<lldb_private::StackFrame>) + 216
1   com.apple.LLDB.framework      	0x000000010f2c8beb lldb_private::StackFrameRecognizerManager::RecognizeFrame(std::__1::shared_ptr<lldb_private::StackFrame>) + 155
2   com.apple.LLDB.framework      	0x000000010f2c2ee9 lldb_private::StackFrame::GetRecognizedFrame() + 169
3   com.apple.LLDB.framework      	0x000000010f2eee2b lldb_private::Thread::SelectMostRelevantFrame() + 75
4   com.apple.LLDB.framework      	0x000000010f2ef0d9 lldb_private::Thread::WillStop() + 89
5   com.apple.LLDB.framework      	0x000000010f2f8165 lldb_private::ThreadList::ShouldStop(lldb_private::Event*) + 1109
6   com.apple.LLDB.framework      	0x000000010f2a11c5 lldb_private::Process::ShouldBroadcastEvent(lldb_private::Event*) + 421
7   com.apple.LLDB.framework      	0x000000010f29d7f8 lldb_private::Process::HandlePrivateEvent(std::__1::shared_ptr<lldb_private::Event>&) + 280
8   com.apple.LLDB.framework      	0x000000010f2a1fb5 lldb_private::Process::RunPrivateStateThread(bool) + 1477
9   com.apple.LLDB.framework      	0x000000010f2a15f5 lldb_private::Process::PrivateStateThread(void*) + 21
10  com.apple.LLDB.framework      	0x000000010f1e7747 lldb_private::HostNativeThreadBase::ThreadCreateTrampoline(void*) + 103
11  libsystem_pthread.dylib       	0x00007fff205978fc _pthread_start + 224
12  libsystem_pthread.dylib       	0x00007fff20593443 thread_start + 15

...

Further debugging showed that lldb.target is not set (i.e. None) when FChdirRecognizer.get_recognized_arguments is triggered.

Interestingly, this function is called 3 times every time the symbolic breakpoint for fchdir is hit.

I was able to circumvent this issue by using frame.thread.process.target instead.

However, within the context of the recognizer, both frame.EvaluateExpression and target.EvaluateExpression hang lldb when used with a function: target.EvaluateExpression("(void *)malloc(0);").

Hi @Kentzo! Convenience variables (lldb.target, lldb.process, lldb.thread, etc.) are only available within the embedded interpreter in lldb, so you don’t want to use them in your scripts directly.

I see that you were able to address that crash, but with regard to the hang, please make sure to file a GitHub issue and attach a reproducer so we can take a look at it.

Thanks!

The official guide as well as inline help in lldb uses lldb.target. You may want to change the docs.

The Python Reference page says:

While extremely convenient, these variables have a couple caveats that you should be aware of…

Moreover, they are only defined and meaningful while in the interactive Python interpreter. There is no guarantee on their value in any other situation, hence you should not use them when defining Python formatters, breakpoint scripts and commands…

But there are a lot of doc pages, and there may well be some other place that was giving the wrong impression. If you can point us to the passage you found that contradicted the statement from the Python reference, we’ll be happy to fix it.

The example in Python Reference — The LLDB Debugger as well as inline help for the frame recognizer lldb command (seems to use the same text).

Thanks! I fixed those two references.