Open dtzSiFive opened 2 years ago
Debugged this a little, and tried a few alternate approaches just to see what's going on. I need to step away from this for now, but in case it's useful/interesting:
One simple answer is stashing the post-order list of modules into a vector and iterating on that, no make_early_inc_range
needed. This appears to work re:valgrind/ASAN at least on the triggering input design. Good, that makes sense. here.
What was a bit more surprising is when I dropped make_early_inc_range
and manually did the same ((for auto I = po_begin(G), E= po_end(G); I != E;) { auto *X = *I++; /* .. */ }
pattern) the errors went away too...? So maybe po_iterator
doesn't work well with make_early_inc_range
? I'm not sure! More investigation/testing needed. here.
I may be missing something re:the above, please let me know :wink:, but anyway this would be good to fix! Have not observed a crash in practice from this, FWIW.
I copied the std::vector solution in https://github.com/llvm/circt/pull/3390, but I think we should leave this issue open to track down what is actually going on and see if we can find a better solution.
In this post[0] (can't wait, love the pipe syntax and views re:c++20/rangev3) it mentions a known problem with some LLVM bits, particularly mapped_iterator.
This is explained by a linked post[1] which describes a problem combining iterator with logic in operator++ with one with logic in operator*, which sure sounds like mapped_iterator and early_inc.
I think this means it'll be fixed soon-ish, perhaps with the copy-assignable PR[2] or otherwise, and if nothing else explains what we were seeing!
[0] https://discourse.llvm.org/t/rfc-extend-ranges-infrastructure-to-better-match-c-20/65377 [1] https://www.fluentcpp.com/2019/04/16/an-alternative-design-to-iterators-and-ranges-using-stdoptional/ [2] https://reviews.llvm.org/D134675
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_iteratorThe
SmallVector
ofpair
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?)