Skip to content

Commit 423c2e9

Browse files
committed
[lldb] Fix crash in CxxModuleHandler when std module is empty
We currently don't handle the error in the Expected we get when searching for an equal local DeclContext. Usually this can't happen as this would require that we have a STL container and we can find libc++'s std module, but when we load the module in the expression parser the module doesn't even contain the 'std' namespace. The only way I see to test this is by having a fake 'std' module that requires a special define to actually provide its contents, while it will just be empty (that is, it doesn't even contain the 'std' namespace) without that define. LLDB currently doesn't know about that define in the expression parser, so it will load the wrong 'empty' module which should trigger this error. Also removed the 'auto' for that variable as the function name doesn't make it obvious that this is an expected and not just a optional/ptr (which is how this slipped in from the start). llvm-svn: 374525
1 parent bb8d540 commit 423c2e9

File tree

7 files changed

+88
-4
lines changed

7 files changed

+88
-4
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# We don't have any standard include directories, so we can't
2+
# parse the test_common.h header we usually inject as it includes
3+
# system headers.
4+
NO_TEST_COMMON_H := 1
5+
6+
CXXFLAGS_EXTRAS = -I $(SRCDIR)/root/usr/include/c++/v1/ -I $(SRCDIR)/root/usr/include/ -nostdinc -nostdinc++ -DENABLE_STD_CONTENT=1
7+
CXX_SOURCES := main.cpp
8+
9+
include Makefile.rules
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
"""
2+
Test that LLDB doesn't crash if the std module we load is empty.
3+
"""
4+
5+
from lldbsuite.test.decorators import *
6+
from lldbsuite.test.lldbtest import *
7+
from lldbsuite.test import lldbutil
8+
import os
9+
10+
class ImportStdModule(TestBase):
11+
12+
mydir = TestBase.compute_mydir(__file__)
13+
14+
@skipIf(compiler=no_match("clang"))
15+
def test(self):
16+
self.build()
17+
18+
sysroot = os.path.join(os.getcwd(), "root")
19+
20+
# Set the sysroot.
21+
self.runCmd("platform select --sysroot '" + sysroot + "' host", CURRENT_EXECUTABLE_SET)
22+
23+
lldbutil.run_to_source_breakpoint(self,
24+
"// Set break point at this line.", lldb.SBFileSpec("main.cpp"))
25+
26+
self.runCmd("settings set target.import-std-module true")
27+
self.runCmd("log enable lldb expr")
28+
29+
# Use the typedef that is only defined in our 'empty' module. If this fails, then LLDB
30+
# somehow figured out the correct define for the header and compiled the right
31+
# standard module that actually contains the std::vector template.
32+
self.expect("expr MissingContent var = 3; var", substrs=['$0 = 3'])
33+
# Try to access our mock std::vector. This should fail but not crash LLDB as the
34+
# std::vector template should be missing from the std module.
35+
self.expect("expr (size_t)v.size()", substrs=["Couldn't lookup symbols"], error=True)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#include <algorithm>
2+
3+
int main(int argc, char **argv) {
4+
// Makes sure we have the mock libc headers in the debug information.
5+
libc_struct s;
6+
std::vector<int> v;
7+
return 0; // Set break point at this line.
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// This is only defined when building, but LLDB is missing this flag when loading the standard
2+
// library module so the actual contents of the module are missing.
3+
#ifdef ENABLE_STD_CONTENT
4+
5+
#include "libc_header.h"
6+
7+
namespace std {
8+
inline namespace __1 {
9+
// Pretend to be a std::vector template we need to instantiate
10+
// in LLDB.
11+
template<typename T>
12+
struct vector { T i; int size() { return 2; } };
13+
}
14+
}
15+
#else
16+
// Unused typedef we can use to check that we actually loaded
17+
// an empty module. Will be missing if LLDB somehow can get the
18+
// ENABLE_STD_CONTENT define right and break this test silently
19+
// (as with the define the module isn't empty anymore and this
20+
// test always succeeds).
21+
typedef int MissingContent;
22+
#endif // ENABLE_STD_CONTENT
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module std {
2+
module "algorithm" { header "algorithm" export * }
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
struct libc_struct {};

lldb/source/Symbol/CxxModuleHandler.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,8 @@ T *createDecl(ASTImporter &importer, Decl *from_d, Args &&... args) {
175175
}
176176

177177
llvm::Optional<Decl *> CxxModuleHandler::tryInstantiateStdTemplate(Decl *d) {
178+
Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS);
179+
178180
// If we don't have a template to instiantiate, then there is nothing to do.
179181
auto td = dyn_cast<ClassTemplateSpecializationDecl>(d);
180182
if (!td)
@@ -196,9 +198,15 @@ llvm::Optional<Decl *> CxxModuleHandler::tryInstantiateStdTemplate(Decl *d) {
196198

197199
// Find the local DeclContext that corresponds to the DeclContext of our
198200
// decl we want to import.
199-
auto to_context = getEqualLocalDeclContext(*m_sema, td->getDeclContext());
200-
if (!to_context)
201+
llvm::Expected<DeclContext *> to_context =
202+
getEqualLocalDeclContext(*m_sema, td->getDeclContext());
203+
if (!to_context) {
204+
LLDB_LOG_ERROR(log, to_context.takeError(),
205+
"Got error while searching equal local DeclContext for decl "
206+
"'{1}':\n{0}",
207+
td->getName());
201208
return {};
209+
}
202210

203211
// Look up the template in our local context.
204212
std::unique_ptr<LookupResult> lookup =
@@ -215,8 +223,6 @@ llvm::Optional<Decl *> CxxModuleHandler::tryInstantiateStdTemplate(Decl *d) {
215223
// Import the foreign template arguments.
216224
llvm::SmallVector<TemplateArgument, 4> imported_args;
217225

218-
Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS);
219-
220226
// If this logic is changed, also update templateArgsAreSupported.
221227
for (const TemplateArgument &arg : foreign_args.asArray()) {
222228
switch (arg.getKind()) {

0 commit comments

Comments
 (0)