Background
I was setting up a fine-tuning pipeline for Foundation-Sec-8B on a Windows 11 machine with an RX 9070 XT using ROCm 7.14. The stack: PyTorch 2.12.0+rocm7.14.0, PEFT, standard HuggingFace Transformers. GPU correctly detected, VRAM visible, torch.cuda.is_available() returned True.
The first sign was the crash output in the terminal itself — the process printed a memory address alongside 0xC0000005 before dying. No Python exception was raised, no traceback. Just a raw AV and an exit.
This is the analysis of what caused it, what the wrong fix looked like, and the correct patch.
Environment
| GPU | AMD Radeon RX 9070 XT (gfx1201, RDNA 4) |
| OS | Windows 11 (build 26100) |
| ROCm | 7.14.0 (torch.version.hip = 7.14.60850) |
| PyTorch | 2.12.0+rocm7.14.0 |
| Driver | Adrenalin 32.0.31041.1004 |
| Issue | ROCm/TheRock #7732 |
Reproducing the Crash
Any operation dispatching a HIP kernel crashes immediately:
|
|
No exception is raised. The Python process exits with 0xC0000005.
WinDbg Analysis
Standard crash dump analysis shows the process is already dead at exit. To catch the access violation at its origin, attach WinDbg with child process tracking and break on first-chance AV:
windbg -o -G rocm_env\Scripts\python.exe finetune.py
At the initial break:
sxe av
g
The process breaks mid-execution with:
(1820.1f1c): Access violation - code c0000005 (first chance)
amdhip64_7!hipProfilerRegisterChunkCallbackExt+0x5c257:
00007ffd`4bf08bb7 mov rax, qword ptr [rcx+8]
r gives:
rcx = 7b2c450fc892ac84 ← not null — garbage pointer
rip = 00007ffd4bf08bb7
~* kn on thread 9:
# 00 amdhip64_7!hipProfilerRegisterChunkCallbackExt+0x5c257
# 01 amdhip64_7!hipRegisterTracerCallback+0x14a0e8
# 02 amdhip64_7!hipRegisterTracerCallback+0x135c16
# 03 amdhip64_7!hipRegisterTracerCallback+0x120ece
# 04 amdhip64_7!hipRegisterTracerCallback+0x10c296
# 05 amdhip64_7!hipRegisterTracerCallback+0xf93ce
# 06 amdhip64_7!hipLaunchKernel+0x88
# 07 torch_hip!at::native::...
The call chain: hipLaunchKernel+0x85 dispatches into the ROCprofiler callback registry. The registry walks a linked list. One node contains rcx = 7b2c450fc892ac84 — a garbage, non-null pointer. Dereferencing [rcx+8] produces the AV.
Root Cause
hipLaunchKernel calls into the ROCprofiler callback notification chain on every kernel dispatch via an indirect call at +0x85:
|
|
r10 holds a function pointer to the callback notification wrapper. Inside that chain, hipProfilerRegisterChunkCallbackExt walks a linked list of registered profiler callbacks. On Windows gfx1201, this list contains an uninitialized or corrupted node — likely a race condition during runtime initialization on first kernel dispatch.
The linked list walk:
|
|
First Patch — Wrong
The obvious fix: NOP out the call r10 at hipLaunchKernel+0x85.
File offset 0x4549B5:
Before: 41 FF D2 (call r10)
After: 90 90 90 (NOP)
The crash stopped. Training appeared to run. GPU showed 100% compute in Task Manager.
But something was wrong. Checking model weights after loading:
|
|
Every tensor transferred to GPU was zero:
|
|
The NOP stopped the crash but also prevented actual kernel execution. Looking at the context after the patched call:
|
|
Without the call r10, execution falls through to jmp +4 which jumps directly to the function epilogue. hipLaunchKernel returns without ever dispatching the kernel. GPU memory allocations succeed (DMA path), but all compute kernels are silently skipped — leaving tensors at their initial zero state.
Loss during training: 0.000, nan, -8.5e+36. The model was “training” on all-zero tensors.
Correct Patch
Instead of patching the call site in hipLaunchKernel, patch the crashing function itself. hipProfilerRegisterChunkCallbackExt is a callback lookup — it should return 0 (not found) when the list is invalid. Making it immediately return 0 is safe: the profiler system simply finds no registered callbacks and skips notification. Kernel dispatch proceeds normally.
Locate the export via the PE export table:
hipProfilerRegisterChunkCallbackExt RVA=0x4BC960 FileOffset=0x4BBD60
Patch the function prologue:
File offset 0x4BBD60:
Before: 48 89 5c ... (push rbx; function prologue)
After: 33 c0 c3 (xor eax, eax; ret → return 0)
Verification:
|
|
Patch Script
GitHub: JM00NJ/amdhip64-hipLaunchKernel-crash-fix
The script locates hipProfilerRegisterChunkCallbackExt dynamically via the PE export table (no hardcoded offset dependency), creates a backup, and reverts the old wrong patch automatically if present.
|
|
Fine-Tuning Script
With the patch applied, standard BF16 training works. The script below fine-tunes Foundation-Sec-8B with LoRA. Modify the variables at the top for your setup — everything else can stay as-is.
|
|
Notes
- Re-run the patcher after ROCm updates — the DLL will be overwritten
- The patch disables ROCprofiler tracing.
rocprofwill not intercept HIP API calls on the patched binary. For profiling, wait for the upstream fix - Reported to AMD: ROCm/TheRock#7732, ROCm/rocm-systems#10924