[lldb-dev] [Bug 44331] New: LLDB crashes in expression evaluation (in codegen)

2019-12-18 Thread via lldb-dev
https://bugs.llvm.org/show_bug.cgi?id=44331

Bug ID: 44331
   Summary: LLDB crashes in expression evaluation (in codegen)
   Product: lldb
   Version: unspecified
  Hardware: PC
OS: Linux
Status: NEW
  Severity: release blocker
  Priority: P
 Component: All Bugs
  Assignee: lldb-dev@lists.llvm.org
  Reporter: ja...@google.com
CC: jdevliegh...@apple.com, llvm-b...@lists.llvm.org

LLDB crashes on expression evaluation. The program, the debug session and the
full stack trace are at the end of the bug report.

The crash reproduces on the current tip of tree
(541daa5e6b9bc38986e09612a9bd6f0f148fdfcf), a bisect points to one of the 10
revision following the revision below (the revision broke the LLDB build, the
build was fixed by 15695cd69c301a250b76ea5d36dcab4d3af055be, that revision is
the first one that crashes).

commit 457226e02a6e8533eaaa864a3fd7c8eeccd2bf58
Author: Richard Smith 
Date:   Mon Sep 23 03:48:44 2019 +

For P0784R7: add support for constexpr destructors, and call them as
appropriate during constant evaluation.

Note that the evaluator is sometimes invoked on incomplete expressions.
In such cases, if an object is constructed but we never reach the point
where it would be destroyed (and it has non-trivial destruction), we
treat the expression as having an unmodeled side-effect.

llvm-svn: 372538


--- Program ---


struct E {
  int x;
};

struct D {
  D(E &e) {}
  D() {}
};

struct F {
  int fi;
  E e;
};

struct B {
  D d;
};

struct C : B {
  C(F *pf) : pf(pf) {}

  int m() {
return 2;  // Break here, eval pf->fi
  }

  F* pf;
  int ci;
};

int main() {
  F f;
  C c(&f);
  c.m();
  return 0;
}

Compiled with clang++ -O0 -g a.cc

--- Debug session ---

(lldb) file a.out
Current executable set to 'a.out' (x86_64).
(lldb) b a.cc:23
Breakpoint 1: where = a.out`C::m() + 8 at a.cc:23:5, address = 0x...
(lldb) r
...
(lldb) p pf->fi

lldb: /llvm-project/llvm/../clang/include/clang/AST/DeclCXX.h:433:
clang::CXXRecordDecl::DefinitionData& clang::CXXRecordDecl::data() const:
Assertion `DD && "queried property of class with no definition"' failed.

--- Stack trace ---

(/lib/x86_64-linux-gnu/libc.so.6+0x2f542)
clang::CXXRecordDecl::data() const
/llvm/../clang/include/clang/AST/DeclCXX.h:434:13
clang::CXXRecordDecl::bases_begin() const
/llvm/../clang/include/clang/AST/DeclCXX.h:595:73
clang::CXXRecordDecl::bases_end() const
/llvm/../clang/include/clang/AST/DeclCXX.h:598:23
clang::CXXRecordDecl::bases() const
/llvm-project/clang/include/clang/AST/DeclCXX.h:591:12
isSafeToConvert(clang::RecordDecl const*, clang::CodeGen::CodeGenTypes&,
llvm::SmallPtrSet&)
/llvm-project/clang/lib/CodeGen/CodeGenTypes.cpp:137:37
isSafeToConvert(clang::QualType, clang::CodeGen::CodeGenTypes&,
llvm::SmallPtrSet&)
/llvm-project/clang/lib/CodeGen/CodeGenTypes.cpp:165:62
isSafeToConvert(clang::RecordDecl const*, clang::CodeGen::CodeGenTypes&,
llvm::SmallPtrSet&)
/llvm-project/clang/lib/CodeGen/CodeGenTypes.cpp:146:9
isSafeToConvert(clang::RecordDecl const*, clang::CodeGen::CodeGenTypes&)
/llvm-project/clang/lib/CodeGen/CodeGenTypes.cpp:186:25
clang::CodeGen::CodeGenTypes::ConvertRecordDeclType(clang::RecordDecl const*)
(.localalias.0) /llvm-project/clang/lib/CodeGen/CodeGenTypes.cpp:733:7
clang::CodeGen::CodeGenTypes::ConvertType(clang::QualType) (.localalias.1)
/llvm-project/clang/lib/CodeGen/CodeGenTypes.cpp:388:47
clang::CodeGen::CodeGenTypes::ConvertTypeForMem(clang::QualType)
/llvm-project/clang/lib/CodeGen/CodeGenTypes.cpp:87:30
clang::CodeGen::CodeGenTypes::ConvertType(clang::QualType) (.localalias.1)
/llvm-project/clang/lib/CodeGen/CodeGenTypes.cpp:560:48
clang::CodeGen::CodeGenTypes::ConvertTypeForMem(clang::QualType)
/llvm-project/clang/lib/CodeGen/CodeGenTypes.cpp:87:30
(anonymous namespace)::CGRecordLowering::getStorageType(clang::FieldDecl
const*) /llvm-project/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp:135:47
(anonymous namespace)::CGRecordLowering::accumulateFields()
/llvm-project/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp:357:25
(anonymous namespace)::CGRecordLowering::lower(bool)
/llvm-project/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp:268:7
clang::CodeGen::CodeGenTypes::ComputeRecordLayout(clang::RecordDecl const*,
llvm::StructType*)
/llvm-project/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp:739:21
clang::CodeGen::CodeGenTypes::ConvertRecordDeclType(clang::RecordDecl const*)
(.localalias.0) /llvm-project/clang/lib/CodeGen/CodeGenTypes.cpp:752:47
clang::CodeGen::CodeGenTypes::ConvertType(clang::QualType) (.localalias.1)
/llvm-project/clang/lib/CodeGen/CodeGenTypes.cpp:388:47
clang::CodeGen::CodeGenTypes::ConvertTypeForMem(clang::QualType)
/llvm-project/clang/lib/CodeGen/CodeGenTypes.cpp:87:30
clang::CodeGen::CodeGenTypes::ConvertType(clang::QualType) (.localalias.1)
/llvm-project/clang/lib/CodeGen/CodeGenTypes.cpp:560:48
(anonymous namespace)::X86_64AB

[lldb-dev] Reporting the results of "thread select"

2019-12-18 Thread Jim Ingham via lldb-dev
We were seeing an ASAN failure in a simple Lit test somebody here was writing.  
The failure was that the "thread backtrace" command was accessing freed memory 
dereferencing a VariableSP it got from the VariableList of a Block.  Turns out 
that the VariableList class has no locking, and backtrace was getting a 
variable from the block's list while another thread was in the process of 
filling in the VariableList of that block from DWARF.

So that bug is easy, there's nothing saying that you can't ask a question of a 
block on two different threads, nor any way to gate setting up the VariableList 
before another thread accesses it that I can see.  It seems like the 
VariableList should lock when it adds or retrieves elements.

But I was curious how we managed to be filling and accessing the VariableList 
simultaneously.  The answer struck me as odd:

The command before "thread backtrace" in the Lit test was "thread select 1".  
It doesn't make sense that this would cause any access problems, since "thread 
select 1" just selects a thread, and prints the Status message from the newly 
selected thread.  That latter bit will print the arguments, so it will access 
the VariableList.  But it should have been done accessing that by the time the 
"thread backtrace" command was run.  Or so it seems...

What CommandObjectThreadSelect in fact does is call "SetSelectedThreadByIndex" 
with "notify" set to "true" - which raises an eBroadcastBitThreadSelected 
event.  Then the command returns success but no result.  Then the Debugger's 
event handler gets the eBroadcastBitThreadSelected in its DefaultEventHandler, 
which calls Thread::GetStatus, putting the results into the debugger's Async 
output stream.  And that's how what looks like the output from "thread select" 
actually gets printed.

This was causing the race because the event handling is not synchronized with 
command handling.  I'm not sure whether it would be a good idea to handle 
commands by having the Debugger post a "got a new line" event to itself, and 
have the handling of that event trigger the command execution.  But that's not 
how it works today.  IOHandlerEditLine directly dispatches a command when it 
gets a complete line.  So the output from the "thread select" status printing 
could happen before, during or after the next command is processed.

That's actually a little problematic if you are writing Lit type tests that 
scrape lldb output because the thread selection message isn't guaranteed to 
happen before the next command is fetched.  So you could occasionally get the 
output from the command after a "thread select" mixed in with the thread status 
message.

That's also not how we handle the "frame select" command which should be 
equivalent.  In that case, we still send an event (we always have to do that so 
UI's can keep in sync with the command line) but the Debugger doesn't listen 
for that event, instead we put the status result directly into the command 
result object.

I tried to figure out why it was done this way but there anything in the scm 
history that shed any light on this.

This seems like a weird way to do things, and leaves a little land mine for 
people because something that looks very much like the output of the "thread 
select" command is in fact NOT it's output.  So I'd like to make "thread 
select" work like "frame select".  But for that to work, I would have to remove 
the code in Debugger::HandleThreadEvent that handles the 
eBroadcastBitThreadSelected event.  If something else was depending on this to 
print status, that would get broken.  Note, the SB API's don't send events when 
they change the Stack or the Frame.  These are supposed to be the API's for 
driving lldb, and having to say "Thread.Select" then wait for an event saying 
the thread was selected seems like an obnoxious API...  So we don't need to 
worry about that.  And the testsuite was clean.

I was just wondering if anybody sees some reason I'm missing for why it would 
be done this way?

If not, I'll just change it, and we'll see if anything I don't know about 
breaks...

Jim

___
lldb-dev mailing list
lldb-dev@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev