llvm / llvm/circt

Dedup iterator invalidation bug

Open
#3,387 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C++
Stars
2.2k
Forks
524
Avg merge
3d 2h
Merged PRs (30d)
46

Description

## Summary

Dedup pass appears to still have a safety issue re:early-inc/post-order iterators over a mutated instance graph.

Ran into this using a recent (post-1.4.0) firtool, reported by ASAN.

## Details

ASAN report

```
=================================================================
==830554==ERROR: AddressSanitizer: heap-use-after-free on address 0x61600014c2a0 at pc 0x000001255169 bp 0x7ffd1e196e90 sp 0x7ffd1e196e88
READ of size 8 at 0x61600014c2a0 thread T0
#0 0x1255168 in (anonymous namespace)::DedupPass::runOnOperation() /home/will/src/sifive/circt/lib/Dialect/FIRRTL/Transforms/Dedup.cpp:1190:21
#1 0x228db02 in mlir::detail::OpToOpPassAdaptor::run(mlir::Pass*, mlir::Operation*, mlir::AnalysisManager, bool, unsigned int) /home/will/src/sifive/circt/llvm/mlir/lib/Pass/Pass.cpp:470:11
#2 0x228f2b3 in mlir::detail::OpToOpPassAdaptor::runPipeline(mlir::OpPassManager&, mlir::Operation*, mlir::AnalysisManager, bool, unsigned int, mlir::PassInstrumentor*, mlir::PassInstrumentation::PipelineParentInfo const*) /home/will/src/sifive/circt/llvm/mlir/lib/Pass/Pass.cpp:534:16
#3 0x22a22af in mlir::detail::OpToOpPassAdaptor::runOnOperationAsyncImpl(bool)::$_12::operator()(mlir::detail::OpToOpPassAdaptor::runOnOperationAsyncImpl(bool)::OpPMInfo&) const /home/will/src/sifive/circt/llvm/mlir/lib/Pass/Pass.cpp:754:36
#4 0x22924e2 in failableParallelForEach<__gnu_cxx::__normal_iterator > >, (lambda at /home/will/src/sifive/circt/llvm/mlir/lib/Pass/Pass.cpp:744:20) &> /home/will/src/sifive/circt/llvm/mlir/include/mlir/IR/Threading.h:46:18
#5 0x22924e2 in failableParallelForEach > &, (lambda at /home/will/src/sifive/circt/llvm/mlir/lib/Pass/Pass.cpp:744:20) &> /home/will/src/sifive/circt/llvm/mlir/include/mlir/IR/Threading.h:92:10
#6 0x22924e2 in mlir::detail::OpToOpPassAdaptor::runOnOperationAsyncImpl(bool) /home/will/src/sifive/circt/llvm/mlir/lib/Pass/Pass.cpp:764:14
#7 0x228de03 in runOnOperation /home/will/src/sifive/circt/llvm/mlir/lib/Pass/Pass.cpp:655:5
#8 0x228de03 in mlir::detail::OpToOpPassAdaptor::run(mlir::Pass*, mlir::Operation*, mlir::AnalysisManager, bool, unsigned int) /home/will/src/sifive/circt/llvm/mlir/lib/Pass/Pass.cpp:468:14
#9 0x228f2b3 in mlir::detail::OpToOpPassAdaptor::runPipeline(mlir::OpPassManager&, mlir::Operation*, mlir::AnalysisManager, bool, unsigned int, mlir::PassInstrumentor*, mlir::PassInstrumentation::PipelineParentInfo const*) /home/will/src/sifive/circt/llvm/mlir/lib/Pass/Pass.cpp:534:16
#10 0x2295522 in runPasses /home/will/src/sifive/circt/llvm/mlir/lib/Pass/Pass.cpp:837:10
#11 0x2295522 in mlir::PassManager::run(mlir::Operation*) /home/will/src/sifive/circt/llvm/mlir/lib/Pass/Pass.cpp:817:60
#12 0xdb6bf6 in processBuffer(mlir::MLIRContext&, mlir::TimingScope&, llvm::SourceMgr&, llvm::Optional > >&) /home/will/src/sifive/circt/tools/firtool/firtool.cpp:624:17
#13 0xdb3cba in processInputSplit(mlir::MLIRContext&, mlir::TimingScope&, std::unique_ptr >, llvm::Optional > >&) /home/will/src/sifive/circt/tools/firtool/firtool.cpp:714:12
#14 0xdb388e in processInput(mlir::MLIRContext&, mlir::TimingScope&, std::unique_ptr >, llvm::Optional > >&) /home/will/src/sifive/circt/tools/firtool/firtool.cpp:730:12
#15 0xdb34f4 in executeFirtool(mlir::MLIRContext&) /home/will/src/sifive/circt/tools/firtool/firtool.cpp:811:14
#16 0xdb2bed in main /home/will/src/sifive/circt/tools/firtool/firtool.cpp:846:17
#17 0x7f0a01f6b236 in __libc_start_call_main (/nix/store/lyl6nysc3i3aqhj6shizjgj0ibnf1pvg-glibc-2.34-210/lib/libc.so.6+0x29236) (BuildId: c512f38583c48b03cc0011d4583d15cea2e94d03)
#18 0x7f0a01f6b2f4 in __libc_start_main@GLIBC_2.2.5 (/nix/store/lyl6nysc3i3aqhj6shizjgj0ibnf1pvg-glibc-2.34-210/lib/libc.so.6+0x292f4) (BuildId: c512f38583c48b03cc0011d4583d15cea2e94d03)
#19 0xcbbf70 in _start /build/glibc-2.34/csu/../sysdeps/x86_64/start.S:116

0x61600014c2a0 is located 288 bytes inside of 544-byte region [0x61600014c180,0x61600014c3a0)
freed by thread T0 here:
LLVMSymbolizer: error reading file: No such file or directory
#0 0xd6b597 in __interceptor_free.part.0 static-reloc.c
#1 0x125ac5a in llvm::po_iterator, false, llvm::GraphTraits >::~po_iterator() /home/will/src/sifive/circt/llvm/llvm/include/llvm/ADT/PostOrderIterator.h:96:7
#2 0x125ac5a in llvm::early_inc_iterator_impl, false, llvm::GraphTraits > >::operator*() /home/will/src/sifive/circt/llvm/llvm/include/llvm/ADT/STLExtras.h:573:5
#3 0x125490e in (anonymous namespace)::DedupPass::runOnOperation() /home/will/src/sifive/circt/lib/Dialect/FIRRTL/Transforms/Dedup.cpp:1190:21
#4 0x228db02 in mlir::detail::OpToOpPassAdaptor::run(mlir::Pass*, mlir::Operation*, mlir::AnalysisManager, bool, unsigned int) /home/will/src/sifive/circt/llvm/mlir/lib/Pass/Pass.cpp:470:11
#5 0x228f2b3 in mlir::detail::OpToOpPassAdaptor::runPipeline(mlir::OpPassManager&, mlir::Operation*, mlir::AnalysisManager, bool, unsigned int, mlir::PassInstrumentor*, mlir::PassInstrumentation::PipelineParentInfo const*) /home/will/src/sifive/circt/llvm/mlir/lib/Pass/Pass.cpp:534:16
#6 0x22a22af in mlir::detail::OpToOpPassAdaptor::runOnOperationAsyncImpl(bool)::$_12::operator()(mlir::detail::OpToOpPassAdaptor::runOnOperationAsyncImpl(bool)::OpPMInfo&) const /home/will/src/sifive/circt/llvm/mlir/lib/Pass/Pass.cpp:754:36
#7 0x22924e2 in failableParallelForEach<__gnu_cxx::__normal_iterator > >, (lambda at /home/will/src/sifive/circt/llvm/mlir/lib/Pass/Pass.cpp:744:20) &> /home/will/src/sifive/circt/llvm/mlir/include/mlir/IR/Threading.h:46:18
#8 0x22924e2 in failableParallelForEach > &, (lambda at /home/will/src/sifive/circt/llvm/mlir/lib/Pass/Pass.cpp:744:20) &> /home/will/src/sifive/circt/llvm/mlir/include/mlir/IR/Threading.h:92:10
#9 0x22924e2 in mlir::detail::OpToOpPassAdaptor::runOnOperationAsyncImpl(bool) /home/will/src/sifive/circt/llvm/mlir/lib/Pass/Pass.cpp:764:14
#10 0x228de03 in runOnOperation /home/will/src/sifive/circt/llvm/mlir/lib/Pass/Pass.cpp:655:5
#11 0x228de03 in mlir::detail::OpToOpPassAdaptor::run(mlir::Pass*, mlir::Operation*, mlir::AnalysisManager, bool, unsigned int) /home/will/src/sifive/circt/llvm/mlir/lib/Pass/Pass.cpp:468:14
#12 0x228f2b3 in mlir::detail::OpToOpPassAdaptor::runPipeline(mlir::OpPassManager&, mlir::Operation*, mlir::AnalysisManager, bool, unsigned int, mlir::PassInstrumentor*, mlir::PassInstrumentation::PipelineParentInfo const*) /home/will/src/sifive/circt/llvm/mlir/lib/Pass/Pass.cpp:534:16
#13 0x2295522 in runPasses /home/will/src/sifive/circt/llvm/mlir/lib/Pass/Pass.cpp:837:10
#14 0x2295522 in mlir::PassManager::run(mlir::Operation*) /home/will/src/sifive/circt/llvm/mlir/lib/Pass/Pass.cpp:817:60
#15 0xdb6bf6 in processBuffer(mlir::MLIRContext&, mlir::TimingScope&, llvm::SourceMgr&, llvm::Optional > >&) /home/will/src/sifive/circt/tools/firtool/firtool.cpp:624:17
#16 0xdb3cba in processInputSplit(mlir::MLIRContext&, mlir::TimingScope&, std::unique_ptr >, llvm::Optional > >&) /home/will/src/sifive/circt/tools/firtool/firtool.cpp:714:12
#17 0xdb388e in processInput(mlir::MLIRContext&, mlir::TimingScope&, std::unique_ptr >, llvm::Optional > >&) /home/will/src/sifive/circt/tools/firtool/firtool.cpp:730:12
#18 0xdb34f4 in executeFirtool(mlir::MLIRContext&) /home/will/src/sifive/circt/tools/firtool/firtool.cpp:811:14
#19 0xdb2bed in main /home/will/src/sifive/circt/tools/firtool/firtool.cpp:846:17
#20 0x7f0a01f6b236 in __libc_start_call_main (/nix/store/lyl6nysc3i3aqhj6shizjgj0ibnf1pvg-glibc-2.34-210/lib/libc.so.6+0x29236) (BuildId: c512f38583c48b03cc0011d4583d15cea2e94d03)
#21 0x7ffd1e19b8e5 ([stack]+0x428e5)

previously allocated by thread T0 here:
#0 0xd6c49f in malloc (/home/will/src/sifive/circt/build-asan/bin/firtool+0xd6c49f)
#1 0xe3a545 in safe_malloc /home/will/src/sifive/circt/llvm/llvm/include/llvm/Support/MemAlloc.h:26:18
#2 0xe3a545 in llvm::SmallVectorBase::grow_pod(void*, unsigned long, unsigned long) /home/will/src/sifive/circt/llvm/llvm/lib/Support/SmallVector.cpp:126:15
#3 0x1209a03 in llvm::SmallVectorTemplateCommon, false, false> >, circt::hw::InstanceGraphNode* (*)(circt::hw::InstanceRecord const*), circt::hw::InstanceGraphNode*> >, void>::grow_pod(unsigned long, unsigned long) /home/will/src/sifive/circt/llvm/llvm/include/llvm/ADT/SmallVector.h:120:11
#4 0x1209a03 in llvm::SmallVectorTemplateBase, false, false> >, circt::hw::InstanceGraphNode* (*)(circt::hw::InstanceRecord const*), circt::hw::InstanceGraphNode*> >, true>::grow(unsigned long) /home/will/src/sifive/circt/llvm/llvm/include/llvm/ADT/SmallVector.h:506:41
#5 0x1209a03 in llvm::SmallVectorImpl, false, false> >, circt::hw::InstanceGraphNode* (*)(circt::hw::InstanceRecord const*), circt::hw::InstanceGraphNode*> > >::operator=(llvm::SmallVectorImpl, false, false> >, circt::hw::InstanceGraphNode* (*)(circt::hw::InstanceRecord const*), circt::hw::InstanceGraphNode*> > > const&) /home/will/src/sifive/circt/llvm/llvm/include/llvm/ADT/SmallVector.h:1026:11
#6 0x125ac3e in llvm::po_iterator, false, llvm::GraphTraits >::operator++(int) /home/will/src/sifive/circt/llvm/llvm/include/llvm/ADT/PostOrderIterator.h:176:23
#7 0x125ac3e in llvm::early_inc_iterator_impl, false, llvm::GraphTraits > >::operator*() /home/will/src/sifive/circt/llvm/llvm/include/llvm/ADT/STLExtras.h:573:13
#8 0x125490e in (anonymous namespace)::DedupPass::runOnOperation() /home/will/src/sifive/circt/lib/Dialect/FIRRTL/Transforms/Dedup.cpp:1190:21
#9 0x228db02 in mlir::detail::OpToOpPassAdaptor::run(mlir::Pass*, mlir::Operation*, mlir::AnalysisManager, bool, unsigned int) /home/will/src/sifive/circt/llvm/mlir/lib/Pass/Pass.cpp:470:11
#10 0x228f2b3 in mlir::detail::OpToOpPassAdaptor::runPipeline(mlir::OpPassManager&, mlir::Operation*, mlir::AnalysisManager, bool, unsigned int, mlir::PassInstrumentor*, mlir::PassInstrumentation::PipelineParentInfo const*) /home/will/src/sifive/circt/llvm/mlir/lib/Pass/Pass.cpp:534:16
#11 0x22a22af in mlir::detail::OpToOpPassAdaptor::runOnOperationAsyncImpl(bool)::$_12::operator()(mlir::detail::OpToOpPassAdaptor::runOnOperationAsyncImpl(bool)::OpPMInfo&) const /home/will/src/sifive/circt/llvm/mlir/lib/Pass/Pass.cpp:754:36
#12 0x22924e2 in failableParallelForEach<__gnu_cxx::__normal_iterator > >, (lambda at /home/will/src/sifive/circt/llvm/mlir/lib/Pass/Pass.cpp:744:20) &> /home/will/src/sifive/circt/llvm/mlir/include/mlir/IR/Threading.h:46:18
#13 0x22924e2 in failableParallelForEach > &, (lambda at /home/will/src/sifive/circt/llvm/mlir/lib/Pass/Pass.cpp:744:20) &> /home/will/src/sifive/circt/llvm/mlir/include/mlir/IR/Threading.h:92:10
#14 0x22924e2 in mlir::detail::OpToOpPassAdaptor::runOnOperationAsyncImpl(bool) /home/will/src/sifive/circt/llvm/mlir/lib/Pass/Pass.cpp:764:14
#15 0x228de03 in runOnOperation /home/will/src/sifive/circt/llvm/mlir/lib/Pass/Pass.cpp:655:5
#16 0x228de03 in mlir::detail::OpToOpPassAdaptor::run(mlir::Pass*, mlir::Operation*, mlir::AnalysisManager, bool, unsigned int) /home/will/src/sifive/circt/llvm/mlir/lib/Pass/Pass.cpp:468:14
#17 0x228f2b3 in mlir::detail::OpToOpPassAdaptor::runPipeline(mlir::OpPassManager&, mlir::Operation*, mlir::AnalysisManager, bool, unsigned int, mlir::PassInstrumentor*, mlir::PassInstrumentation::PipelineParentInfo const*) /home/will/src/sifive/circt/llvm/mlir/lib/Pass/Pass.cpp:534:16
#18 0x2295522 in runPasses /home/will/src/sifive/circt/llvm/mlir/lib/Pass/Pass.cpp:837:10
#19 0x2295522 in mlir::PassManager::run(mlir::Operation*) /home/will/src/sifive/circt/llvm/mlir/lib/Pass/Pass.cpp:817:60
#20 0xdb6bf6 in processBuffer(mlir::MLIRContext&, mlir::TimingScope&, llvm::SourceMgr&, llvm::Optional > >&) /home/will/src/sifive/circt/tools/firtool/firtool.cpp:624:17
#21 0xdb3cba in processInputSplit(mlir::MLIRContext&, mlir::TimingScope&, std::unique_ptr >, llvm::Optional > >&) /home/will/src/sifive/circt/tools/firtool/firtool.cpp:714:12
#22 0xdb388e in processInput(mlir::MLIRContext&, mlir::TimingScope&, std::unique_ptr >, llvm::Optional > >&) /home/will/src/sifive/circt/tools/firtool/firtool.cpp:730:12
#23 0xdb34f4 in executeFirtool(mlir::MLIRContext&) /home/will/src/sifive/circt/tools/firtool/firtool.cpp:811:14
#24 0xdb2bed in main /home/will/src/sifive/circt/tools/firtool/firtool.cpp:846:17
#25 0x7f0a01f6b236 in __libc_start_call_main (/nix/store/lyl6nysc3i3aqhj6shizjgj0ibnf1pvg-glibc-2.34-210/lib/libc.so.6+0x29236) (BuildId: c512f38583c48b03cc0011d4583d15cea2e94d03)
#26 0x7ffd1e19b8e5 ([stack]+0x428e5)
```

The `SmallVector` of `pair`s looks to be the visit stack stored in post-order iterators.

So it looks like the post-order iterator's state -- despite (because of?) `make_early_inc_range` wrapping it-- does not work well when mutating the underlying graph. (Would external storage would help?)

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in lib/Dialect/FIRRTL/Transforms/Dedup.cpp at line 1190, using the supplied ASAN trace to inspect the DedupPass traversal and its early-increment/post-order iterator behavior. Reproduce the report with firtool and confirm the dedup pass no longer produces the reported heap-use-after-free under ASAN.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.