-
Notifications
You must be signed in to change notification settings - Fork 14.1k
[LLDB] Avoid crashes when inspecting MSVC STL types #140761
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-lldb Author: nerix (Nerixyz) ChangesWhen inspecting/printing types from MSVC's STL, LLDB would crash because it assumes these types were from libstdc++. Specifically, Fixes #120310. This still has one unresolved discussion: What about MS STL types? This is #24834, but there was a bit of discussion in #120310 as well. The main issue is that MSVC's STL uses the same type names as libstdc++ (i.e. neither uses an inline namespace like libc++ for some types). Full diff: https://github.com/llvm/llvm-project/pull/140761.diff 4 Files Affected:
diff --git a/lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp b/lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp
index b1fdc0fe37763..ed4536cb5c775 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp
@@ -74,9 +74,11 @@ lldb::ChildCacheState GenericOptionalFrontend::Update() {
if (m_stdlib == StdLib::LibCxx)
engaged_sp = m_backend.GetChildMemberWithName("__engaged_");
- else if (m_stdlib == StdLib::LibStdcpp)
- engaged_sp = m_backend.GetChildMemberWithName("_M_payload")
- ->GetChildMemberWithName("_M_engaged");
+ else if (m_stdlib == StdLib::LibStdcpp) {
+ ValueObjectSP payload = m_backend.GetChildMemberWithName("_M_payload");
+ if (payload)
+ engaged_sp = payload->GetChildMemberWithName("_M_engaged");
+ }
if (!engaged_sp)
return lldb::ChildCacheState::eRefetch;
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp
index 02113baf64b8c..54158d9a0d85a 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp
@@ -379,7 +379,7 @@ LibStdcppSharedPtrSyntheticFrontEnd::CalculateNumChildren() {
lldb::ValueObjectSP
LibStdcppSharedPtrSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {
- if (idx == 0)
+ if (idx == 0 && m_ptr_obj)
return m_ptr_obj->GetSP();
if (idx == 1) {
if (m_ptr_obj && !m_obj_obj) {
diff --git a/lldb/test/Shell/Process/Windows/msstl_smoke.cpp b/lldb/test/Shell/Process/Windows/msstl_smoke.cpp
new file mode 100644
index 0000000000000..4ae8f4256f24e
--- /dev/null
+++ b/lldb/test/Shell/Process/Windows/msstl_smoke.cpp
@@ -0,0 +1,57 @@
+// clang-format off
+
+// REQUIRES: target-windows
+// RUN: %build --compiler=clang-cl -o %t.exe --std c++20 -- %s
+// RUN: env LLDB_USE_NATIVE_PDB_READER=1 %lldb -f %t.exe -o "b main" -o "run" -o "fr v" -o c | FileCheck %s
+
+#include <bitset>
+#include <coroutine>
+#include <deque>
+#include <forward_list>
+#include <list>
+#include <map>
+#include <memory>
+#include <optional>
+#include <set>
+#include <string>
+#include <tuple>
+#include <unordered_map>
+#include <unordered_set>
+#include <variant>
+#include <vector>
+
+int main() {
+ std::shared_ptr<int> foo;
+ std::weak_ptr<int> weak = foo;
+ std::unique_ptr<int> unique(new int(42));
+ std::optional<int> opt;
+ std::string str = "str";
+ std::string longStr =
+ "string that is long enough such that no SSO can happen";
+ std::wstring wStr = L"wstr";
+ std::wstring longWStr =
+ L"string that is long enough such that no SSO can happen";
+ std::tuple<int, bool, float> tuple{1, false, 4.2};
+ std::coroutine_handle<> coroHandle;
+ std::bitset<16> bitset(123);
+
+ std::map<int, int> map{{1, 2}, {2, 4}, {3, 6}, {4, 8}, {5, 10}};
+ auto mapIt = map.find(3);
+ auto mapItEnd = map.find(9);
+ std::set<int> set{1, 2, 3};
+ std::multimap<int, int> mMap{{1, 2}, {1, 1}, {2, 4}};
+ std::multiset<int> mSet{1, 2, 3};
+
+ std::variant<int, float, std::string, std::monostate> variant;
+ std::list<int> list{1, 2, 3};
+ std::forward_list<int> fwList{1, 2, 3};
+
+ std::unordered_map<int, int> uMap{{1, 2}, {2, 4}, {3, 6}};
+ std::unordered_set<int> uSet{1, 2, 4};
+ std::unordered_multimap<int, int> uMMap{{1, 2}, {1, 1}, {2, 4}};
+ std::unordered_multiset<int> uMSet{1, 1, 2};
+ std::deque<int> deque{1, 2, 3};
+ std::vector<int> vec{1, 2, 3};
+}
+
+// CHECK: Process {{.*}} exited with status = 0 (0x00000000)
diff --git a/lldb/test/Shell/helper/build.py b/lldb/test/Shell/helper/build.py
index b2b8146e88c75..caaa14f90af1c 100755
--- a/lldb/test/Shell/helper/build.py
+++ b/lldb/test/Shell/helper/build.py
@@ -683,14 +683,14 @@ def _get_compilation_command(self, source, obj):
args.append("-fms-compatibility-version=19")
args.append("/c")
+ if self.std:
+ args.append("/std:" + self.std)
+
args.append("/Fo" + obj)
if self.toolchain_type == "clang-cl":
args.append("--")
args.append(source)
- if self.std:
- args.append("/std:" + self.std)
-
return ("compiling", [source], obj, self.compile_env, args)
def _get_link_command(self):
|
// RUN: %build --compiler=clang-cl -o %t.exe --std c++20 -- %s | ||
// RUN: env LLDB_USE_NATIVE_PDB_READER=1 %lldb -f %t.exe -o "b main" -o "run" -o "fr v" -o c | FileCheck %s | ||
|
||
#include <bitset> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we not running the data-formatter tests on Windows at all? There's definitely tests for all of these elsewhere in the API test-suite
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you have any specific tests? Ideally ones that test optional and shared_ptr. I can look at them later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The tests in lldb/test/API/functionalities/data-formatter/data-formatter-stl
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Most of these tests are unsupported due to being in the libc++/libstdc++ categories which aren't supported on Windows ("Don't know how to build with libc++ on windows"). The only tests that run are libstdcpp/unique_ptr/invalid
and libcxx-simulators/*
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm right that makes sense. Should we then have a Windows data-formatter subdirectory in lldb/test/API/functionalities/data-formatter/data-formatter-stl
? I think we should ideally have two test configurations:
- Tests that ensure we at least don't crash when using the MSVC STL. E.g., at least for
std::optional
andstd::shared_ptr
. This would test your current PR - Tests for libc++ on Windows (which AFAIU, isn't the recommended configuration on Windows but is definitely used in the wild)
Not sure how easy it is to set up (2). That shouldn't block this PR, but would be nice to get around to it.
But (1) should be doable. Though not sure how equipped the API test infrastructure is to compile against MSVC STL. Worst case we could go for Shell tests like you did here
CC @DavidSpickett @labath @omjavaid for opinions on Windows testing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm I wonder if that was leftover documentation from when the data-formatters were all written in python? But yea, now they're all in the cplusplus
category IIUC
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup looks like it is. At least when browsing back to:
commit 78453eed1219b83dff87d34a4bbbe48cc65eda70 (HEAD)
Author: Enrico Granata <egranata@apple.com>
Date: Thu May 3 01:08:44 2012 +0000
Adding a new 'type category disable *' feature that disables all categories - This is intended as a quick kill switch for data formatters for cases where the user wants as little extra processing as possible to be done on their target, or to override major data formatters bug, should they occur
llvm-svn: 156044
And searching the repo for gnu-libstdc++
, you'll see that the libcxx and lisbtdcpp formatters were written in python and were added to separate categories. Not 100% why they got combined back into the same category. Presumably the idea was that you never want to have both categories enabled anyway, so if a cplusplus
category can just turn on/off the STL formatters for you wholesale, that'd be more intuitive.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I presume all API tests on Windows are compiling against MSVC STL when compiled on Windows (it has nothing else to use). If you're wondering whether there's a good way to detect that is the case, yeah, that might be tricky.
For number 2, I'm not into the idea of changing the existing bot to build everything against libcxx, but if we can enable the runtime and then libcxx specific tests will be run as well, that's fine. Windows is supported and tested for libcxx as long as clang/clang-cl is the compiler, which we use already on the bot.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the additional context David. I'm not super familiar with the Windows test bot setup
Not sure what the best testing strategy here is then. Since the STL formatters in LLDB currently don't support MSVC STL, and we just want to make sure they don't crash, maybe we could even omit tests for this PR until we get proper support for it? Though I don't mind the smoke test added here either tbh, maybe with a FIXME? Just diverges a bit from the rest of our formatter testing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this smoke test ensures they don't crash horribly, which I think it does, we should accept it. If we have issue(s) talking about MSVC formatter support link to them, or if we don't have an overall one, open one and link to that.
If this test fails way too often and it's holding up formatter development elsewhere, then we can revisit it of course.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like a fine stop-gap for now to avoid crashing
Just left some clarification questions
FYI @charles-zablit |
Yes, exactly. The formatted output for these types is still incomplete (often, types are formatted without any children). |
15c47a0
to
355cdcd
Compare
This is still leftover from the days when the libc++ and libstdc++ formatters were both written in python and in separate categories. Since then we group libstdc++ and libc++ formatters into the same cateogry. This patch removes references to the obsolete `gnu-libstdc++` category from the docs (and a test). See [this thread](llvm#140761 (comment)) for more context
#141610) This is still leftover from the days when the libc++ and libstdc++ formatters were both written in python and in separate categories. Since then we group libstdc++ and libc++ formatters into the same cateogry. This patch removes references to the obsolete `gnu-libstdc++` category from the docs (and a test). See [this thread](#140761 (comment)) for more context
…c++ category (#141610) This is still leftover from the days when the libc++ and libstdc++ formatters were both written in python and in separate categories. Since then we group libstdc++ and libc++ formatters into the same cateogry. This patch removes references to the obsolete `gnu-libstdc++` category from the docs (and a test). See [this thread](llvm/llvm-project#140761 (comment)) for more context
@@ -0,0 +1,57 @@ | |||
// clang-format off | |||
|
|||
// REQUIRES: target-windows |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a comment here to explain why this test exists? I.e., that this just ensures that debugging with MSVC STL doesn't crash, etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM (just left small test comments)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Request changes just so the remaining comment doesn't get forgotten, the rest Michael has approved and if he's cool with it so am I.
355cdcd
to
af77293
Compare
Think this is good to go after rebase |
From llvm/llvm-project#140761. `MsvcBuilder` passed `/std:<value>` (if specified) after `--`, so the compiler would interpret this as a file. This moves the argument before the `--`.
af77293
to
9ee1b61
Compare
@Nerixyz do you need us to merge this for you? |
Yeah, that would be great! |
I put a summary and some ideas about MSVC STL support in #24834 (comment). |
llvm#141610) This is still leftover from the days when the libc++ and libstdc++ formatters were both written in python and in separate categories. Since then we group libstdc++ and libc++ formatters into the same cateogry. This patch removes references to the obsolete `gnu-libstdc++` category from the docs (and a test). See [this thread](llvm#140761 (comment)) for more context
From llvm#140761. `MsvcBuilder` passed `/std:<value>` (if specified) after `--`, so the compiler would interpret this as a file. This moves the argument before the `--`.
When inspecting/printing types from MSVC's STL, LLDB would crash because it assumes these types were from libstdc++. Specifically,
std::shared_ptr
andstd::optional
would crash because of a null pointer dereference. I added a minimal test that tests the types with C++ helpers for libstdc++ (only tests for crashes).frame variable
crashes when printing a shared_ptr when program uses MSVC STL #120310This still has one unresolved discussion: What about MS STL types? This is #24834, but there was a bit of discussion in #120310 as well. The main issue is that MSVC's STL uses the same type names as libstdc++ (i.e. neither uses an inline namespace like libc++ for some types).