Issue 203752
Summary [mlir][linalg] SEGFAULT in --linalg-fuse-elementwise-ops: nullptr deref in deduplicateOperandsAndRemoveDeadResults
Labels mlir
Assignees
Reporter Kiritobl
    ### [MLIR][Linalg] SEGFAULT in mlir::RewriterBase::replaceAllUsesWith during linalg-fuse-elementwise-ops

#### Bug Description
`mlir-opt --linalg-fuse-elementwise-ops` crashes with a **Segmentation Fault (SEGFAULT)** when processing nested `linalg.generic` operations where the inner generic's `linalg.yield` returns the **outer** generic's block argument instead of its own.

#### Crash Chain & Root Cause
**Location**: `mlir/lib/Dialect/Linalg/Transforms/EraseUnusedOperandsAndResults.cpp`

When all operands of a `linalg.generic` are dead, the `replacements` vector in `populateOpPayload()` keeps `nullptr` entries for the removed operands. `mergeBlocks` → `inlineBlockBefore` subsequently invokes `replaceAllUsesWith(blockArg, nullptr)`. This causes a null-pointer dereference because the `assert(newValue)` guard is compiled out in release builds.

```
deduplicateOperandsAndRemoveDeadResults()
  → inlineBlockBefore()
    → replaceAllUsesWith(blockArg, nullptr)   // SEGFAULT here
```

#### Steps to Reproduce
Run the following command with the provided reproducer MLIR:
```bash
mlir-opt --linalg-fuse-elementwise-ops reproducer.mlir
```

#### Reproducer (`reproducer.mlir`)
```mlir
#map_2d = affine_map<(d0, d1) -> (d0, d1)>
#map_2d_to_1d = affine_map<(d0, d1) -> (d0)>
#map_1d = affine_map<(d0) -> (d0)>

func.func @linalg_fuse_crash() {
  %cst_out = arith.constant dense<[1, 2, 3]> : tensor<3xi32>
  %cst_in  = arith.constant dense<[[1, 2], [3, 4], [5, 6]]> : tensor<3x2xi32>
  %cst_1d  = arith.constant dense<[1, 2, 3]> : tensor<3xi32>
  %c0      = arith.constant 0 : index
  %false   = arith.constant false
  %c42     = arith.constant 42 : i32
  %alloc   = memref.alloc() : memref<5x5x3xi1>

  %result = linalg.generic {
    indexing_maps = [#map_2d, #map_2d_to_1d],
    iterator_types = ["parallel", "reduction"]
  } ins(%cst_in : tensor<3x2xi32>) outs(%cst_out : tensor<3xi32>) {
  ^bb0(%in: i32, %out: i32):
    %inner = linalg.generic {
      indexing_maps = [#map_1d, #map_1d],
      iterator_types = ["parallel"]
    } ins(%cst_1d : tensor<3xi32>) outs(%cst_1d : tensor<3xi32>) {
    ^bb0(%in_inner: i32, %out_inner: i32):
      // Side effect makes hasPureTensorSemantics return false
      memref.store %false, %alloc[%c0, %c0, %c0] : memref<5x5x3xi1>
      // CRITICAL: yields OUTER %out instead of inner %out_inner
      linalg.yield %out : i32
    } -> tensor<3xi32>
    // Returns constant → all outer inputs are dead
    linalg.yield %c42 : i32
  } -> tensor<3xi32>

  return
}
```

#### Stack Dump
```text
Stack dump:
0.	Program arguments: mlir-opt --linalg-fuse-elementwise-ops reproducer.mlir
#0 0x00006190d4ac6518 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (mlir-opt+0x1f8c518)
#1 0x00006190d4ac33b5 llvm::sys::RunSignalHandlers() (mlir-opt+0x1f893b5)
#2 0x00006190d4ac7641 SignalHandler(int, siginfo_t*, void*) Signals.cpp:0:0
#3 0x00007eaf2f042520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
#4 0x00006190d4b902b0 mlir::RewriterBase::replaceAllUsesWith(mlir::Value, mlir::Value) (mlir-opt+0x20562b0)
#5 0x00006190dd24272a mlir::RewriterBase::inlineBlockBefore(mlir::Block*, mlir::Block*, llvm::ilist_iterator<llvm::ilist_detail::node_options<mlir::Operation, true, false, void, false, void>, false, false>, mlir::ValueRange) (mlir-opt+0xa70872a)
#6 0x00006190da7fca4b mlir::linalg::deduplicateOperandsAndRemoveDeadResults(mlir::RewriterBase&, mlir::linalg::GenericOp, bool) (mlir-opt+0x7cc2a4b)
#7 0x00006190da7fef09 (anonymous namespace)::DeduplicateAndRemoveDeadOperandsAndResults::matchAndRewrite(mlir::linalg::GenericOp, mlir::PatternRewriter&) const EraseUnusedOperandsAndResults.cpp:0:0
#8 0x00006190dcec7bc3 void llvm::function_ref<void ()>::callback_fn<mlir::PatternApplicator::matchAndRewrite(mlir::Operation*, mlir::PatternRewriter&, llvm::function_ref<bool (mlir::Pattern const&)>, llvm::function_ref<void (mlir::Pattern const&)>, llvm::function_ref<llvm::LogicalResult (mlir::Pattern const&)>)::$_0>(long) PatternApplicator.cpp:0:0
#9 0x00006190dcec441a mlir::PatternApplicator::matchAndRewrite(mlir::Operation*, mlir::PatternRewriter&, llvm::function_ref<bool (mlir::Pattern const&)>, llvm::function_ref<void (mlir::Pattern const&)>, llvm::function_ref<llvm::LogicalResult (mlir::Pattern const&)>) (mlir-opt+0xa38a41a)
#10 0x00006190dce9c296 (anonymous namespace)::GreedyPatternRewriteDriver::processWorklist() GreedyPatternRewriteDriver.cpp:0:0
#11 0x00006190dce9b392 void llvm::function_ref<void ()>::callback_fn<(anonymous namespace)::RegionPatternRewriteDriver::simplify(bool*) &&::$_2>(long) GreedyPatternRewriteDriver.cpp:0:0
#12 0x00006190dce983b5 mlir::applyPatternsGreedily(mlir::Region&, mlir::FrozenRewritePatternSet const&, mlir::GreedyRewriteConfig, bool*) (mlir-opt+0xa35e3b5)
#13 0x00006190da7ec605 (anonymous namespace)::LinalgElementwiseOpFusionPass::runOnOperation() ElementwiseOpFusion.cpp:0:0
#14 0x00006190dcf259c8 mlir::detail::OpToOpPassAdaptor::run(mlir::Pass*, mlir::Operation*, mlir::AnalysisManager, bool, unsigned int) (mlir-opt+0xa3eb9c8)
#15 0x00006190dcf267a4 mlir::detail::OpToOpPassAdaptor::runPipeline(mlir::OpPassManager&, mlir::Operation*, mlir::AnalysisManager, bool, unsigned int, mlir::PassInstrumentor*, mlir::PassInstrumentation::PipelineParentInfo const*) (mlir-opt+0xa3ec7a4)
#16 0x00006190dcf2db32 mlir::PassManager::runPasses(mlir::Operation*, mlir::AnalysisManager) (mlir-opt+0xa3f3b32)
#17 0x00006190dcf2d20a mlir::PassManager::run(mlir::Operation*) (mlir-opt+0xa3f320a)
...
Segmentation fault (core dumped)
```
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to