Skip to content

[Vanilla Fix] Fix IsSonic wave drawing crash near the top screen edge - #2474

Merged
Coronia merged 2 commits into
Phobos-developers:developfrom
JerryDing07:fix/sonic-wave-slow-path-clip
Oct 17, 2026
Merged

Coronia merged 2 commits into
Phobos-developers:developfrom
JerryDing07:fix/sonic-wave-slow-path-clip

Conversation

@JerryDing07

Copy link
Copy Markdown
Contributor

What kind of change is this?

  • New feature, vanilla bugfix or enhancement of a released feature - changelog, docs and credits entries are needed.
  • Improvement to a new (unreleased) feature - docs and credits entries are needed; no changelog entry (Skip Changelog).
  • Bugfix to a new (unreleased) feature - credits entry is needed; no changelog or docs entries (Skip Changelog, Skip Docs).
  • Bugfix to an old (released) feature - changelog and credits entries are needed; no docs entry (Skip Docs).
  • Completely minor change (e.g. a typo fix) - no entries are needed (Skip Changelog, Skip Docs, Skip Credits).

Description

Fixes a vanilla crash when an IsSonic=true wave is drawn near the top edge of the screen.

Root cause

For each pixel, the sonic wave drawing code (0x75EDF0) reads the source color from up to 3 pixels ahead in the wave direction: ColorData entries 10-12 hold 3 times the direction step. The drawing loops therefore have to stay at least 3 pixels inside the clip rectangle.

WaveClass has two sets of drawing loops. The ones used when the ZBuffer does not wrap keep a 3 pixel margin, but the ones used when it wraps (top-down loop at 0x75FD22-0x75FD76, bottom-up loop at 0x760033-0x76007A) only keep 2 pixels. On row 2 (the third row from the top), a pixel whose direction points upwards reads 3 rows up, which is one row above the surface buffer and may fall into unmapped memory.

The fix patches these 8 bounds in the wrapping loops from 2 to 3 pixels, so they match the non-wrapping loops. Magnetron drawing has the same 2 pixel margin, which is correct there because it clamps the color index to 9.

The existing WaveClass_DrawSonic_CrashFix hook (0x75EE49) does not cover this case: it clamps the color index to 12 while the crash already happens with index 10.

Reproduction

cnc-ddraw (the default CnCNet renderer) allocates padding around each surface (guard_lines=200 by default, see ddsurface.c), so the out-of-bounds read hits zeroed memory and nothing happens. Native DirectDraw and renderers without such padding crash. It can be reproduced with cnc-ddraw by setting guard_lines=0 in ddraw.ini.

With Ares the crash address is reported in Ares.dll (WaveClass_Draw_Sonic, hooked at 0x75EE57), because Ares replaces that pixel read. The fix works on the loop bounds, so the pixel function is never called for those rows no matter who handles the read. None of the patched addresses are hooked by Ares or Phobos.

Testing

Tested with cnc-ddraw guard_lines=0, Ares 3.0p1, dolphin attacking while the view was moved so the waves were drawn along the screen edges:

  • Before (Phobos 0.4.0.2): crashed (video below; the crash dialog is not captured).
  • After (this PR): no crash after 5 minutes, tested along the top, bottom, left and right edges.
  • No visible difference in how the waves look, apart from one less pixel drawn at the very edge of the screen.
2026-10-16.20-08-43.mp4

@Coronia Coronia added ❓Vanilla bug Vanilla game bugs that are requested to be fixed Needs testing labels Oct 17, 2026
@github-actions

github-actions Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

Nightly build for this pull request:

This comment is automatic and is meant to allow guests to get latest nightly builds for this pull request without registering. It is updated on every successful build.

@NetsuNegi NetsuNegi added the ⚙️T1 T1 maintainer review is sufficient label Oct 17, 2026

@NetsuNegi NetsuNegi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, there are some code simplification suggestions to consider, non mandatory.

Comment thread src/Misc/Hooks.BugFixes.cpp Outdated
Comment thread src/Misc/Hooks.BugFixes.cpp Outdated
Co-authored-by: Netsu_Negi <71598172+NetsuNegi@users.noreply.github.com>
@JerryDing07

Copy link
Copy Markdown
Contributor Author

Applied, thanks!

@NetsuNegi

Copy link
Copy Markdown
Contributor

Applied, thanks!

:)

@Coronia
Coronia merged commit 6998e37 into Phobos-developers:develop Oct 17, 2026
15 checks passed
@JerryDing07
JerryDing07 deleted the fix/sonic-wave-slow-path-clip branch October 17, 2026 17:30
@DeathFishAtEase

Copy link
Copy Markdown
Collaborator

Also a heads-up on EOL: 6998e37 (this PR) committed the four DEFINE_PATCH lines at src/Misc/Hooks.BugFixes.cpp:1880-1883 with CRLF while the rest of that blob is LF. Under * text eol=crlf that makes it the only i/mixed file in the repo, so every clone shows a 4-line phantom diff that git checkout -- can never clear (git diff --ignore-cr-at-eol is empty).

DEFINE_PATCH(0x75FD24, 0x03); // lea edx, [eax+3]
DEFINE_PATCH(0x75FD33, 0xFD); // lea edx, [eax+ecx-3]
DEFINE_PATCH(0x75FD54, 0xFD); // lea edx, [ecx+edx-3]
DEFINE_PATCH(0x75FD78, 0x03); // lea edi, [ecx+3]

I've normalized it in ef9a9e2 (just git add --renormalize src/Misc/Hooks.BugFixes.cpp, +4/−4, nothing else touched).

DeathFishAtEase added a commit to DeathFishAtEase/Phobos that referenced this pull request Oct 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

⚙️T1 T1 maintainer review is sufficient Tested ❓Vanilla bug Vanilla game bugs that are requested to be fixed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants