[Lldb-commits] [lldb] 3bc765d - [lldb][test] Add test for ASTImporter's name conflict resolution (#112566)
via lldb-commits
lldb-commits at lists.llvm.org
Fri Oct 18 06:19:46 PDT 2024
Author: Michael Buch
Date: 2024-10-18T14:19:42+01:00
New Revision: 3bc765dbbf9bf0eceab1c9679b9f761b3f760d56
URL: https://github.com/llvm/llvm-project/commit/3bc765dbbf9bf0eceab1c9679b9f761b3f760d56
DIFF: https://github.com/llvm/llvm-project/commit/3bc765dbbf9bf0eceab1c9679b9f761b3f760d56.diff
LOG: [lldb][test] Add test for ASTImporter's name conflict resolution (#112566)
This is a reduced test case from a crash we've observed in the past. The
assertion that this test triggers is:
```
Assertion failed: ((Pos == ImportedDecls.end() || Pos->second == To) && "Try to import an already imported Decl"), function MapImported, file ASTImporter.cpp, line 10494.
```
In a non-asserts build we crash later on in the ASTImporter. The root
cause is, as the assertion above points out, that we erroneously replace
an existing `From->To` decl mapping with a `To` decl that isn't
complete. Then we try to complete it but it has no definition and we
dereference a nullptr.
The reason this happens is basically what's been described in
https://reviews.llvm.org/D67803?id=220956#1676588
The dylib contains a definition of `Service` which is different to the
one in the main executable. When we start dumping the children of the
variable we're printing, we start completing it's members,
`ASTImport`ing fields in the process. When the ASTImporter realizes
there's been a name conflict (i.e., a structural mismatch on the
`Service` type) it would usually report back an error. However, LLDB
uses `ODRHandlingType::Liberal`, which means we create a new decl for
the ODR'd type instead of re-using the previously mapped decl.
Eventually this leads us to crash.
Ideally we'd be using `ODRHandlingType::Conservative` and warn/error,
though LLDB relies on this in some cases (particularly for
distinguishing template specializations, though maybe there's better a
way to deal with those).
We should really warn the user when this happens and not crash. To avoid
the crash we'd need to know to not create a decl for the ODR violation,
and instead re-use the definition we've previously seen. Though I'm not
yet sure that's viable for all of LLDB's use-cases (where ODR violations
might legimiately occur in a program, e.g., with opaque definitions,
etc.).
Added:
lldb/test/API/lang/cpp/odr-handling-with-dylib/Makefile
lldb/test/API/lang/cpp/odr-handling-with-dylib/TestOdrHandlingWithDylib.py
lldb/test/API/lang/cpp/odr-handling-with-dylib/main.cpp
lldb/test/API/lang/cpp/odr-handling-with-dylib/plugin.cpp
lldb/test/API/lang/cpp/odr-handling-with-dylib/plugin.h
lldb/test/API/lang/cpp/odr-handling-with-dylib/service.cpp
lldb/test/API/lang/cpp/odr-handling-with-dylib/service.h
Modified:
Removed:
################################################################################
diff --git a/lldb/test/API/lang/cpp/odr-handling-with-dylib/Makefile b/lldb/test/API/lang/cpp/odr-handling-with-dylib/Makefile
new file mode 100644
index 00000000000000..91eadaa37282ee
--- /dev/null
+++ b/lldb/test/API/lang/cpp/odr-handling-with-dylib/Makefile
@@ -0,0 +1,6 @@
+CXX_SOURCES := main.cpp service.cpp
+
+DYLIB_CXX_SOURCES := plugin.cpp
+DYLIB_NAME := plugin
+
+include Makefile.rules
diff --git a/lldb/test/API/lang/cpp/odr-handling-with-dylib/TestOdrHandlingWithDylib.py b/lldb/test/API/lang/cpp/odr-handling-with-dylib/TestOdrHandlingWithDylib.py
new file mode 100644
index 00000000000000..f67d933f6ae51a
--- /dev/null
+++ b/lldb/test/API/lang/cpp/odr-handling-with-dylib/TestOdrHandlingWithDylib.py
@@ -0,0 +1,29 @@
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class OdrHandlingWithDylibTestCase(TestBase):
+ @skipIf(
+ bugnumber="https://github.com/llvm/llvm-project/issues/50375, rdar://135551810"
+ )
+ def test(self):
+ """
+ Tests that the expression evaluator is able to deal with types
+ whose definitions conflict across multiple LLDB modules (in this
+ case the definition for 'class Service' in the main executable
+ has an additional field compared to the definition found in the
+ dylib). This causes the ASTImporter to detect a name conflict
+ while importing 'Service'. With LLDB's liberal ODRHandlingType
+ the ASTImporter happily creates a conflicting AST node for
+ 'Service' in the scratch ASTContext, leading to a crash down
+ the line.
+ """
+ self.build()
+
+ lldbutil.run_to_source_breakpoint(
+ self, "plugin_entry", lldb.SBFileSpec("plugin.cpp")
+ )
+
+ self.expect_expr("*gProxyThis")
diff --git a/lldb/test/API/lang/cpp/odr-handling-with-dylib/main.cpp b/lldb/test/API/lang/cpp/odr-handling-with-dylib/main.cpp
new file mode 100644
index 00000000000000..f3372e0fbe7018
--- /dev/null
+++ b/lldb/test/API/lang/cpp/odr-handling-with-dylib/main.cpp
@@ -0,0 +1,11 @@
+#include "plugin.h"
+
+#define HIDE_FROM_PLUGIN 1
+#include "service.h"
+
+int main() {
+ exported();
+ plugin_init();
+ plugin_entry();
+ return 0;
+}
diff --git a/lldb/test/API/lang/cpp/odr-handling-with-dylib/plugin.cpp b/lldb/test/API/lang/cpp/odr-handling-with-dylib/plugin.cpp
new file mode 100644
index 00000000000000..190388000a3c8f
--- /dev/null
+++ b/lldb/test/API/lang/cpp/odr-handling-with-dylib/plugin.cpp
@@ -0,0 +1,14 @@
+#include "plugin.h"
+#include "service.h"
+
+struct Proxy : public Service {
+ State *proxyState;
+};
+
+Proxy *gProxyThis = 0;
+
+extern "C" {
+void plugin_init() { gProxyThis = new Proxy; }
+
+void plugin_entry() {}
+}
diff --git a/lldb/test/API/lang/cpp/odr-handling-with-dylib/plugin.h b/lldb/test/API/lang/cpp/odr-handling-with-dylib/plugin.h
new file mode 100644
index 00000000000000..9d4ba5df5a83a3
--- /dev/null
+++ b/lldb/test/API/lang/cpp/odr-handling-with-dylib/plugin.h
@@ -0,0 +1,9 @@
+#ifndef PLUGIN_H_IN
+#define PLUGIN_H_IN
+
+extern "C" {
+void plugin_entry(void);
+void plugin_init(void);
+}
+
+#endif // PLUGIN_H_IN
diff --git a/lldb/test/API/lang/cpp/odr-handling-with-dylib/service.cpp b/lldb/test/API/lang/cpp/odr-handling-with-dylib/service.cpp
new file mode 100644
index 00000000000000..6302a45483495e
--- /dev/null
+++ b/lldb/test/API/lang/cpp/odr-handling-with-dylib/service.cpp
@@ -0,0 +1,15 @@
+#define HIDE_FROM_PLUGIN 1
+#include "service.h"
+
+struct ServiceAux {
+ Service *Owner;
+};
+
+struct Service::State {};
+
+void exported() {
+ // Make sure debug-info for definition of Service is
+ // emitted in this CU.
+ Service service;
+ service.start(0);
+}
diff --git a/lldb/test/API/lang/cpp/odr-handling-with-dylib/service.h b/lldb/test/API/lang/cpp/odr-handling-with-dylib/service.h
new file mode 100644
index 00000000000000..37c6b9aeb2d9b8
--- /dev/null
+++ b/lldb/test/API/lang/cpp/odr-handling-with-dylib/service.h
@@ -0,0 +1,20 @@
+#ifndef SERVICE_H_IN
+#define SERVICE_H_IN
+
+struct ServiceAux;
+
+struct Service {
+ struct State;
+ bool start(State *) { return true; }
+
+#ifdef HIDE_FROM_PLUGIN
+ int __resv1;
+#endif // !HIDE_FROM_PLUGIN
+
+ Service *__owner;
+ ServiceAux *aux;
+};
+
+void exported();
+
+#endif
More information about the lldb-commits
mailing list