[Crash] Access violation in guest thread OptimizeChangeBanc (read guest 0x4) while playing, RTX 2060 6 GB #287

Closed
opened 2026-11-07 19:04:38 +00:00 by NaviySk8 · 10 comments
NaviySk8 commented 2026-11-07 19:04:38 +00:00 (Migrated from github.com)

hookshot_log.txt

Build: less-stutter release (HookshotBuilder.zip sha256 03f23d9f…0296), built from the command line over an earlier small-vram build with the same .nup. Game: 0400486024DEC000, v131072, build e0f3ccfa (--check OK).

PC: Ryzen 5 3600, RTX 2060 6 GB (Turing), driver 621.14, 32 GB RAM, Windows 11 Pro (build 26300).

Settings: hookshot_env.txt: RX_VK_ROBUST=1, RX_VK_VRAM_MB=2560. In-game menu: frame generation 2x, resolution 67%, game speed real time, FPS counter on.

What happened: About 13,700 frames into the session, while walking from Kakariko Village toward the castle (Hyrule Field to Castle Town), the game closed. The GPU did not reset this time: there is no "device lost" in the log and no nvlddmkm event at that time. The crash is in a guest thread:

[hos OptimizeChangeBanc] CRASH: exception 0xc0000005 (read 0x100000000004, guest 0x4) at hookshot.exe+0x1910366d
[hos OptimizeChangeBanc] CRASH: host backtrace: hookshot.exe+0x1910366d
[hos OptimizeChangeBanc] CRASH: thread OptimizeChangeBanc, sp 0x105a69eae0
[hos OptimizeChangeBanc] CRASH:   x0  0000000000000000  x1  000000105a69eae0  x2  0000000000000000  x3  00000000000003d0
[hos OptimizeChangeBanc] CRASH:   x19 0000007e4a891968  x20 0000000000000000  x21 0000007e4a7c0a70  x22 000000105a69eb60
[hos OptimizeChangeBanc] CRASH:   x29 000000105a69eb20  x30 00000000809051ec

x0 is null and the read is at guest 0x4, so it looks like a field read through a null pointer. lr (x30) is 0x809051ec. Full hookshot_log.txt attached. I have a Windows minidump too, but I'm not attaching it because it contains game memory. I can run something against it if that helps.

Possibly useful for 6 GB Turing cards (#132): before the texture limit, small-vram and less-stutter both lost the device after a zone change, with VRAM at about 4.7 of 5.1 GB allowed (checkpoints in compute dispatches, nvlddmkm event 153 each time). Driver 621.14 and RX_VK_ROBUST=1 alone did not stop it. With RX_VK_VRAM_MB=2560, the session above ran with no GPU reset, although VRAM still went over the driver's allowance at times (e.g. 5681 MB used of 5138 MB allowed, 1951 MB of it free in the blocks).

[hookshot_log.txt](https://github.com/user-attachments/files/34526689/hookshot_log.txt) **Build:** `less-stutter` release (HookshotBuilder.zip sha256 `03f23d9f…0296`), built from the command line over an earlier `small-vram` build with the same .nup. Game: `0400486024DEC000`, v131072, build `e0f3ccfa` (`--check` OK). **PC:** Ryzen 5 3600, RTX 2060 6 GB (Turing), driver 621.14, 32 GB RAM, Windows 11 Pro (build 26300). **Settings:** `hookshot_env.txt`: `RX_VK_ROBUST=1`, `RX_VK_VRAM_MB=2560`. In-game menu: frame generation 2x, resolution 67%, game speed real time, FPS counter on. **What happened:** About 13,700 frames into the session, while walking from Kakariko Village toward the castle (Hyrule Field to Castle Town), the game closed. The GPU did not reset this time: there is no "device lost" in the log and no `nvlddmkm` event at that time. The crash is in a guest thread: ``` [hos OptimizeChangeBanc] CRASH: exception 0xc0000005 (read 0x100000000004, guest 0x4) at hookshot.exe+0x1910366d [hos OptimizeChangeBanc] CRASH: host backtrace: hookshot.exe+0x1910366d [hos OptimizeChangeBanc] CRASH: thread OptimizeChangeBanc, sp 0x105a69eae0 [hos OptimizeChangeBanc] CRASH: x0 0000000000000000 x1 000000105a69eae0 x2 0000000000000000 x3 00000000000003d0 [hos OptimizeChangeBanc] CRASH: x19 0000007e4a891968 x20 0000000000000000 x21 0000007e4a7c0a70 x22 000000105a69eb60 [hos OptimizeChangeBanc] CRASH: x29 000000105a69eb20 x30 00000000809051ec ``` `x0` is null and the read is at guest `0x4`, so it looks like a field read through a null pointer. `lr` (x30) is `0x809051ec`. Full `hookshot_log.txt` attached. I have a Windows minidump too, but I'm not attaching it because it contains game memory. I can run something against it if that helps. **Possibly useful for 6 GB Turing cards (#132):** before the texture limit, `small-vram` and `less-stutter` both lost the device after a zone change, with VRAM at about 4.7 of 5.1 GB allowed (checkpoints in compute dispatches, `nvlddmkm` event 153 each time). Driver 621.14 and `RX_VK_ROBUST=1` alone did not stop it. With `RX_VK_VRAM_MB=2560`, the session above ran with no GPU reset, although VRAM still went over the driver's allowance at times (e.g. 5681 MB used of 5138 MB allowed, 1951 MB of it free in the blocks).
NotRexed commented 2026-11-07 19:25:27 +00:00 (Migrated from github.com)

Thanks for the detailed report. #284 (RX 9060 XT) crashes in the same thread, OptimizeChangeBanc, reading guest address 0x4, so this is one bug on both vendors; I'm tracking it here.

Thanks for the detailed report. #284 (RX 9060 XT) crashes in the same thread, `OptimizeChangeBanc`, reading guest address 0x4, so this is one bug on both vendors; I'm tracking it here.
NotRexed commented 2026-11-07 19:49:47 +00:00 (Migrated from github.com)

Found it from your log and #284's: both crash inside Hookshot's NVN code, nvnTextureBuilderGetStorageSize (or its alignment twin) called with no texture builder. Its format is read at +4 of nothing, which is the guest-0x4 crash. The next release answers 0 there instead of crashing, and logs the caller once (nvn: storage size of no texture builder (lr ...)), so if you can send the log from that build we'll see why the game asks.

Found it from your log and #284's: both crash inside Hookshot's NVN code, `nvnTextureBuilderGetStorageSize` (or its alignment twin) called with no texture builder. Its format is read at +4 of nothing, which is the guest-0x4 crash. The next release answers 0 there instead of crashing, and logs the caller once (`nvn: storage size of no texture builder (lr ...)`), so if you can send the log from that build we'll see why the game asks.
Nitnek commented 2026-11-08 00:12:53 +00:00 (Migrated from github.com)

Still crashes here, same thread and same guest 0x4 read, with a build that already has the no_builder guard (source 8f67b23, built from the command line with llvm-mingw; Ryzen 7 5800X, RTX 3070 8 GB, 32 GB RAM). It happened while loading into Castle Town from Hyrule Field:

[hos OptimizeChangeBanc] CRASH: exception 0xc0000005 (read 0x100000000004, guest 0x4) at hookshot.exe+0x19ba31cd
[hos OptimizeChangeBanc] CRASH: guest backtrace: lr 0x809051ec 0x814f2a3c 0x800ac780 0x800ac614 0x80456fb4 0x80455a70 0x83bb5a14 ...

llvm-symbolizer --obj=hookshot.exe 0x159ba31cd names the faulting host function n_nvnMemoryPoolGetFlags, not a texture builder getter. The lifted caller agrees: in f_80905130 the last indirect call (proc table +2080, returning to 0x809051ec) gets x0 = *(x3), the pool pointer the caller passed in, and its result is used as flags (>> 1 & 2). The same *(x3) goes as x1 to the call at +2064 just before (most likely nvnTextureBuilderSetStorage). So while the scene loads, the game sets up a texture with no pool and then asks that pool for its flags.

Local workaround in host/nvn_native.c, in the same style as no_builder:

static int no_pool(Ctx *c, const char *what) {
    if (c->x[0]) return 0;
    static int told;
    if (told++ < 8) hos_log("nvn: %s of no memory pool (lr %#llx): 0", what, (unsigned long long)c->x[30]);
    return 1;
}
NV(nvnMemoryPoolGetFlags) { if (no_pool(c, "flags")) { RET(0); return; } RET(((const nvn_pool *)P(0))->flags); }
NV(nvnMemoryPoolGetSize) { if (no_pool(c, "size")) { RET(0); return; } RET(((const nvn_pool *)P(0))->size); }
NV(nvnMemoryPoolGetBufferAddress) { if (no_pool(c, "buffer address")) { RET(0); return; } RET(((const nvn_pool *)P(0))->gpu); }

nvnTextureInitialize already copes with a null b->pool. I haven't tested this in game yet; I'll report back whether it gets past Castle Town. Why the game has no pool at that point is still open.

Still crashes here, same thread and same guest 0x4 read, with a build that already has the `no_builder` guard (source 8f67b23, built from the command line with llvm-mingw; Ryzen 7 5800X, RTX 3070 8 GB, 32 GB RAM). It happened while loading into Castle Town from Hyrule Field: ``` [hos OptimizeChangeBanc] CRASH: exception 0xc0000005 (read 0x100000000004, guest 0x4) at hookshot.exe+0x19ba31cd [hos OptimizeChangeBanc] CRASH: guest backtrace: lr 0x809051ec 0x814f2a3c 0x800ac780 0x800ac614 0x80456fb4 0x80455a70 0x83bb5a14 ... ``` `llvm-symbolizer --obj=hookshot.exe 0x159ba31cd` names the faulting host function **`n_nvnMemoryPoolGetFlags`**, not a texture builder getter. The lifted caller agrees: in `f_80905130` the last indirect call (proc table +2080, returning to 0x809051ec) gets `x0 = *(x3)`, the pool pointer the caller passed in, and its result is used as flags (`>> 1 & 2`). The same `*(x3)` goes as x1 to the call at +2064 just before (most likely `nvnTextureBuilderSetStorage`). So while the scene loads, the game sets up a texture with no pool and then asks that pool for its flags. Local workaround in `host/nvn_native.c`, in the same style as `no_builder`: ```c static int no_pool(Ctx *c, const char *what) { if (c->x[0]) return 0; static int told; if (told++ < 8) hos_log("nvn: %s of no memory pool (lr %#llx): 0", what, (unsigned long long)c->x[30]); return 1; } NV(nvnMemoryPoolGetFlags) { if (no_pool(c, "flags")) { RET(0); return; } RET(((const nvn_pool *)P(0))->flags); } NV(nvnMemoryPoolGetSize) { if (no_pool(c, "size")) { RET(0); return; } RET(((const nvn_pool *)P(0))->size); } NV(nvnMemoryPoolGetBufferAddress) { if (no_pool(c, "buffer address")) { RET(0); return; } RET(((const nvn_pool *)P(0))->gpu); } ``` `nvnTextureInitialize` already copes with a null `b->pool`. I haven't tested this in game yet; I'll report back whether it gets past Castle Town. Why the game has no pool at that point is still open.
NotRexed commented 2026-11-08 01:02:09 +00:00 (Migrated from github.com)

The new release is out: https://github.com/NotRexed/Hookshot/releases/tag/no-visual-studio. Please rebuild with it and tell me here whether it's fixed for you (attach hookshot_log.txt if not).

The new release is out: https://github.com/NotRexed/Hookshot/releases/tag/no-visual-studio. Please rebuild with it and tell me here whether it's fixed for you (attach hookshot_log.txt if not).
hallygtree commented 2026-11-08 05:15:46 +00:00 (Migrated from github.com)

Still happening on device-lost-fix (caaaf2b7). Same guest 0x4 read and backtrace, but in BaseProcCreateAndDeleteThread, and no nvn: storage size of no texture builder line in the log. Right after a scene change near Kakariko. One RomFS mod loaded (DualSense icons, includes a ResourceSizeTable).

Log: https://gist.github.com/hallygtree/601826c494c613dd7da742f10fa042cd

Still happening on **device-lost-fix** (caaaf2b7). Same guest 0x4 read and backtrace, but in `BaseProcCreateAndDeleteThread`, and no `nvn: storage size of no texture builder` line in the log. Right after a scene change near Kakariko. One RomFS mod loaded (DualSense icons, includes a ResourceSizeTable). Log: https://gist.github.com/hallygtree/601826c494c613dd7da742f10fa042cd
nicholasgower commented 2026-11-08 07:25:22 +00:00 (Migrated from github.com)

The Kakariko Village day-to-night occurrence is now reported with its full log in #509. #510 is the fix: it adds a
o_pool\ guard to the memory-pool accessors (the same class as
o_builder, but for
vnMemoryPoolGetFlags/\GetSize/\GetBufferAddress/\Map\ rather than the texture-builder queries) and a game-free regression test.

The Kakariko Village day-to-night occurrence is now reported with its full log in #509. #510 is the fix: it adds a \ o_pool\ guard to the memory-pool accessors (the same class as \ o_builder\, but for \ vnMemoryPoolGetFlags\/\GetSize\/\GetBufferAddress\/\Map\ rather than the texture-builder queries) and a game-free regression test.
nicholasgower commented 2026-11-08 09:27:43 +00:00 (Migrated from github.com)

PR #510 is merged into main (7d852f3): nvnMemoryPoolGetFlags and the other pool accessors now answer 0 for a null pool instead of reading guest 0x4, and the first few occurrences log nvn: ... of no memory pool (lr ...). The crash in your 00:12 comment was on 8f67b23, which predates that guard.

I also extended the game-free test to every guarded accessor (GetFlags, GetSize, Map, GetBufferAddress, InvalidateMappedRange) in PR #541. Please retest on a build that contains 7d852f3 (current main or the next release); if it still happens, attach hookshot_log.txt and the nvn: ... of no memory pool line. Keeping this open until the retest.

PR #510 is merged into `main` (`7d852f3`): `nvnMemoryPoolGetFlags` and the other pool accessors now answer 0 for a null pool instead of reading guest `0x4`, and the first few occurrences log `nvn: ... of no memory pool (lr ...)`. The crash in your 00:12 comment was on `8f67b23`, which predates that guard. I also extended the game-free test to every guarded accessor (`GetFlags`, `GetSize`, `Map`, `GetBufferAddress`, `InvalidateMappedRange`) in PR #541. Please retest on a build that contains `7d852f3` (current `main` or the next release); if it still happens, attach `hookshot_log.txt` and the `nvn: ... of no memory pool` line. Keeping this open until the retest.
Nitnek commented 2026-11-08 12:24:11 +00:00 (Migrated from github.com)

Retested on 53af338 (contains 7d852f3), same PC (Ryzen 7 5800X, RTX 3070 8 GB). The guard fires, but the game crashes a few instructions later in the same thread, on a scene change:

[hos OptimizeChangeBanc] nvn: flags of no memory pool (lr 0x809051ec): 0
[hos OptimizeChangeBanc] CRASH: exception 0xc0000005 (write 0x100000000000, guest 0) at hookshot.exe+0x868f92
[hos OptimizeChangeBanc] CRASH: guest backtrace: lr 0x800ac684 0x80456fb4 0x80455a70 0x83bb5a14 0x80387b00 0x80383d8c 0x801a2268 0x80034bd4 0x80df26c0 0x834a2ec8 0
[hos OptimizeChangeBanc] CRASH:   x0  0000000000000000  ...  x2  00000000000003d0

hookshot.exe+0x868f92 is in f_8575cdc0 (the sdk's memcpy), called from f_800ac5d0 with a null destination and 0x3d0 bytes. In the lifted code:

f_800ac5d0:
    x0 = [x19 + 424] + x22
    f_800a8df0()            // x0 = [x0 + 8]; tail-calls the proc at table +2096 -> returns 0 here
    x1 = [x21 + 16]; x2 = x20
    f_8572f020() -> f_8575cdc0 (memcpy to 0)

Earlier in the same function, f_800ac6e0 -> f_814f28c0 -> f_80905130 is the texture setup that asked for the flags of the null pool. So the same object has no pool for its texture and no CPU mapping for the buffer that gets filled right after. Answering 0 moves the crash from the read of guest 0x4 to the write of guest 0.

Only one no memory pool line was logged (flags), and no map line. So the call at +2096 is not nvnMemoryPoolMap; my guess is nvnBufferMap on a buffer whose pool is null, which returns 0 without a log line.

The real question looks like why the game ends up with a null pool for this resource during a banc change. One guess is that an allocation on the game's side fails under Hookshot. For example, the pool's memory budget could fill up if the HLE storage sizes or alignments are larger than the real driver's. I haven't verified that yet. I'm happy to trace further or run a build with extra logging if that helps.

Retested on `53af338` (contains `7d852f3`), same PC (Ryzen 7 5800X, RTX 3070 8 GB). The guard fires, but the game crashes a few instructions later in the same thread, on a scene change: ``` [hos OptimizeChangeBanc] nvn: flags of no memory pool (lr 0x809051ec): 0 [hos OptimizeChangeBanc] CRASH: exception 0xc0000005 (write 0x100000000000, guest 0) at hookshot.exe+0x868f92 [hos OptimizeChangeBanc] CRASH: guest backtrace: lr 0x800ac684 0x80456fb4 0x80455a70 0x83bb5a14 0x80387b00 0x80383d8c 0x801a2268 0x80034bd4 0x80df26c0 0x834a2ec8 0 [hos OptimizeChangeBanc] CRASH: x0 0000000000000000 ... x2 00000000000003d0 ``` `hookshot.exe+0x868f92` is in `f_8575cdc0` (the sdk's memcpy), called from `f_800ac5d0` with a null destination and 0x3d0 bytes. In the lifted code: ``` f_800ac5d0: x0 = [x19 + 424] + x22 f_800a8df0() // x0 = [x0 + 8]; tail-calls the proc at table +2096 -> returns 0 here x1 = [x21 + 16]; x2 = x20 f_8572f020() -> f_8575cdc0 (memcpy to 0) ``` Earlier in the same function, `f_800ac6e0` -> `f_814f28c0` -> `f_80905130` is the texture setup that asked for the flags of the null pool. So the same object has no pool for its texture and no CPU mapping for the buffer that gets filled right after. Answering 0 moves the crash from the read of guest 0x4 to the write of guest 0. Only one `no memory pool` line was logged (`flags`), and no `map` line. So the call at +2096 is not `nvnMemoryPoolMap`; my guess is `nvnBufferMap` on a buffer whose pool is null, which returns 0 without a log line. The real question looks like why the game ends up with a null pool for this resource during a banc change. One guess is that an allocation on the game's side fails under Hookshot. For example, the pool's memory budget could fill up if the HLE storage sizes or alignments are larger than the real driver's. I haven't verified that yet. I'm happy to trace further or run a build with extra logging if that helps.
alberthorta commented 2026-11-08 13:11:36 +00:00 (Migrated from github.com)

Confirming the post-guard crash on the low-vram release (source 618e37c6), with a different GPU and place: RTX 2080 Super (8 GB), driver 621.14, Windows 11. It happened leaving Hyrule Castle into Hyrule Field, on the scene change. Identical to the comment above: the guard fires, then the write to guest 0:

[hos OptimizeChangeBanc] nvn: flags of no memory pool (lr 0x809051ec): 0
[hos OptimizeChangeBanc] CRASH: exception 0xc0000005 (write 0x100000000000, guest 0) at hookshot.exe+0x87c2d0
[hos OptimizeChangeBanc] CRASH: guest backtrace: lr 0x800ac684 0x80456fb4 0x80455a70 0x83bb5a14 0x80387b00 0x80383d8c 0x801a2268 0x80034bd4 0x80df26c0 0x834a2ec8 0
[hos OptimizeChangeBanc] CRASH:   x0  0000000000000000  x1  0000007fe9ad7df8  x2  00000000000003d0  x3  0000000000000000

Same x2 = 0x3d0 size, so it looks like the same memcpy into the null pool's buffer address. Earlier today, on compile-retry (before the guard), the same thread crashed in Hyrule Field with the old read guest 0x4 signature and the same guest backtrace from 0x80456fb4 on.

Settings: Quality preset Low (6GB), Handheld profile On, frame generation 2x, RX_VK_WAIT_GPU=0. I can attach the full hookshot_log.txt if it helps.

Confirming the post-guard crash on the **`low-vram` release** (source `618e37c6`), with a different GPU and place: **RTX 2080 Super (8 GB)**, driver 621.14, Windows 11. It happened **leaving Hyrule Castle into Hyrule Field**, on the scene change. Identical to the comment above: the guard fires, then the write to guest 0: ``` [hos OptimizeChangeBanc] nvn: flags of no memory pool (lr 0x809051ec): 0 [hos OptimizeChangeBanc] CRASH: exception 0xc0000005 (write 0x100000000000, guest 0) at hookshot.exe+0x87c2d0 [hos OptimizeChangeBanc] CRASH: guest backtrace: lr 0x800ac684 0x80456fb4 0x80455a70 0x83bb5a14 0x80387b00 0x80383d8c 0x801a2268 0x80034bd4 0x80df26c0 0x834a2ec8 0 [hos OptimizeChangeBanc] CRASH: x0 0000000000000000 x1 0000007fe9ad7df8 x2 00000000000003d0 x3 0000000000000000 ``` Same `x2 = 0x3d0` size, so it looks like the same memcpy into the null pool's buffer address. Earlier today, on `compile-retry` (before the guard), the same thread crashed in Hyrule Field with the old `read guest 0x4` signature and the same guest backtrace from `0x80456fb4` on. Settings: Quality preset Low (6GB), Handheld profile On, frame generation 2x, `RX_VK_WAIT_GPU=0`. I can attach the full `hookshot_log.txt` if it helps.
NotRexed commented 2026-11-08 23:22:27 +00:00 (Migrated from github.com)

Closing as fixed in v2.0.0: a buffer the game maps without memory now gets scratch memory instead of address 0, and the same OptimizeChangeBanc crash was confirmed gone after 2 hours in Hyrule Field (#648) and in Kakariko (#595). If it still happens on v2.0.5, please open a new issue with hookshot_log.txt.

Closing as fixed in v2.0.0: a buffer the game maps without memory now gets scratch memory instead of address 0, and the same OptimizeChangeBanc crash was confirmed gone after 2 hours in Hyrule Field (#648) and in Kakariko (#595). If it still happens on v2.0.5, please open a new issue with hookshot_log.txt.
Commenting is not possible because the repository is archived.
No milestone
No assignees
1 participant
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
MagicBeanDev/Hookshot#287
No description provided.