[llvm] r324412 - Fix a crash when emitting DIEs for variable-length arrays

Adrian Prantl via llvm-commits llvm-commits at lists.llvm.org
Tue Feb 6 14:17:45 PST 2018


Author: adrian
Date: Tue Feb  6 14:17:45 2018
New Revision: 324412

URL: http://llvm.org/viewvc/llvm-project?rev=324412&view=rev
Log:
Fix a crash when emitting DIEs for variable-length arrays

VLAs may refer to a previous DIE to express the DW_AT_count of their
type. Clang generates an artificial "vla_expr" variable for this. If
this DIE hasn't been created yet LLVM asserts. This patch fixes this
by sorting the local variables so that dependencies come before they
are needed. It also replaces the linear scan in DWARFFile with a
std::map, which can be faster.

Differential Revision: https://reviews.llvm.org/D42940

Added:
    llvm/trunk/test/DebugInfo/X86/vla-dependencies.ll
Modified:
    llvm/trunk/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
    llvm/trunk/lib/CodeGen/AsmPrinter/DwarfFile.cpp
    llvm/trunk/lib/CodeGen/AsmPrinter/DwarfFile.h

Modified: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp?rev=324412&r1=324411&r2=324412&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp (original)
+++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp Tue Feb  6 14:17:45 2018
@@ -568,13 +568,41 @@ DIE *DwarfCompileUnit::constructVariable
   return Var;
 }
 
+/// Determine whether a variable appears in a count: expression.
+static bool dependsOn(DbgVariable *A, DbgVariable *B) {
+  auto *Array = dyn_cast<DICompositeType>(A->getType());
+  if (!Array || Array->getTag() != dwarf::DW_TAG_array_type)
+    return false;
+  return llvm::any_of(Array->getElements(), [&](DINode *El) {
+    if (auto *Subrange = dyn_cast<DISubrange>(El)) {
+      auto Count = Subrange->getCount();
+      if (auto *Var = Count.dyn_cast<DIVariable *>())
+        return Var == B->getVariable();
+    }
+    return false;
+  });
+}
+
+/// Sort local variables so that variables appearing inside of helper
+/// expressions come first.
+static bool sortLocalVars(DbgVariable *A, DbgVariable *B) {
+  return dependsOn(B, A);
+}
+
 DIE *DwarfCompileUnit::createScopeChildrenDIE(LexicalScope *Scope,
                                               SmallVectorImpl<DIE *> &Children,
                                               bool *HasNonScopeChildren) {
   assert(Children.empty());
   DIE *ObjectPointer = nullptr;
 
-  for (DbgVariable *DV : DU->getScopeVariables().lookup(Scope))
+  // Emit function arguments (order is significant).
+  auto Vars = DU->getScopeVariables().lookup(Scope);
+  for (auto &DV : Vars.Args)
+    Children.push_back(constructVariableDIE(*DV.second, *Scope, ObjectPointer));
+
+  // Emit local variables.
+  std::stable_sort(Vars.Locals.begin(), Vars.Locals.end(), sortLocalVars);
+  for (DbgVariable *DV : Vars.Locals)
     Children.push_back(constructVariableDIE(*DV, *Scope, ObjectPointer));
 
   // Skip imported directives in gmlt-like data.

Modified: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfFile.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/DwarfFile.cpp?rev=324412&r1=324411&r2=324412&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfFile.cpp (original)
+++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfFile.cpp Tue Feb  6 14:17:45 2018
@@ -103,37 +103,18 @@ void DwarfFile::emitStrings(MCSection *S
 }
 
 bool DwarfFile::addScopeVariable(LexicalScope *LS, DbgVariable *Var) {
-  SmallVectorImpl<DbgVariable *> &Vars = ScopeVariables[LS];
+  auto &ScopeVars = ScopeVariables[LS];
   const DILocalVariable *DV = Var->getVariable();
-  // Variables with positive arg numbers are parameters.
   if (unsigned ArgNum = DV->getArg()) {
-    // Keep all parameters in order at the start of the variable list to ensure
-    // function types are correct (no out-of-order parameters)
-    //
-    // This could be improved by only doing it for optimized builds (unoptimized
-    // builds have the right order to begin with), searching from the back (this
-    // would catch the unoptimized case quickly), or doing a binary search
-    // rather than linear search.
-    auto I = Vars.begin();
-    while (I != Vars.end()) {
-      unsigned CurNum = (*I)->getVariable()->getArg();
-      // A local (non-parameter) variable has been found, insert immediately
-      // before it.
-      if (CurNum == 0)
-        break;
-      // A later indexed parameter has been found, insert immediately before it.
-      if (CurNum > ArgNum)
-        break;
-      if (CurNum == ArgNum) {
-        (*I)->addMMIEntry(*Var);
-        return false;
-      }
-      ++I;
+    auto Cached = ScopeVars.Args.find(ArgNum);
+    if (Cached == ScopeVars.Args.end())
+      ScopeVars.Args[ArgNum] = Var;
+    else {
+      Cached->second->addMMIEntry(*Var);
+      return false;
     }
-    Vars.insert(I, Var);
-    return true;
-  }
-
-  Vars.push_back(Var);
+  } else {
+    ScopeVars.Locals.push_back(Var);
+  }    
   return true;
 }

Modified: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfFile.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/DwarfFile.h?rev=324412&r1=324411&r2=324412&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfFile.h (original)
+++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfFile.h Tue Feb  6 14:17:45 2018
@@ -17,6 +17,7 @@
 #include "llvm/CodeGen/DIE.h"
 #include "llvm/IR/Metadata.h"
 #include "llvm/Support/Allocator.h"
+#include <map>
 #include <memory>
 #include <utility>
 
@@ -47,8 +48,15 @@ class DwarfFile {
   /// the string offsets table. The contribution is shared by all units.
   MCSymbol *StringOffsetsStartSym = nullptr;
 
-  // Collection of dbg variables of a scope.
-  DenseMap<LexicalScope *, SmallVector<DbgVariable *, 8>> ScopeVariables;
+  /// The variables of a lexical scope.
+  struct ScopeVars {
+    /// We need to sort Args by ArgNo and check for duplicates. This could also
+    /// be implemented as a list or vector + std::lower_bound().
+    std::map<unsigned, DbgVariable *> Args;
+    SmallVector<DbgVariable *, 8> Locals;
+  };
+  /// Collection of DbgVariables of each lexical scope.
+  DenseMap<LexicalScope *, ScopeVars> ScopeVariables;
 
   // Collection of abstract subprogram DIEs.
   DenseMap<const MDNode *, DIE *> AbstractSPDies;
@@ -109,7 +117,7 @@ public:
   /// \returns false if the variable was merged with a previous one.
   bool addScopeVariable(LexicalScope *LS, DbgVariable *Var);
 
-  DenseMap<LexicalScope *, SmallVector<DbgVariable *, 8>> &getScopeVariables() {
+  DenseMap<LexicalScope *, ScopeVars> &getScopeVariables() {
     return ScopeVariables;
   }
 

Added: llvm/trunk/test/DebugInfo/X86/vla-dependencies.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/X86/vla-dependencies.ll?rev=324412&view=auto
==============================================================================
--- llvm/trunk/test/DebugInfo/X86/vla-dependencies.ll (added)
+++ llvm/trunk/test/DebugInfo/X86/vla-dependencies.ll Tue Feb  6 14:17:45 2018
@@ -0,0 +1,99 @@
+; RUN: llc -mtriple=x86_64-apple-darwin %s -o - -filetype=obj | llvm-dwarfdump - | FileCheck %s
+; CHECK:  DW_TAG_subprogram
+; CHECK:    DW_AT_name	("h")
+; CHECK: 0x00000[[VLAEXPR:.*]]:     DW_TAG_variable
+; CHECK-NEXT:                DW_AT_name	("vla_expr")
+;0x000000b1:   DW_TAG_array_type
+;                DW_AT_type	(cu + 0x0066 "unsigned char")
+;
+;0x000000b6:     DW_TAG_subrange_type
+;                  DW_AT_type	(cu + 0x0079 "sizetype")
+;                  DW_AT_count	(cu + 0x[[VLAEXPR]])
+;
+;
+; Generated from:
+;
+; #define DECLARE_ARRAY(type, var_name, size) type var_name[size]
+;  
+; void h(void);
+; void k(void *);
+;  
+; void g() {
+;   h();
+; }
+;  
+; void h() {
+;   int count = 2;
+;   DECLARE_ARRAY(int, array, count);
+;   k((void *)array);
+; }
+source_filename = "/tmp/test.c"
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.13.0"
+
+; Function Attrs: nounwind ssp uwtable
+define void @g() local_unnamed_addr #0 !dbg !10 {
+entry:
+  %vla2.i = alloca [2 x i32], align 16, !dbg !13
+  call void @llvm.dbg.declare(metadata [2 x i32]* %vla2.i, metadata !20, metadata !DIExpression(DW_OP_stack_value)), !dbg !13
+  %0 = bitcast [2 x i32]* %vla2.i to i8*, !dbg !25
+  call void @llvm.lifetime.start.p0i8(i64 8, i8* nonnull %0), !dbg !25
+  call void @llvm.dbg.value(metadata i32 2, metadata !16, metadata !DIExpression()) #3, !dbg !25
+  call void @llvm.dbg.value(metadata i64 2, metadata !18, metadata !DIExpression()) #3, !dbg !13
+  call void @k(i8* nonnull %0) #3, !dbg !26
+  call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %0), !dbg !27
+  ret void, !dbg !28
+}
+
+; Function Attrs: nounwind readnone speculatable
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+declare void @k(i8*) local_unnamed_addr
+
+; Function Attrs: nounwind readnone speculatable
+declare void @llvm.dbg.value(metadata, metadata, metadata) #1
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #2
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #2
+
+attributes #0 = { nounwind ssp uwtable }
+attributes #1 = { nounwind readnone speculatable }
+attributes #2 = { argmemonly nounwind }
+attributes #3 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!5, !6, !7, !8}
+!llvm.ident = !{!9}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 7.0.0 (trunk 324259) (llvm/trunk 324261)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3)
+!1 = !DIFile(filename: "/tmp/test.c", directory: "/")
+!2 = !{}
+!3 = !{!4}
+!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
+!5 = !{i32 2, !"Dwarf Version", i32 4}
+!6 = !{i32 2, !"Debug Info Version", i32 3}
+!7 = !{i32 1, !"wchar_size", i32 4}
+!8 = !{i32 7, !"PIC Level", i32 2}
+!9 = !{!"clang version 7.0.0 (trunk 324259) (llvm/trunk 324261)"}
+!10 = distinct !DISubprogram(name: "g", scope: !1, file: !1, line: 6, type: !11, isLocal: false, isDefinition: true, scopeLine: 6, isOptimized: true, unit: !0, variables: !2)
+!11 = !DISubroutineType(types: !12)
+!12 = !{null}
+!13 = !DILocation(line: 12, column: 3, scope: !14, inlinedAt: !24)
+!14 = distinct !DISubprogram(name: "h", scope: !1, file: !1, line: 10, type: !11, isLocal: false, isDefinition: true, scopeLine: 10, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !15)
+!15 = !{!16, !18, !20}
+!16 = !DILocalVariable(name: "count", scope: !14, file: !1, line: 11, type: !17)
+!17 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!18 = !DILocalVariable(name: "vla_expr", scope: !14, file: !1, line: 12, type: !19)
+!19 = !DIBasicType(name: "long unsigned int", size: 64, encoding: DW_ATE_unsigned)
+!20 = !DILocalVariable(name: "array", scope: !14, file: !1, line: 12, type: !21)
+!21 = !DICompositeType(tag: DW_TAG_array_type, baseType: !17, elements: !22)
+!22 = !{!23}
+!23 = !DISubrange(count: !18)
+!24 = distinct !DILocation(line: 7, column: 3, scope: !10)
+!25 = !DILocation(line: 11, column: 7, scope: !14, inlinedAt: !24)
+!26 = !DILocation(line: 13, column: 3, scope: !14, inlinedAt: !24)
+!27 = !DILocation(line: 14, column: 1, scope: !14, inlinedAt: !24)
+!28 = !DILocation(line: 8, column: 1, scope: !10)




More information about the llvm-commits mailing list