Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reland "[Support] Assert that DomTree nodes share parent"" #102782

Merged
merged 4 commits into from
Aug 13, 2024

Conversation

vitalybuka
Copy link
Collaborator

@vitalybuka vitalybuka commented Aug 11, 2024

Reverts #102780
Reland #101198
Fixes #102784

@llvmbot
Copy link
Member

llvmbot commented Aug 11, 2024

@llvm/pr-subscribers-llvm-transforms
@llvm/pr-subscribers-llvm-analysis

@llvm/pr-subscribers-llvm-support

Author: Vitaly Buka (vitalybuka)

Changes

Reverts llvm/llvm-project#102780
Reland #101198


Full diff: https://github.com/llvm/llvm-project/pull/102782.diff

5 Files Affected:

  • (modified) llvm/include/llvm/Support/GenericDomTree.h (+2)
  • (modified) llvm/lib/Analysis/TypeMetadataUtils.cpp (+2)
  • (modified) llvm/lib/Transforms/Scalar/AlignmentFromAssumptions.cpp (+1)
  • (modified) llvm/lib/Transforms/Scalar/LoopFuse.cpp (+6-2)
  • (added) llvm/test/Transforms/AlignmentFromAssumptions/domtree-crash.ll (+33)
diff --git a/llvm/include/llvm/Support/GenericDomTree.h b/llvm/include/llvm/Support/GenericDomTree.h
index 7e2b68e6faea29..45ef38b965b752 100644
--- a/llvm/include/llvm/Support/GenericDomTree.h
+++ b/llvm/include/llvm/Support/GenericDomTree.h
@@ -397,6 +397,8 @@ class DominatorTreeBase {
   /// may (but is not required to) be null for a forward (backwards)
   /// statically unreachable block.
   DomTreeNodeBase<NodeT> *getNode(const NodeT *BB) const {
+    assert((!BB || Parent == NodeTrait::getParent(const_cast<NodeT *>(BB))) &&
+           "cannot get DomTreeNode of block with different parent");
     if (auto Idx = getNodeIndex(BB); Idx && *Idx < DomTreeNodes.size())
       return DomTreeNodes[*Idx].get();
     return nullptr;
diff --git a/llvm/lib/Analysis/TypeMetadataUtils.cpp b/llvm/lib/Analysis/TypeMetadataUtils.cpp
index 67ce1540112bb7..9ec0785eb5034d 100644
--- a/llvm/lib/Analysis/TypeMetadataUtils.cpp
+++ b/llvm/lib/Analysis/TypeMetadataUtils.cpp
@@ -33,6 +33,8 @@ findCallsAtConstantOffset(SmallVectorImpl<DevirtCallSite> &DevirtCalls,
     // after indirect call promotion and inlining, where we may have uses
     // of the vtable pointer guarded by a function pointer check, and a fallback
     // indirect call.
+    if (CI->getFunction() != User->getFunction())
+      continue;
     if (!DT.dominates(CI, User))
       continue;
     if (isa<BitCastInst>(User)) {
diff --git a/llvm/lib/Transforms/Scalar/AlignmentFromAssumptions.cpp b/llvm/lib/Transforms/Scalar/AlignmentFromAssumptions.cpp
index f3422a705dca7a..8555ef5c22f827 100644
--- a/llvm/lib/Transforms/Scalar/AlignmentFromAssumptions.cpp
+++ b/llvm/lib/Transforms/Scalar/AlignmentFromAssumptions.cpp
@@ -208,6 +208,7 @@ bool AlignmentFromAssumptionsPass::processAssumption(CallInst *ACall,
       continue;
 
     if (Instruction *K = dyn_cast<Instruction>(J))
+      if (K->getFunction() == ACall->getFunction())
         WorkList.push_back(K);
   }
 
diff --git a/llvm/lib/Transforms/Scalar/LoopFuse.cpp b/llvm/lib/Transforms/Scalar/LoopFuse.cpp
index 8512b2accbe7c2..fe0e30d1965e05 100644
--- a/llvm/lib/Transforms/Scalar/LoopFuse.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopFuse.cpp
@@ -1729,7 +1729,9 @@ struct LoopFuser {
     // mergeLatch may remove the only block in FC1.
     SE.forgetLoop(FC1.L);
     SE.forgetLoop(FC0.L);
-    SE.forgetLoopDispositions();
+    // Forget block dispositions as well, so that there are no dangling
+    // pointers to erased/free'ed blocks.
+    SE.forgetBlockAndLoopDispositions();
 
     // Move instructions from FC0.Latch to FC1.Latch.
     // Note: mergeLatch requires an updated DT.
@@ -2023,7 +2025,9 @@ struct LoopFuser {
     // mergeLatch may remove the only block in FC1.
     SE.forgetLoop(FC1.L);
     SE.forgetLoop(FC0.L);
-    SE.forgetLoopDispositions();
+    // Forget block dispositions as well, so that there are no dangling
+    // pointers to erased/free'ed blocks.
+    SE.forgetBlockAndLoopDispositions();
 
     // Move instructions from FC0.Latch to FC1.Latch.
     // Note: mergeLatch requires an updated DT.
diff --git a/llvm/test/Transforms/AlignmentFromAssumptions/domtree-crash.ll b/llvm/test/Transforms/AlignmentFromAssumptions/domtree-crash.ll
new file mode 100644
index 00000000000000..c7fc1dc6996718
--- /dev/null
+++ b/llvm/test/Transforms/AlignmentFromAssumptions/domtree-crash.ll
@@ -0,0 +1,33 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -passes=alignment-from-assumptions -S < %s | FileCheck %s
+
+; The alignment assumption is a global, which has users in a different
+; function. Test that in this case the dominator tree is only queried with
+; blocks from the same function.
+
+@global = external constant [192 x i8]
+
+define void @fn1() {
+; CHECK-LABEL: define void @fn1() {
+; CHECK-NEXT:    call void @llvm.assume(i1 false) [ "align"(ptr @global, i64 1) ]
+; CHECK-NEXT:    ret void
+;
+  call void @llvm.assume(i1 false) [ "align"(ptr @global, i64 1) ]
+  ret void
+}
+
+define void @fn2() {
+; CHECK-LABEL: define void @fn2() {
+; CHECK-NEXT:    ret void
+; CHECK:       [[LOOP:.*]]:
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i8, ptr @global, i64 0
+; CHECK-NEXT:    [[LOAD:%.*]] = load i64, ptr [[GEP]], align 1
+; CHECK-NEXT:    br label %[[LOOP]]
+;
+  ret void
+
+loop:
+  %gep = getelementptr inbounds i8, ptr @global, i64 0
+  %load = load i64, ptr %gep, align 1
+  br label %loop
+}

@vitalybuka
Copy link
Collaborator Author

@aengelke
Sorry for reverting, but it's better to revert and then investigate.
I am not planning to reland this, it's just an additional notice about the reverted patch.

@aengelke
Copy link
Contributor

Thanks @dyung for the reproducer, that was very helpful -- reduced further to a test case. I now was able to track it down to SLPVectorize and made a (imho) uncontroversial change to fix it.

Sorry for reverting, but it's better to revert and then investigate.

Sure, nothing to be sorry about! :)

@aengelke aengelke requested a review from nikic August 11, 2024 06:00
; CHECK-NEXT: ret void
;
entry:
%0 = getelementptr i8, ptr null, i64 28
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you replace null with a global here to make the code not be immediate UB?

Is the code iterating over null users or over 0.000000e+00/1.000000e+00 users? If it's the latter, than this code probably needs a larger fix, because iterating over ConstantData users is not allowed in general. (Also applies to null, but in that case a global is a plausible replacement.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's iterating over the ConstantData users. I'm not familiar with SLP, please advise how to fix the larger problem. (If iterating over such users is not allowed, why is there no assertion for this?)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's iterating over the ConstantData users. I'm not familiar with SLP, please advise how to fix the larger problem.

Adding an isa<ConstantData>(V) break; in this function should work. (You should still keep your check, in case we're iterating over GV users.)

If iterating over such users is not allowed, why is there no assertion for this?

Nobody has implemented it :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added the extra check.

@aengelke
Copy link
Contributor

(CI failure (timeout on lldb-api :: functionalities/fork/concurrent_vfork/TestConcurrentVFork.py) seems unrelated)

Copy link
Contributor

@nikic nikic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@aengelke aengelke merged commit 5ce47a5 into main Aug 13, 2024
8 checks passed
@aengelke aengelke deleted the revert-102780-revert-101198-domtreecleanup4 branch August 13, 2024 09:56
@ilovepi
Copy link
Contributor

ilovepi commented Aug 13, 2024

Hi, I think we're seeing an assertion failure in two-stage builds after this patch. I'm still bisecting to be sure, but given the assertion we're seeing, I think its related. Would you mind taking a look, and reverting if its going to take a while to fix?

: && /b/s/w/ir/x/w/llvm_build/./bin/clang++ --sysroot=/b/s/w/ir/x/w/cipd/linux -stdlib=libc++ -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wc++98-compat-extra-semi -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wno-comment -Wstring-conversion -Wmisleading-indentation -Wctad-maybe-unsupported -fdiagnostics-color -ffunction-sections -fdata-sections -flto=full -ffat-lto-objects -ffile-prefix-map=/b/s/w/ir/x/w/llvm_build/tools/clang/stage2-bins=../../../../llvm-llvm-project -ffile-prefix-map=/b/s/w/ir/x/w/llvm-llvm-project/= -no-canonical-prefixes -fno-common -Woverloaded-virtual -Wno-nested-anon-types -O3 -DNDEBUG -stdlib=libc++ -static-libstdc++ -fuse-ld=lld -Wl,--color-diagnostics -flto=full -ffat-lto-objects    -Wl,--gc-sections tools/clang/tools/clang-format/CMakeFiles/clang-format.dir/ClangFormat.cpp.o -o bin/clang-format  -Wl,-rpath,"\$ORIGIN/../lib:"  lib/libLLVMSupport.a  -lpthread  lib/libclangBasic.a  lib/libclangFormat.a  lib/libclangRewrite.a  lib/libclangToolingCore.a  lib/libclangToolingInclusions.a  lib/libclangToolingCore.a  lib/libclangRewrite.a  lib/libclangLex.a  lib/libclangBasic.a  lib/libLLVMFrontendOpenMP.a  lib/libLLVMScalarOpts.a  lib/libLLVMAggressiveInstCombine.a  lib/libLLVMInstCombine.a  lib/libLLVMFrontendOffloading.a  lib/libLLVMTransformUtils.a  lib/libLLVMAnalysis.a  lib/libtf_xla_runtime.a  lib/libLLVMProfileData.a  lib/libLLVMSymbolize.a  lib/libLLVMDebugInfoPDB.a  lib/libLLVMDebugInfoMSF.a  lib/libLLVMDebugInfoBTF.a  lib/libLLVMDebugInfoDWARF.a  lib/libLLVMObject.a  lib/libLLVMIRReader.a  lib/libLLVMBitReader.a  lib/libLLVMAsmParser.a  lib/libLLVMCore.a  lib/libLLVMRemarks.a  lib/libLLVMBitstreamReader.a  lib/libLLVMMCParser.a  lib/libLLVMMC.a  lib/libLLVMDebugInfoCodeView.a  lib/libLLVMTextAPI.a  lib/libLLVMBinaryFormat.a  lib/libLLVMTargetParser.a  lib/libLLVMSupport.a  -lrt  -ldl  -lpthread  -lm  /b/s/w/ir/x/w/zlib_install_target/lib/libz.a  /b/s/w/ir/x/w/zstd_install/lib/libzstd.a  -pthread  lib/libLLVMDemangle.a && :
ld.lld: llvm/include/llvm/Support/GenericDomTree.h:401: DomTreeNodeBase<NodeT> *llvm::DominatorTreeBase<llvm::BasicBlock, false>::getNode(const NodeT *) const [NodeT = llvm::BasicBlock, IsPostDom = false]: Assertion `(!BB || Parent == NodeTrait::getParent(const_cast<NodeT *>(BB))) && "cannot get DomTreeNode of block with different parent"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.	Program arguments: /b/s/w/ir/x/w/llvm_build/./bin/ld.lld --sysroot=/b/s/w/ir/x/w/cipd/linux --hash-style=gnu --build-id --eh-frame-hdr -m elf_x86_64 -pie -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o bin/clang-format /b/s/w/ir/x/w/cipd/linux/usr/lib/x86_64-linux-gnu/Scrt1.o /b/s/w/ir/x/w/cipd/linux/usr/lib/x86_64-linux-gnu/crti.o /b/s/w/ir/x/w/llvm_build/./lib/clang/20/lib/x86_64-unknown-linux-gnu/clang_rt.crtbegin.o -L/b/s/w/ir/x/w/llvm_build/./bin/../lib/x86_64-unknown-linux-gnu -L/b/s/w/ir/x/w/llvm_build/./lib/clang/20/lib/x86_64-unknown-linux-gnu -L/b/s/w/ir/x/w/cipd/linux/lib/x86_64-linux-gnu -L/b/s/w/ir/x/w/cipd/linux/lib/../lib64 -L/b/s/w/ir/x/w/cipd/linux/usr/lib/x86_64-linux-gnu -L/b/s/w/ir/x/w/cipd/linux/lib -L/b/s/w/ir/x/w/cipd/linux/usr/lib --fat-lto-objects -plugin-opt=mcpu=x86-64 -plugin-opt=O3 -plugin-opt=-function-sections=1 -plugin-opt=-data-sections=1 --color-diagnostics --gc-sections tools/clang/tools/clang-format/CMakeFiles/clang-format.dir/ClangFormat.cpp.o -rpath $ORIGIN/../lib: lib/libLLVMSupport.a -lpthread lib/libclangBasic.a lib/libclangFormat.a lib/libclangRewrite.a lib/libclangToolingCore.a lib/libclangToolingInclusions.a lib/libclangToolingCore.a lib/libclangRewrite.a lib/libclangLex.a lib/libclangBasic.a lib/libLLVMFrontendOpenMP.a lib/libLLVMScalarOpts.a lib/libLLVMAggressiveInstCombine.a lib/libLLVMInstCombine.a lib/libLLVMFrontendOffloading.a lib/libLLVMTransformUtils.a lib/libLLVMAnalysis.a lib/libtf_xla_runtime.a lib/libLLVMProfileData.a lib/libLLVMSymbolize.a lib/libLLVMDebugInfoPDB.a lib/libLLVMDebugInfoMSF.a lib/libLLVMDebugInfoBTF.a lib/libLLVMDebugInfoDWARF.a lib/libLLVMObject.a lib/libLLVMIRReader.a lib/libLLVMBitReader.a lib/libLLVMAsmParser.a lib/libLLVMCore.a lib/libLLVMRemarks.a lib/libLLVMBitstreamReader.a lib/libLLVMMCParser.a lib/libLLVMMC.a lib/libLLVMDebugInfoCodeView.a lib/libLLVMTextAPI.a lib/libLLVMBinaryFormat.a lib/libLLVMTargetParser.a lib/libLLVMSupport.a -lrt -ldl -lpthread -lm /b/s/w/ir/x/w/zlib_install_target/lib/libz.a /b/s/w/ir/x/w/zstd_install/lib/libzstd.a lib/libLLVMDemangle.a -Bstatic -lc++ -Bdynamic -lm /b/s/w/ir/x/w/llvm_build/./lib/clang/20/lib/x86_64-unknown-linux-gnu/libclang_rt.builtins.a --as-needed -lunwind --no-as-needed -lpthread -lc /b/s/w/ir/x/w/llvm_build/./lib/clang/20/lib/x86_64-unknown-linux-gnu/libclang_rt.builtins.a --as-needed -lunwind --no-as-needed /b/s/w/ir/x/w/llvm_build/./lib/clang/20/lib/x86_64-unknown-linux-gnu/clang_rt.crtend.o /b/s/w/ir/x/w/cipd/linux/usr/lib/x86_64-linux-gnu/crtn.o
1.	Running pass "function<eager-inv>(loop-mssa(licm<allowspeculation>),gvn<>,memcpyopt,dse,move-auto-init,mldst-motion<no-split-footer-bb>,loop(indvars,loop-deletion,loop-unroll-full),loop-distribute,loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>,infer-alignment,loop-unroll<O3>,transform-warning,sroa<preserve-cfg>,instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,simplifycfg<bonus-inst-threshold=1;forward-switch-cond;switch-range-to-icmp;switch-to-lookup;no-keep-loops;hoist-common-insts;sink-common-insts;speculate-blocks;simplify-cond-branch;no-speculate-unpredictables>,sccp,instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,bdce,slp-vectorizer,vector-combine,infer-alignment,instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>,loop-mssa(licm<allowspeculation>),alignment-from-assumptions,jump-threading)" on module "ld-temp.o"
2.	Running pass "instcombine<max-iterations=1;no-use-loop-info;no-verify-fixpoint>" on function "_ZL15getOpenFileImplIN4llvm12MemoryBufferEENS0_7ErrorOrINSt3__210unique_ptrIT_NS3_14default_deleteIS5_EEEEEEiRKNS0_5TwineEmmlbbNS3_8optionalINS0_5AlignEEE"
#0 0x000055e2ff6b31b8 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/b/s/w/ir/x/w/llvm_build/./bin/ld.lld+0x237e1b8)
clang++: error: unable to execute command: Aborted
clang++: error: linker command failed due to signal (use -v to see invocation)

First Failing Bot: https://ci.chromium.org/ui/p/fuchsia/builders/prod/clang-linux-x64/b8739716235612224273/overview

Logs: https://logs.chromium.org/logs/fuchsia/buildbucket/cr-buildbucket/8739716235612224273/+/u/clang/build/stdout

You should be able to reproduce with any 2-stage build, as long as you're also building clang-format.

Bug: https://fxbug.dev/359549254

@fhahn
Copy link
Contributor

fhahn commented Aug 13, 2024

The below now crashes with opt -passes='default<O3>'

; ModuleID = 'reduced.ll'
source_filename = "reduced.ll"
target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128-Fn32"
target triple = "arm64-apple-macosx"

%struct.widget = type { %struct.baz, i8, [7 x i8] }
%struct.baz = type { %struct.snork }
%struct.snork = type { [8 x i8] }

define void @spam(ptr %arg) {
bb:
  call void @barney(ptr %arg)
  ret void
}

define ptr @zot(ptr %arg) {
bb:
  %call = call ptr @ham.8(ptr %arg)
  ret ptr null
}

define void @wombat() personality ptr null {
bb:
  call void @snork()
  unreachable
}

define ptr @wombat.1(ptr %arg) {
bb:
  %call = call ptr @foo.9(ptr %arg)
  ret ptr null
}

define void @quux() personality ptr null {
bb:
  call void @wobble()
  ret void
}

define void @wobble() personality ptr null {
bb:
  call void @quux.3()
  ret void
}

define void @eggs() personality ptr null {
bb:
  %alloca = alloca %struct.widget, align 8
  br label %bb1

bb1:                                              ; preds = %bb1, %bb
  call void @spam(ptr %alloca)
  %call = call ptr @zot(ptr %alloca)
  br label %bb1
}

define void @wobble.2() personality ptr null {
bb:
  call void @wibble(ptr null)
  ret void
}

define void @quux.3() personality ptr null {
bb:
  call void @wobble.2()
  ret void
}

define void @zot.4() personality ptr null {
bb:
  call void @blam()
  ret void
}

define void @blam() {
bb:
  %load = load volatile i32, ptr null, align 4
  %icmp = icmp eq i32 %load, 0
  br i1 %icmp, label %bb2, label %bb3

bb1:                                              ; preds = %bb3, %bb2
  ret void

bb2:                                              ; preds = %bb
  call void @eggs()
  br label %bb1

bb3:                                              ; preds = %bb
  call void @quux()
  br label %bb1
}

define void @barney(ptr %arg) personality ptr null {
bb:
  %load = load volatile i1, ptr null, align 1
  br i1 %load, label %bb2, label %bb3

bb1:                                              ; preds = %bb3, %bb2
  ret void

bb2:                                              ; preds = %bb
  %call = call ptr @wombat.1(ptr %arg)
  br label %bb1

bb3:                                              ; preds = %bb
  call void @zot.4()
  br label %bb1
}

define void @snork() personality ptr null {
bb:
  call void @barney(ptr null)
  ret void
}

define void @wibble(ptr %arg) personality ptr null {
bb:
  %load = load volatile i1, ptr null, align 1
  br i1 %load, label %bb2, label %bb3

bb1:                                              ; preds = %bb3, %bb2
  ret void

bb2:                                              ; preds = %bb
  %call = call i64 @zot.5(i64 0)
  %inttoptr = inttoptr i64 %call to ptr
  store ptr %inttoptr, ptr %arg, align 8
  br label %bb1

bb3:                                              ; preds = %bb
  %call4 = call i64 @foo()
  br label %bb1
}

define i64 @zot.5(i64 %arg) {
bb:
  ret i64 %arg
}

define i64 @foo() {
bb:
  call void @wombat()
  ret i64 0
}

define ptr @ham(ptr %arg) {
bb:
  %call = call ptr @foo.7(ptr %arg)
  ret ptr null
}

define void @quux.6(ptr %arg) {
bb:
  %load = load ptr, ptr %arg, align 8
  store ptr null, ptr %arg, align 8
  store i32 0, ptr %load, align 4
  ret void
}

define ptr @foo.7(ptr %arg) {
bb:
  call void @quux.6(ptr %arg)
  ret ptr null
}

define ptr @ham.8(ptr %arg) personality ptr null {
bb:
  %call = call ptr @ham(ptr %arg)
  ret ptr null
}

define ptr @foo.9(ptr %arg) {
bb:
  store i64 1, ptr %arg, align 8
  ret ptr null
}

@aengelke
Copy link
Contributor

aengelke commented Aug 13, 2024

For @fhahn's reduced code (thanks for that!), a fix is at #103302.

@aengelke
Copy link
Contributor

@ilovepi I was able to reproduce the (or a similar) problem in a stage2 clang build, and can say that #103302 fixed the problem for me.

@ilovepi
Copy link
Contributor

ilovepi commented Aug 13, 2024

@ilovepi I was able to reproduce the (or a similar) problem in a stage2 clang build, and can say that #103302 fixed the problem for me.

Thanks!

bwendling pushed a commit to bwendling/llvm-project that referenced this pull request Aug 15, 2024
A dominance query of a block that is in a different function is
ill-defined, so assert that getNode() is only called for blocks that are
in the same function.

There are three cases, where this behavior did occur. LoopFuse didn't
explicitly do this, but didn't invalidate the SCEV block dispositions,
leaving dangling pointers to free'ed basic blocks behind, causing
use-after-free. We do, however, want to be able to dereference basic
blocks inside the dominator tree, so that we can refer to them by a
number stored inside the basic block.

Reverts llvm#102780
Reland llvm#101198
Fixes llvm#102784

Co-authored-by: Alexis Engelke <engelke@in.tum.de>
@mikaelholmen
Copy link
Collaborator

mikaelholmen commented Aug 15, 2024

Hi,

I hit the new assertion with

clang -cc1 -analyze -analyzer-checker=core bbi-98084.c

Result:

clang: ../include/llvm/Support/GenericDomTree.h:401: DomTreeNodeBase<NodeT> *llvm::DominatorTreeBase<clang::CFGBlock, true>::getNode(const NodeT *) const [NodeT = clang::CFGBlock, IsPostDom = true]: Assertion `(!BB || Parent == NodeTrait::getParent(const_cast<NodeT *>(BB))) && "cannot get DomTreeNode of block with different parent"' failed.
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: build-all/bin/clang -cc1 -analyze -analyzer-checker=core bbi-98084.c
1.	<eof> parser at end of file
 #0 0x000055c5fc23be87 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (build-all/bin/clang+0x7ed5e87)
 #1 0x000055c5fc2399ee llvm::sys::RunSignalHandlers() (build-all/bin/clang+0x7ed39ee)
 #2 0x000055c5fc23c54f SignalHandler(int) Signals.cpp:0:0
 #3 0x00007f50ecd71cf0 __restore_rt (/lib64/libpthread.so.0+0x12cf0)
 #4 0x00007f50ea92aacf raise (/lib64/libc.so.6+0x4eacf)
 #5 0x00007f50ea8fdea5 abort (/lib64/libc.so.6+0x21ea5)
 #6 0x00007f50ea8fdd79 _nl_load_domain.cold.0 (/lib64/libc.so.6+0x21d79)
 #7 0x00007f50ea923426 (/lib64/libc.so.6+0x47426)
 #8 0x000055c5fded94df (build-all/bin/clang+0x9b734df)
 #9 0x000055c5fded8906 llvm::IDFCalculatorBase<clang::CFGBlock, true>::calculate(llvm::SmallVectorImpl<clang::CFGBlock*>&) (build-all/bin/clang+0x9b72906)
#10 0x000055c5fded6ff6 clang::ControlDependencyCalculator::getControlDependencies(clang::CFGBlock*) DebugCheckers.cpp:0:0
#11 0x000055c5fe247da1 (anonymous namespace)::TrackControlDependencyCondBRVisitor::VisitNode(clang::ento::ExplodedNode const*, clang::ento::BugReporterContext&, clang::ento::PathSensitiveBugReport&) BugReporterVisitors.cpp:0:0
#12 0x000055c5fe232c85 generateVisitorsDiagnostics(clang::ento::PathSensitiveBugReport*, clang::ento::ExplodedNode const*, clang::ento::BugReporterContext&) BugReporter.cpp:0:0
#13 0x000055c5fe22e574 clang::ento::PathSensitiveBugReporter::generatePathDiagnostics(llvm::ArrayRef<clang::ento::PathDiagnosticConsumer*>, llvm::ArrayRef<clang::ento::PathSensitiveBugReport*>&) (build-all/bin/clang+0x9ec8574)
#14 0x000055c5fe231b9b clang::ento::PathSensitiveBugReporter::generateDiagnosticForConsumerMap(clang::ento::BugReport*, llvm::ArrayRef<clang::ento::PathDiagnosticConsumer*>, llvm::ArrayRef<clang::ento::BugReport*>) (build-all/bin/clang+0x9ecbb9b)
#15 0x000055c5fe22bee6 clang::ento::BugReporter::FlushReport(clang::ento::BugReportEquivClass&) (build-all/bin/clang+0x9ec5ee6)
#16 0x000055c5fe22bcbb clang::ento::BugReporter::FlushReports() (build-all/bin/clang+0x9ec5cbb)
#17 0x000055c5fde0e3dd (anonymous namespace)::AnalysisConsumer::HandleCode(clang::Decl*, unsigned int, clang::ento::ExprEngine::InliningModes, llvm::DenseSet<clang::Decl const*, llvm::DenseMapInfo<clang::Decl const*, void>>*) AnalysisConsumer.cpp:0:0
#18 0x000055c5fdde70ab (anonymous namespace)::AnalysisConsumer::HandleTranslationUnit(clang::ASTContext&) AnalysisConsumer.cpp:0:0
#19 0x000055c5fe391847 clang::ParseAST(clang::Sema&, bool, bool) (build-all/bin/clang+0xa02b847)
#20 0x000055c5fceea190 clang::FrontendAction::Execute() (build-all/bin/clang+0x8b84190)
#21 0x000055c5fce55c7f clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) (build-all/bin/clang+0x8aefc7f)
#22 0x000055c5fcfd7d3e clang::ExecuteCompilerInvocation(clang::CompilerInstance*) (build-all/bin/clang+0x8c71d3e)
#23 0x000055c5f9abe8f6 cc1_main(llvm::ArrayRef<char const*>, char const*, void*) (build-all/bin/clang+0x57588f6)
#24 0x000055c5f9abb09d ExecuteCC1Tool(llvm::SmallVectorImpl<char const*>&, llvm::ToolContext const&) driver.cpp:0:0
#25 0x000055c5f9ab9de4 clang_main(int, char**, llvm::ToolContext const&) (build-all/bin/clang+0x5753de4)
#26 0x000055c5f9acb5b7 main (build-all/bin/clang+0x57655b7)
#27 0x00007f50ea916d85 __libc_start_main (/lib64/libc.so.6+0x3ad85)
#28 0x000055c5f9ab89ae _start (build-all/bin/clang+0x57529ae)
Abort (core dumped)

bbi-98084.c.gz

Edit: I tested this on main commit f1779ae.

@aengelke
Copy link
Contributor

That looks like a use-after-free of ExplodedNodes, which get reallocated while a visitor still holds a reference. When replacing the free list and allocator with standard new/delete, Valgrind complains:

==197546== Invalid read of size 8                                                                                                                                                                                                                                                                                              
==197546==    at 0x8BFCA75: getLocation (llvm-project/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h:145)                                                                                                                                                                                               
==197546==    by 0x8BFCA75: getStackFrame (llvm-project/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h:152)                                                                                                                                                                                             
==197546==    by 0x8BFCA75: (anonymous namespace)::TrackControlDependencyCondBRVisitor::VisitNode(clang::ento::ExplodedNode const*, clang::ento::BugReporterContext&, clang::ento::PathSensitiveBugReport&) (llvm-project/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp:2081)                                          
==197546==    by 0x8BE90E2: generateVisitorsDiagnostics(clang::ento::PathSensitiveBugReport*, clang::ento::ExplodedNode const*, clang::ento::BugReporterContext&) (llvm-project/clang/lib/StaticAnalyzer/Core/BugReporter.cpp:2829)                                                                                            
==197546==    by 0x8BE529B: findValidReport (llvm-project/clang/lib/StaticAnalyzer/Core/BugReporter.cpp:2870)                                                                                                                                                                                                                  
==197546==    by 0x8BE529B: clang::ento::PathSensitiveBugReporter::generatePathDiagnostics(llvm::ArrayRef<clang::ento::PathDiagnosticConsumer*>, llvm::ArrayRef<clang::ento::PathSensitiveBugReport*>&) (llvm-project/clang/lib/StaticAnalyzer/Core/BugReporter.cpp:2918)                                                      
==197546==    by 0x8BE7AE3: clang::ento::PathSensitiveBugReporter::generateDiagnosticForConsumerMap(clang::ento::BugReport*, llvm::ArrayRef<clang::ento::PathDiagnosticConsumer*>, llvm::ArrayRef<clang::ento::BugReport*>) (llvm-project/clang/lib/StaticAnalyzer/Core/BugReporter.cpp:3344)                                  
==197546==    by 0x8BE3878: clang::ento::BugReporter::FlushReport(clang::ento::BugReportEquivClass&) (llvm-project/clang/lib/StaticAnalyzer/Core/BugReporter.cpp:3116)                                                                                                                                                         
==197546==    by 0x8BE36BA: clang::ento::BugReporter::FlushReports() (llvm-project/clang/lib/StaticAnalyzer/Core/BugReporter.cpp:2501)                                                                                                                                                                                         
==197546==    by 0x90E3034: RunPathSensitiveChecks (llvm-project/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp:748)                                                                                                                                                                                                   
==197546==    by 0x90E3034: (anonymous namespace)::AnalysisConsumer::HandleCode(clang::Decl*, unsigned int, clang::ento::ExprEngine::InliningModes, llvm::DenseSet<clang::Decl const*, llvm::DenseMapInfo<clang::Decl const*, void> >*) (llvm-project/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp:699)              
==197546==    by 0x90BECB6: HandleDeclsCallGraph (llvm-project/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp:486)                                                                                                                                                                                                     
==197546==    by 0x90BECB6: runAnalysisOnTranslationUnit (llvm-project/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp:558)                                                                                                                                                                                             
==197546==    by 0x90BECB6: (anonymous namespace)::AnalysisConsumer::HandleTranslationUnit(clang::ASTContext&) (llvm-project/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp:613)                                                                                                                                       
==197546==    by 0x6358CB8: clang::ParseAST(clang::Sema&, bool, bool) (llvm-project/clang/lib/Parse/ParseAST.cpp:184)                                                                                                                                                                                                          
==197546==    by 0x8903A93: clang::FrontendAction::Execute() (llvm-project/clang/lib/Frontend/FrontendAction.cpp:1078)                                                                                                                                                                                                         
==197546==    by 0x8878A4C: clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) (llvm-project/clang/lib/Frontend/CompilerInstance.cpp:1061)                                                                                                                                                                         
==197546==    by 0x898E5D1: clang::ExecuteCompilerInvocation(clang::CompilerInstance*) (llvm-project/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp:280)                                                                                                                                                                 
==197546==  Address 0x150a4698 is 24 bytes inside a block of size 88 free'd                                                                                                                                                                                                                                                    
==197546==    at 0x484A164: operator delete(void*) (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)                                                                                                                                                                                                                
==197546==    by 0x8C5DA12: clang::ento::ExplodedGraph::reclaimRecentlyAllocatedNodes() (llvm-project/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp:184)                                                                                                                                                                     
==197546==    by 0x8C672E8: clang::ento::ExprEngine::ProcessStmt(clang::Stmt const*, clang::ento::ExplodedNode*) (llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp:1111)                                                                                                                                              
==197546==    by 0x8C6724B: clang::ento::ExprEngine::processCFGElement(clang::CFGElement, clang::ento::ExplodedNode*, unsigned int, clang::ento::NodeBuilderContext*) (llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp:976)                                                                                          
==197546==    by 0x8C4B122: clang::ento::CoreEngine::HandlePostStmt(clang::CFGBlock const*, unsigned int, clang::ento::ExplodedNode*) (llvm-project/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp:484)                                                                                                                          
==197546==    by 0x8C4A0FB: operator() (llvm-project/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp:159)                                                                        
==197546==    by 0x8C4A0FB: clang::ento::CoreEngine::ExecuteWorkList(clang::LocationContext const*, unsigned int, llvm::IntrusiveRefCntPtr<clang::ento::ProgramState const>) (llvm-project/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp:163)
==197546==    by 0x90E2F21: ExecuteWorkList (llvm-project/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h:192)                                             
==197546==    by 0x90E2F21: RunPathSensitiveChecks (llvm-project/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp:729)                                                  
==197546==    by 0x90E2F21: (anonymous namespace)::AnalysisConsumer::HandleCode(clang::Decl*, unsigned int, clang::ento::ExprEngine::InliningModes, llvm::DenseSet<clang::Decl const*, llvm::DenseMapInfo<clang::Decl const*, void> >*) (llvm-project/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp:699)
==197546==    by 0x90BECB6: HandleDeclsCallGraph (llvm-project/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp:486)                                                                                           
==197546==    by 0x90BECB6: runAnalysisOnTranslationUnit (llvm-project/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp:558)                                            
==197546==    by 0x90BECB6: (anonymous namespace)::AnalysisConsumer::HandleTranslationUnit(clang::ASTContext&) (llvm-project/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp:613)                                                                                                                                       
==197546==    by 0x6358CB8: clang::ParseAST(clang::Sema&, bool, bool) (llvm-project/clang/lib/Parse/ParseAST.cpp:184)                                                                                                                          
==197546==    by 0x8903A93: clang::FrontendAction::Execute() (llvm-project/clang/lib/Frontend/FrontendAction.cpp:1078)                                                                                               
==197546==    by 0x8878A4C: clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) (llvm-project/clang/lib/Frontend/CompilerInstance.cpp:1061)                        
==197546==    by 0x898E5D1: clang::ExecuteCompilerInvocation(clang::CompilerInstance*) (llvm-project/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp:280)                

I have absolutely no idea of when nodes should be freed (or what the code does). Tagging some people who show up in git blame -- @cheshire @tkremenek how to fix?

@cheshire
Copy link
Contributor

Haven't touched the code in 6 years, @haoNoQ should have the current contacts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

A/F: "cannot get DomTreeNode of block with different parent" after 8101d18
8 participants