Summary
The MLIR inliner crashes with an assertion failure when processing a func.func that has no return terminator and contains an unregistered op with a region. The assertion fires in walkReferencedSymbolNodes during call graph construction.
Assertion
mlir-opt: mlir/lib/Transforms/Utils/Inliner.cpp:42:
void walkReferencedSymbolNodes(...):
Assertion `symbolUses && "expected uses to be valid"' failed.
Minimal Reproducer
File (min.mlir):
module {
func.func @f() {
"a.b"() ({}) : () -> ()
}
}
Command:
mlir-opt --allow-unregistered-dialect --inline min.mlir
Stack Trace (key frames)
#9 walkReferencedSymbolNodes(...) Inliner.cpp:62
#12 CGUseList::recomputeUses(...) Inliner.cpp:233
#13 CGUseList(...) Inliner.cpp:159
#14 mlir::Inliner::doInlining() Inliner.cpp:759
#15 InlinerPass::runOnOperation() InlinerPass.cpp:152
Analysis
The inliner calls SymbolTable::getSymbolUses() on the parent region of an operation during call graph construction. When a func.func has no terminator (not caught by a verifier pass beforehand because --allow-unregistered-dialect relaxes verification), the function body is malformed in a way that causes getSymbolUses() to return std::nullopt — indicating the symbol table is not analyzable for that scope. The assertion on the returned value then fires unconditionally rather than handling the failure gracefully.
The inliner should either (a) guard against std::nullopt from getSymbolUses() and emit a diagnostic instead of asserting, or (b) run the verifier before the inliner to reject malformed inputs early.
Environment
- MLIR from
llvm-project (see build at projects/mlir/llvm-mlir-build)
- Triggered with
--allow-unregistered-dialect --inline
- Also triggered with the full pass pipeline:
--allow-unregistered-dialect --inline --loop-invariant-code-motion --cse --canonicalize --symbol-dce --sccp --verify-each
This bug was found by fusion-fuzz
Summary
The MLIR inliner crashes with an assertion failure when processing a
func.functhat has no return terminator and contains an unregistered op with a region. The assertion fires inwalkReferencedSymbolNodesduring call graph construction.Assertion
Minimal Reproducer
File (
min.mlir):Command:
Stack Trace (key frames)
Analysis
The inliner calls
SymbolTable::getSymbolUses()on the parent region of an operation during call graph construction. When afunc.funchas no terminator (not caught by a verifier pass beforehand because--allow-unregistered-dialectrelaxes verification), the function body is malformed in a way that causesgetSymbolUses()to returnstd::nullopt— indicating the symbol table is not analyzable for that scope. The assertion on the returned value then fires unconditionally rather than handling the failure gracefully.The inliner should either (a) guard against
std::nulloptfromgetSymbolUses()and emit a diagnostic instead of asserting, or (b) run the verifier before the inliner to reject malformed inputs early.Environment
llvm-project(see build atprojects/mlir/llvm-mlir-build)--allow-unregistered-dialect --inline--allow-unregistered-dialect --inline --loop-invariant-code-motion --cse --canonicalize --symbol-dce --sccp --verify-eachThis bug was found by fusion-fuzz