Skip to content

fix(motchan): Prevent undefined behavior when reading floats from motion channel packets - #3648

Merged
xezon merged 4 commits into
TheSuperHackers:mainfrom
CryoTheRenegade:refactor/motion-channel-floats
Nov 9, 2026
Merged

xezon merged 4 commits into
TheSuperHackers:mainfrom
CryoTheRenegade:refactor/motion-channel-floats

Conversation

@CryoTheRenegade

@CryoTheRenegade CryoTheRenegade commented Nov 2, 2026 •

Copy link
Copy Markdown

Follow-up to #3630, #3635 and #3636. TimeCodedMotionChannelClass and AdaptiveDeltaMotionChannelClass store their animation packets in a uint32 array and read the float values through float* casts. Reading a uint32 object as a float is undefined behavior, the same problem as #3521.

The motion channel code in both games now reads each uint32 element and converts it with std::bit_cast<float32>:

  • TimeCodedMotionChannelClass::Get_Vector: for the copied and the interpolated vector values.
  • TimeCodedMotionChannelClass::Get_QuatVector: a new Set_Quaternion_From_Packet helper sets a quaternion from the four floats of a packet. It replaces the four q.Set calls that read through a float*.
  • AdaptiveDeltaMotionChannelClass::decompress: for the starting value of each vector component. The other decompress overload only used its float* to find where the packet bytes start, so it now points a const uint32* there.

The Generals and Zero Hour files are identical since #3594, and both get the same change.

Evidence

  • Disassembly: I compared both games' motchan objects against a build of main.
    • VS 2026 (ClangCL) Release: every function is identical.
    • VC6 Release: only Get_Vector, Get_QuatVector and the first decompress overload changed. VC6 now copies the packet values with integer moves where it used fld/fstp before. The float arithmetic instructions and the calls in each function are the same as on main.

AI Disclosure

Claude Opus 5.5 was used to aid in implementation and to compare the disassembly.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Codex Review Summary: ✅ Completed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-09T19:13:51.412678Z c480a7c New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@coderabbitai

coderabbitai Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

Explain Change →

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • Resume reviews
  • Trigger review

No actionable comments were generated in the recent review.

Walkthrough

Both game variants update motion-channel packet reads to use std::bit_cast or memcpy instead of float-pointer casts. The changes cover vector and quaternion retrieval, interpolation, and adaptive-delta decompression.

Changes

Motion Packet Reads

Layer / File(s) Summary
Vector and quaternion packet reads
Generals/Code/Libraries/Source/WWVegas/WW3D2/motchan.cpp, GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/motchan.cpp
Vector and quaternion packet values use std::bit_cast instead of float-pointer reinterpretation. Packet-copy paths use memcpy. A local helper converts four packet values to a quaternion.
Adaptive-delta decompression
Generals/Code/Libraries/Source/WWVegas/WW3D2/motchan.cpp, GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/motchan.cpp
The decompressor uses uint32 pointers for packed initial values and bit-casts the initial value to float. The continuation decompressor uses an offset into the uint32 data.

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Possibly related PRs

Suggested labels: Gen, ZH

Suggested reviewers: xezon, bobtista

Merge Risk: Minimal · previous review b3f03

The packet-read changes have no identified merge-blocking issue and appear mergeable subject to normal build and test checks.

Pre-merge checks: Passed 4

Check name Status Explanation
Title check Passed The title names the main change: a fix that prevents undefined behavior when reading floats from motion channel packets. The changeset replaces float* reads from uint32 packet arrays with std::bit_cas…
Description check Passed The description is directly related to the changeset. It explains that TimeCodedMotionChannelClass and AdaptiveDeltaMotionChannelClass read float values through float* casts from uint32 arrays. It lis…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Title check

Explanation

The title names the main change: a fix that prevents undefined behavior when reading floats from motion channel packets. The changeset replaces float* reads from uint32 packet arrays with std::bit_cast conversions in motchan.cpp for both Generals and Zero Hour, which matches the title. The title uses a conventional prefix and is slightly long at 88 characters, but it is specific and accurate.

Full details: Description check

Explanation

The description is directly related to the changeset. It explains that TimeCodedMotionChannelClass and AdaptiveDeltaMotionChannelClass read float values through float* casts from uint32 arrays. It lists the changed functions (Get_Vector, Get_QuatVector with the new Set_Quaternion_From_Packet helper, and decompress), states that both games receive the same change, and gives disassembly evidence. It is detailed and on-topic.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

Recent review info

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 6cb1f2f1-d63d-4170-9dfc-e10b703c8009
Commits

Reviewing files that changed from the base of the PR and between 08a14c7 and b3f0333.

Files selected for processing: 2

  • Generals/Code/Libraries/Source/WWVegas/WW3D2/motchan.cpp
  • GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/motchan.cpp

Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 2 remain after this review.

@greptile-apps

greptile-apps Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge; no actionable issues were found.

Summary

Removes reads through incompatible float pointers in both games’ motion channels.

  • Motion channels read float values safely from animation packets.

No actionable issues were found. No builds or runtime tests were run.

Reviews (4) · Last reviewed commit: "refactor(ww3d2): Take a packet array in ..." · Reviewed by Greptile

@xezon xezon left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Looks technically fine.

@xezon xezon added Minor Severity: Minor < Major < Critical < Blocker Fix Is fixing something, but is not user facing labels Nov 7, 2026
@xezon

xezon commented Nov 9, 2026

Copy link
Copy Markdown

Github says "This branch cannot be rebased due to conflicts"

CryoTheRenegade and others added 4 commits November 9, 2026 12:11
TimeCodedMotionChannelClass and AdaptiveDeltaMotionChannelClass store
their packets in uint32 arrays and read the float values through float
pointers. Read each uint32 element and convert it with std::bit_cast.

AdaptiveDeltaMotionChannelClass::decompress only used its float pointer
to find where the packet bytes start, so it now points a uint32 pointer
there instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…elper

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…p dead initialization

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@CryoTheRenegade
CryoTheRenegade force-pushed the refactor/motion-channel-floats branch from b3f0333 to c480a7c Compare November 9, 2026 19:11
@CryoTheRenegade

Copy link
Copy Markdown
Author

Github says "This branch cannot be rebased due to conflicts"

Rebased

@xezon
xezon merged commit 998f337 into TheSuperHackers:main Nov 9, 2026
28 checks passed
@CryoTheRenegade
CryoTheRenegade deleted the refactor/motion-channel-floats branch November 10, 2026 18:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Fix Is fixing something, but is not user facing Minor Severity: Minor < Major < Critical < Blocker

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants