Skip to content

Fix use-after-free in rock-linalg-align to avoid app crash when enable debug logging - #2465

Open
kazhang2 wants to merge 1 commit into
ROCm:developfrom
kazhang2:fix-use-after-free-in-rock-linalg-align
Open

kazhang2 wants to merge 1 commit into
ROCm:developfrom
kazhang2:fix-use-after-free-in-rock-linalg-align

Conversation

@kazhang2

@kazhang2 kazhang2 commented Sep 17, 2026 •

Copy link
Copy Markdown

Motivation

The LinalgAlignRewriter::drainWorklist logging callbacks print the matched operation's name via op->getName(). The MemcpyRewritePattern::matchAndRewrite erase their root operation before returning success, so the success callback dereferences freed memory and crashes with an access violation (0xC0000005) inside OperationName::Impl::getName when the pass runs with -debug-only=rock-linalg-align.

Technical Details

The three logging callbacks passed to PatternApplicator::matchAndRewrite (canApply, onFailure, onSuccess) print the matched operation via op->getName(). The memcpy and reduction rewrite patterns erase their root operation (eraseOp) in MemcpyRewritePattern::matchAndRewrite

b.eraseOp(copy);
return success();
}
before returning success. When onSuccess then runs and calls op->getName(), it reads freed memory. This is only reachable in #ifndef NDEBUG builds with the debug flag set; without the flag the buggy logging never executes and the pass works correctly, which is why it went unnoticed.

Observed in practice when MIGraphX (migraphx_gpu.dll) compiles an ONNX model with ROCMLIR_DEBUG_FLAGS=--debug-only=rock-linalg-align: the process dies mid-log-line at Matched ... MemcpyRewritePattern pattern on ..., right after
** Erase : "memref.copy".

Test Plan

reproduce step
run in powershell
@'
module {
func.func @repro(%output: memref<1xf32>) attributes {rock.kernel} {
%zero = arith.constant 0.0 : f32
%regs = rock.alloc() : memref<1xf32, #gpu.address_space>
rock.fill(%regs, %zero) : memref<1xf32, #gpu.address_space>, f32
%tmp = memref.alloc() : memref<1xf32>
rock.threadwise_write_all {forceUnroll, useIndexDiffs}
%regs -> by set
: memref<1xf32, #gpu.address_space> -> memref<1xf32>
memref.copy %tmp, %output : memref<1xf32> to memref<1xf32>
return
}
}
'@ | & .\build\bin\rocmlir-opt.exe --rock-linalg-align --debug-only=rock-linalg-align

Test Result

rocmlir-opt.exe --rock-linalg-align --debug-only=rock-linalg-align
pass

Submission Checklist

The LinalgAlignRewriter::drainWorklist logging callbacks print the
matched operation's name via op->getName(). The memcpy and reduction
rewrite patterns erase their root operation before returning success,
so the success callback dereferences freed memory and crashes with an
access violation (0xC0000005) inside OperationName::Impl::getName when
the pass runs with -debug-only=rock-linalg-align.

Snapshot the OperationName before applying the pattern and print from
the copy; OperationName does not reference the erased operation's
storage.

Adds a regression test that erases a memref.copy through the align
pass with debug logging enabled. Originally hit via MIGraphX
(migraphx_gpu.dll) compiling an ONNX model with
ROCMLIR_DEBUG_FLAGS=--debug-only=rock-linalg-align, then minimized to
a single rock.fill / threadwise_write_all / memref.copy function.

Signed-off-by: kazhang2 <kazhang2@amd.com>
@kazhang2
kazhang2 requested a review from causten as a code owner September 17, 2026 08:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant