llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
27.07k stars 11.08k forks source link

[LLDB][Crash] segfault when printing evaluation error result while target is running #93313

Open nsadeveloper789 opened 1 month ago

nsadeveloper789 commented 1 month ago

a92f7832f35c6c4792d8693e724c19802da75b36

This commit actually fixes a bug we were encountering with LLDB 1500 in Xcode, but trades it for a segfault in the latest main. The commit adds some calls to ValueObjectConstResult::Create(nullptr, error). If, in Python, you call repr(value) on such a value, LLDB will crash:

#0  in lldb_private::FormatManager::GetPossibleMatches(lldb_private::ValueObject&, lldb_private::CompilerType, lldb::DynamicValueType, std::vector<lldb_private::FormattersMatchCandidate, std::allocator<lldb_private::FormattersMatchCandidate> >&, lldb_private::FormattersMatchCandidate::Flags, bool) [clone .localalias] ()
#1  in lldb_private::FormattersMatchData::GetMatchesVector() ()
#2  in void lldb_private::TypeCategoryMap::Get<std::shared_ptr<lldb_private::TypeFormatImpl> >(lldb_private::FormattersMatchData&, std::shared_ptr<lldb_private::TypeFormatImpl>&) ()
#3  in std::shared_ptr<lldb_private::TypeFormatImpl> lldb_private::FormatManager::GetCached<std::shared_ptr<lldb_private::TypeFormatImpl> >(lldb_private::FormattersMatchData&) ()
#4  in std::shared_ptr<lldb_private::TypeFormatImpl> lldb_private::FormatManager::Get<std::shared_ptr<lldb_private::TypeFormatImpl> >(lldb_private::ValueObject&, lldb::DynamicValueType) ()
#5  in lldb_private::FormatManager::GetFormat(lldb_private::ValueObject&, lldb::DynamicValueType) ()
#6  in lldb_private::DataVisualization::GetFormat(lldb_private::ValueObject&, lldb::DynamicValueType) ()
#7  in lldb_private::ValueObject::UpdateFormatsIfNeeded() [clone .localalias] ()
#8  in lldb_private::ValueObject::UpdateValueIfNeeded(bool) [clone .localalias] ()
#9  in lldb_private::ValueObjectPrinter::SetupMostSpecializedValue() [clone .localalias] ()
#10 in lldb_private::ValueObjectPrinter::ValueObjectPrinter(lldb_private::ValueObject&, lldb_private::Stream*, lldb_private::DumpValueObjectOptions const&) ()
#11 in lldb_private::ValueObject::Dump(lldb_private::Stream&, lldb_private::DumpValueObjectOptions const&) [clone .localalias] ()
#12 in lldb::SBValue::GetDescription(lldb::SBStream&) ()
#13 in _wrap_SBValue___repr__ ()

(I've scrubbed addresses and file paths.)

While I had my own script I was working from, I suspect it's fairly easy to reproduce by amending TestRunLocker.py to assert on repr(val), not just repr(error) or error.GetCString().

I was able to fix it by replacing nullptr with exe_ctx.GetBestExecutionContextScope(), but I only tried this with SBTarget.cpp. I'm not certain this is the correct fix, or if the formatters need fixing to handle nullptr. There are also other places that pass in nullptr besides those added by the referenced commit.

Aside

If you're curious, the actual problem we were investigating involved SBProcess.GetMemoryRegionInfo. We eventually devised a script that turned out to be very similar to your TestRunLocker.py case:

  1. Launch a target process in async mode that is just a sleep loop.
  2. List the memory regions (as a baseline before the actual test).
  3. Continue execution of the process and wait for running.
  4. Attempt to evaluate an expression. (We were evaluating $pc.) It correctly returned an error, because the target is running.
  5. Interrupt the process and wait for stop.
  6. List the memory regions again.

If, for the second query, we used GetMemoryRegions, we got an empty list. If we used GetMemoryRegionInfo, we got an error: qMemoryRegionInfo not supported.

In preparing to submit that bug, we built the latest and re-ran our script, but it crashed instead. We can confirm the qMemoryRegionInfo thing is no longer an issue in the latest main branch, but this new bug remains. So long as we avoid printing the evaluated value, our script now behaves correctly.

llvmbot commented 1 month ago

@llvm/issue-subscribers-lldb

Author: Dan (nsadeveloper789)

a92f7832f35c6c4792d8693e724c19802da75b36 This commit actually fixes a bug we were encountering with LLDB 1500 in Xcode, but trades it for a segfault in the latest `main`. The commit adds some calls to `ValueObjectConstResult::Create(nullptr, error)`. If, in Python, you call `repr(value)` on such a value, LLDB will crash: ``` #0 in lldb_private::FormatManager::GetPossibleMatches(lldb_private::ValueObject&, lldb_private::CompilerType, lldb::DynamicValueType, std::vector<lldb_private::FormattersMatchCandidate, std::allocator<lldb_private::FormattersMatchCandidate> >&, lldb_private::FormattersMatchCandidate::Flags, bool) [clone .localalias] () #1 in lldb_private::FormattersMatchData::GetMatchesVector() () #2 in void lldb_private::TypeCategoryMap::Get<std::shared_ptr<lldb_private::TypeFormatImpl> >(lldb_private::FormattersMatchData&, std::shared_ptr<lldb_private::TypeFormatImpl>&) () #3 in std::shared_ptr<lldb_private::TypeFormatImpl> lldb_private::FormatManager::GetCached<std::shared_ptr<lldb_private::TypeFormatImpl> >(lldb_private::FormattersMatchData&) () #4 in std::shared_ptr<lldb_private::TypeFormatImpl> lldb_private::FormatManager::Get<std::shared_ptr<lldb_private::TypeFormatImpl> >(lldb_private::ValueObject&, lldb::DynamicValueType) () #5 in lldb_private::FormatManager::GetFormat(lldb_private::ValueObject&, lldb::DynamicValueType) () #6 in lldb_private::DataVisualization::GetFormat(lldb_private::ValueObject&, lldb::DynamicValueType) () #7 in lldb_private::ValueObject::UpdateFormatsIfNeeded() [clone .localalias] () #8 in lldb_private::ValueObject::UpdateValueIfNeeded(bool) [clone .localalias] () #9 in lldb_private::ValueObjectPrinter::SetupMostSpecializedValue() [clone .localalias] () #10 in lldb_private::ValueObjectPrinter::ValueObjectPrinter(lldb_private::ValueObject&, lldb_private::Stream*, lldb_private::DumpValueObjectOptions const&) () #11 in lldb_private::ValueObject::Dump(lldb_private::Stream&, lldb_private::DumpValueObjectOptions const&) [clone .localalias] () #12 in lldb::SBValue::GetDescription(lldb::SBStream&) () #13 in _wrap_SBValue___repr__ () ``` (I've scrubbed addresses and file paths.) While I had my own script I was working from, I suspect it's fairly easy to reproduce by amending `TestRunLocker.py` to assert on `repr(val)`, not just `repr(error)` or `error.GetCString()`. I was able to fix it by replacing `nullptr` with `exe_ctx.GetBestExecutionContextScope()`, but I only tried this with `SBTarget.cpp`. I'm not certain this is the correct fix, or if the formatters need fixing to handle nullptr. There are also other places that pass in nullptr besides those added by the referenced commit. ### Aside If you're curious, the actual problem we were investigating involved `SBProcess.GetMemoryRegionInfo`. We eventually devised a script that turned out to be very similar to your `TestRunLocker.py` case: 1. Launch a target process in async mode that is just a sleep loop. 2. List the memory regions (as a baseline before the actual test). 3. Continue execution of the process and wait for running. 4. Attempt to evaluate an expression. (We were evaluating `$pc`.) It correctly returned an error, because the target is running. 5. Interrupt the process and wait for stop. 6. List the memory regions again. If, for the second query, we used `GetMemoryRegions`, we got an empty list. If we used `GetMemoryRegionInfo`, we got an error: `qMemoryRegionInfo not supported`. In preparing to submit that bug, we built the latest and re-ran our script, but it crashed instead. We can confirm the `qMemoryRegionInfo` thing is no longer an issue in the latest `main` branch, but this new bug remains. So long as we avoid printing the evaluated value, our script now behaves correctly.
jimingham commented 1 month ago

I fixed this in https://github.com/apple/llvm-project/pull/8821

jimingham commented 1 month ago

Oops, make that:

https://github.com/llvm/llvm-project/pull/93880

The previous one was for the wrong project...