kparzysz created this revision.
kparzysz added a reviewer: rsmith.
Herald added subscribers: pengfei, krytarowski, arichardson, emaste.
Herald added a project: All.
kparzysz requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Compiling the following testcase causes a crash:

  struct A {
    ~A() {}
  };
  
  int fred(char *p, int *q) {
    if (p != 0) {
      goto bail;
    }
    thread_local A a;
    *q = 0;
  bail:
    return 0;
  }

The crash is caused by CFGBuilder thinking that the variable `a` is local (in 
terms of storage scope), and trying to perform some sort of a lifetime analysis 
on it.  The problem is that the program would not have been legal if `a` was 
actually local, and the problem would have been diagnosed earlier, preventing 
CFGBuilder from running in the first place.

This fix recognizes locally declared C++11 `thread_local` variables as `static`.

  Assertion failed: (F != const_iterator() && "L iterator is not reachable from 
F iterator."), function distance, file 
/w/src/llvm.org/clang/lib/Analysis/CFG.cpp, line 334.
  PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ 
and include the crash backtrace, preprocessed source, and associated run script.
  Stack dump:
  0.      Program arguments: /w/c/org/bin/clang++ -c dd.cc
  1.      <eof> parser at end of file
  2.      dd.cc:5:27: parsing function body 'fred'
   #0 0x000000000561c8aa llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) 
(/w/c/org/bin/clang+++0x561c8aa)
   #1 0x000000000561a788 llvm::sys::RunSignalHandlers() 
(/w/c/org/bin/clang+++0x561a788)
   #2 0x000000000557edd4 (anonymous 
namespace)::CrashRecoveryContextImpl::HandleCrash(int, unsigned long) 
CrashRecoveryContext.cpp:0:0
   #3 0x000000000557efa0 CrashRecoverySignalHandler(int) 
CrashRecoveryContext.cpp:0:0
   #4 0x00000008091f35b0 handle_signal /usr/src/lib/libthr/thread/thr_sig.c:0:3
   #5 0x00000008091f2b6f thr_sighandler 
/usr/src/lib/libthr/thread/thr_sig.c:247:1
   #6 0x00007ffffffff2d3 ([vdso]+0x2d3)
   #7 0x000000080950f14a thr_kill 
/usr/obj/usr/src/amd64.amd64/lib/libc/thr_kill.S:4:0
   #8 0x0000000809487c34 _raise /usr/src/lib/libc/gen/raise.c:0:10
   #9 0x0000000809538e99 abort /usr/src/lib/libc/stdlib/abort.c:73:17
  #10 0x000000080946a9d1 (/lib/libc.so.7+0x929d1)
  #11 0x0000000007f2fa66 (anonymous 
namespace)::CFGBuilder::addAutomaticObjHandling((anonymous 
namespace)::LocalScope::const_iterator, (anonymous 
namespace)::LocalScope::const_iterator, clang::Stmt*) CFG.cpp:0:0
  #12 0x0000000007f2adc7 (anonymous 
namespace)::CFGBuilder::VisitGotoStmt(clang::GotoStmt*) CFG.cpp:0:0
  #13 0x0000000007f2866f (anonymous 
namespace)::CFGBuilder::VisitCompoundStmt(clang::CompoundStmt*, bool) 
CFG.cpp:0:0
  #14 0x0000000007f2b612 (anonymous 
namespace)::CFGBuilder::VisitIfStmt(clang::IfStmt*) CFG.cpp:0:0
  #15 0x0000000007f2866f (anonymous 
namespace)::CFGBuilder::VisitCompoundStmt(clang::CompoundStmt*, bool) 
CFG.cpp:0:0
  #16 0x0000000007f211e4 clang::CFG::buildCFG(clang::Decl const*, clang::Stmt*, 
clang::ASTContext*, clang::CFG::BuildOptions const&) 
(/w/c/org/bin/clang+++0x7f211e4)
  #17 0x0000000007ef12ab clang::AnalysisDeclContext::getCFG() 
(/w/c/org/bin/clang+++0x7ef12ab)
  #18 0x00000000076bb654 
clang::sema::AnalysisBasedWarnings::IssueWarnings(clang::sema::AnalysisBasedWarnings::Policy,
 clang::sema::FunctionScopeInfo*, clang::Decl const*, clang::QualType) 
(/w/c/org/bin/clang+++0x76bb654)
  #19 0x00000000076b05f7 
clang::Sema::PopFunctionScopeInfo(clang::sema::AnalysisBasedWarnings::Policy 
const*, clang::Decl const*, clang::QualType) (/w/c/org/bin/clang+++0x76b05f7)
  #20 0x0000000007817aa2 clang::Sema::ActOnFinishFunctionBody(clang::Decl*, 
clang::Stmt*, bool) (/w/c/org/bin/clang+++0x7817aa2)
  #21 0x00000000075bb3f3 
clang::Parser::ParseFunctionStatementBody(clang::Decl*, 
clang::Parser::ParseScope&) (/w/c/org/bin/clang+++0x75bb3f3)
  #22 0x0000000007590e34 
clang::Parser::ParseFunctionDefinition(clang::ParsingDeclarator&, 
clang::Parser::ParsedTemplateInfo const&, clang::Parser::LateParsedAttrList*) 
(/w/c/org/bin/clang+++0x7590e34)
  #23 0x0000000007615d7d clang::Parser::ParseDeclGroup(clang::ParsingDeclSpec&, 
clang::DeclaratorContext, clang::SourceLocation*, clang::Parser::ForRangeInit*) 
(/w/c/org/bin/clang+++0x7615d7d)
  #24 0x000000000758f681 
clang::Parser::ParseDeclOrFunctionDefInternal(clang::ParsedAttributes&, 
clang::ParsingDeclSpec&, clang::AccessSpecifier) 
(/w/c/org/bin/clang+++0x758f681)
  #25 0x000000000758f0a2 
clang::Parser::ParseDeclarationOrFunctionDefinition(clang::ParsedAttributes&, 
clang::ParsingDeclSpec*, clang::AccessSpecifier) 
(/w/c/org/bin/clang+++0x758f0a2)
  #26 0x000000000758de8b 
clang::Parser::ParseExternalDeclaration(clang::ParsedAttributes&, 
clang::ParsingDeclSpec*) (/w/c/org/bin/clang+++0x758de8b)
  #27 0x000000000758bdcd 
clang::Parser::ParseTopLevelDecl(clang::OpaquePtr<clang::DeclGroupRef>&, 
clang::Sema::ModuleImportState&) (/w/c/org/bin/clang+++0x758bdcd)
  #28 0x0000000007585f7e clang::ParseAST(clang::Sema&, bool, bool) 
(/w/c/org/bin/clang+++0x7585f7e)
  #29 0x0000000006082523 clang::FrontendAction::Execute() 
(/w/c/org/bin/clang+++0x6082523)
  #30 0x000000000600aeef 
clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) 
(/w/c/org/bin/clang+++0x600aeef)
  #31 0x000000000614c4b5 
clang::ExecuteCompilerInvocation(clang::CompilerInstance*) 
(/w/c/org/bin/clang+++0x614c4b5)
  #32 0x0000000003244afc cc1_main(llvm::ArrayRef<char const*>, char const*, 
void*) (/w/c/org/bin/clang+++0x3244afc)
  #33 0x00000000032421ea ExecuteCC1Tool(llvm::SmallVectorImpl<char const*>&) 
driver.cpp:0:0
  #34 0x0000000005eb48e7 void llvm::function_ref<void 
()>::callback_fn<clang::driver::CC1Command::Execute(llvm::ArrayRef<llvm::Optional<llvm::StringRef>
 >, std::__1::basic_string<char, std::__1::char_traits<char>, 
std::__1::allocator<char> >*, bool*) const::$_1>(long) Job.cpp:0:0
  #35 0x000000000557ecf0 
llvm::CrashRecoveryContext::RunSafely(llvm::function_ref<void ()>) 
(/w/c/org/bin/clang+++0x557ecf0)
  #36 0x0000000005eb43f2 
clang::driver::CC1Command::Execute(llvm::ArrayRef<llvm::Optional<llvm::StringRef>
 >, std::__1::basic_string<char, std::__1::char_traits<char>, 
std::__1::allocator<char> >*, bool*) const (/w/c/org/bin/clang+++0x5eb43f2)
  #37 0x0000000005e7dba4 
clang::driver::Compilation::ExecuteCommand(clang::driver::Command const&, 
clang::driver::Command const*&) const (/w/c/org/bin/clang+++0x5e7dba4)
  #38 0x0000000005e7dfd9 
clang::driver::Compilation::ExecuteJobs(clang::driver::JobList const&, 
llvm::SmallVectorImpl<std::__1::pair<int, clang::driver::Command const*> >&) 
const (/w/c/org/bin/clang+++0x5e7dfd9)
  #39 0x0000000005e953ac 
clang::driver::Driver::ExecuteCompilation(clang::driver::Compilation&, 
llvm::SmallVectorImpl<std::__1::pair<int, clang::driver::Command const*> >&) 
(/w/c/org/bin/clang+++0x5e953ac)
  clang-15: error: clang frontend command failed with exit code 134 (use -v to 
see invocation)
  clang version 15.0.0 (https://github.com/llvm/llvm-project.git 
0b2a2620b883cef1dac63f3ea4c839aba0e4d80e)
  Target: x86_64-unknown-freebsd13.0
  Thread model: posix
  InstalledDir: /w/c/org/bin
  clang-15: note: diagnostic msg:
  ********************
  
  PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:
  Preprocessed source(s) and associated run script(s) are located at:
  clang-15: note: diagnostic msg: /tmp/dd-48e7c6.cpp
  clang-15: note: diagnostic msg: /tmp/dd-48e7c6.sh
  clang-15: note: diagnostic msg:
  
  ********************


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D125177

Files:
  clang/lib/Analysis/CFG.cpp
  clang/test/Analysis/cfg.cpp


Index: clang/test/Analysis/cfg.cpp
===================================================================
--- clang/test/Analysis/cfg.cpp
+++ clang/test/Analysis/cfg.cpp
@@ -593,6 +593,63 @@
   A(), B();
 }
 
+// CHECK-LABEL: int crash_with_thread_local(char *p, int *q)
+// CHECK:       [B7 (ENTRY)]
+// CHECK-NEXT:    Succs (1): B6
+// CHECK:       [B1]
+// CHECK-NEXT:   bail:
+// CHECK-NEXT:    1: 0
+// CHECK-NEXT:    2: return [B1.1];
+// CHECK-NEXT:    Preds (2): B2 B5
+// CHECK-NEXT:    Succs (1): B0
+// CHECK:       [B2]
+// CHECK-NEXT:    1: 0
+// CHECK-NEXT:    2: q
+// CHECK-NEXT:    3: [B2.2] (ImplicitCastExpr, LValueToRValue, int *)
+// CHECK-NEXT:    4: *[B2.3]
+// CHECK-NEXT:    5: [B2.4] = [B2.1]
+// CHECK-NEXT:    Preds (2): B3 B4
+// CHECK-NEXT:    Succs (1): B1
+// CHECK:       [B3]
+// WARNINGS-NEXT: 1:  (CXXConstructExpr, struct ClassWithDtor)
+// ANALYZER-NEXT: 1:  (CXXConstructExpr, [B3.2], struct ClassWithDtor)
+// CHECK-NEXT:    2: thread_local ClassWithDtor a;
+// CHECK-NEXT:    Preds (1): B4
+// CHECK-NEXT:    Succs (1): B2
+// CHECK:       [B4]
+// CHECK-NEXT:    T: static init a
+// CHECK-NEXT:    Preds (1): B6
+// CHECK-NEXT:    Succs (2): B2 B3
+// CHECK:       [B5]
+// CHECK-NEXT:    T: goto bail;
+// CHECK-NEXT:    Preds (1): B6
+// CHECK-NEXT:    Succs (1): B1
+// CHECK:       [B6]
+// CHECK-NEXT:    1: p
+// CHECK-NEXT:    2: [B6.1] (ImplicitCastExpr, LValueToRValue, char *)
+// CHECK-NEXT:    3: 0
+// CHECK-NEXT:    4: [B6.3] (ImplicitCastExpr, NullToPointer, char *)
+// CHECK-NEXT:    5: [B6.2] != [B6.4]
+// CHECK-NEXT:    T: if [B6.5]
+// CHECK-NEXT:    Preds (1): B7
+// CHECK-NEXT:    Succs (2): B5 B4
+// CHECK:       [B0 (EXIT)]
+// CHECK-NEXT:    Preds (1): B1
+
+struct ClassWithDtor {
+  ~ClassWithDtor() {}
+};
+
+int crash_with_thread_local(char *p, int *q) {
+  if (p != 0) {
+    goto bail;
+  }
+  thread_local ClassWithDtor a;
+  *q = 0;
+bail:
+  return 0;
+}
+
 // CHECK-LABEL: template<> int *PR18472<int>()
 // CHECK: [B2 (ENTRY)]
 // CHECK-NEXT:   Succs (1): B1
Index: clang/lib/Analysis/CFG.cpp
===================================================================
--- clang/lib/Analysis/CFG.cpp
+++ clang/lib/Analysis/CFG.cpp
@@ -2021,6 +2021,11 @@
   // Check if variable is local.
   switch (VD->getStorageClass()) {
   case SC_None:
+    if (VD->getTSCSpec() == ThreadStorageClassSpecifier::TSCS_thread_local) {
+      // TSCS_thread_local implies "static" for block scope variables.
+      return Scope;
+    }
+    break;
   case SC_Auto:
   case SC_Register:
     break;


Index: clang/test/Analysis/cfg.cpp
===================================================================
--- clang/test/Analysis/cfg.cpp
+++ clang/test/Analysis/cfg.cpp
@@ -593,6 +593,63 @@
   A(), B();
 }
 
+// CHECK-LABEL: int crash_with_thread_local(char *p, int *q)
+// CHECK:       [B7 (ENTRY)]
+// CHECK-NEXT:    Succs (1): B6
+// CHECK:       [B1]
+// CHECK-NEXT:   bail:
+// CHECK-NEXT:    1: 0
+// CHECK-NEXT:    2: return [B1.1];
+// CHECK-NEXT:    Preds (2): B2 B5
+// CHECK-NEXT:    Succs (1): B0
+// CHECK:       [B2]
+// CHECK-NEXT:    1: 0
+// CHECK-NEXT:    2: q
+// CHECK-NEXT:    3: [B2.2] (ImplicitCastExpr, LValueToRValue, int *)
+// CHECK-NEXT:    4: *[B2.3]
+// CHECK-NEXT:    5: [B2.4] = [B2.1]
+// CHECK-NEXT:    Preds (2): B3 B4
+// CHECK-NEXT:    Succs (1): B1
+// CHECK:       [B3]
+// WARNINGS-NEXT: 1:  (CXXConstructExpr, struct ClassWithDtor)
+// ANALYZER-NEXT: 1:  (CXXConstructExpr, [B3.2], struct ClassWithDtor)
+// CHECK-NEXT:    2: thread_local ClassWithDtor a;
+// CHECK-NEXT:    Preds (1): B4
+// CHECK-NEXT:    Succs (1): B2
+// CHECK:       [B4]
+// CHECK-NEXT:    T: static init a
+// CHECK-NEXT:    Preds (1): B6
+// CHECK-NEXT:    Succs (2): B2 B3
+// CHECK:       [B5]
+// CHECK-NEXT:    T: goto bail;
+// CHECK-NEXT:    Preds (1): B6
+// CHECK-NEXT:    Succs (1): B1
+// CHECK:       [B6]
+// CHECK-NEXT:    1: p
+// CHECK-NEXT:    2: [B6.1] (ImplicitCastExpr, LValueToRValue, char *)
+// CHECK-NEXT:    3: 0
+// CHECK-NEXT:    4: [B6.3] (ImplicitCastExpr, NullToPointer, char *)
+// CHECK-NEXT:    5: [B6.2] != [B6.4]
+// CHECK-NEXT:    T: if [B6.5]
+// CHECK-NEXT:    Preds (1): B7
+// CHECK-NEXT:    Succs (2): B5 B4
+// CHECK:       [B0 (EXIT)]
+// CHECK-NEXT:    Preds (1): B1
+
+struct ClassWithDtor {
+  ~ClassWithDtor() {}
+};
+
+int crash_with_thread_local(char *p, int *q) {
+  if (p != 0) {
+    goto bail;
+  }
+  thread_local ClassWithDtor a;
+  *q = 0;
+bail:
+  return 0;
+}
+
 // CHECK-LABEL: template<> int *PR18472<int>()
 // CHECK: [B2 (ENTRY)]
 // CHECK-NEXT:   Succs (1): B1
Index: clang/lib/Analysis/CFG.cpp
===================================================================
--- clang/lib/Analysis/CFG.cpp
+++ clang/lib/Analysis/CFG.cpp
@@ -2021,6 +2021,11 @@
   // Check if variable is local.
   switch (VD->getStorageClass()) {
   case SC_None:
+    if (VD->getTSCSpec() == ThreadStorageClassSpecifier::TSCS_thread_local) {
+      // TSCS_thread_local implies "static" for block scope variables.
+      return Scope;
+    }
+    break;
   case SC_Auto:
   case SC_Register:
     break;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to