Skip to content

[T6] Zone loader spins forever instead of erroring when a fastfile fails to inflate #82

Description

@schindlershadow

What happened?

On ARM64 Android (Snapdragon 8 Gen 2) running the client under Wine/Proton arm64ec with
FEX as the x86→ARM64 translator, T6MP hangs forever at Loading fastfile code_pre_gfx_mp
— no error, no crash, one thread pinned at 100% CPU indefinitely.

I traced it to the guest instruction level, and there are two separate issues. The first one
is platform-independent and is the reason this presents as a silent freeze rather than an
error message.

1. The inflate error path is an infinite spin loop (affects all platforms)

The zone chunk loader does roughly:

inflateInit2_(&strm, -15, ...)      ; raw deflate
call <decrypt/deblock>
call inflate                        ; inflate(&strm, Z_FULL_FLUSH)
cmp  eax, 1
je   done                           ; Z_STREAM_END -> fine
test eax, eax
jne  <back to the cmp>              ; eax is NEVER reloaded -> spins forever

If inflate() returns anything other than Z_OK or Z_STREAM_END, the loop re-tests the
same stale return value forever. So any corrupt or unreadable fastfile becomes a
permanent silent hang instead of hitting the existing
Fastfile for zone '...' is corrupt or unreadable. error. That would apply on Windows too,
and it makes this class of problem very hard for users to self-diagnose.

2. Signed/encrypted zones are misdetected under x86→ARM translation

The loader treats the signed retail zone as if it were an unsigned one: it reads a chunk
size at offset 0x0C and begins inflating at 0x10, instead of skipping the 0x138
signed header (TAff0100 + version + PHEEBs71 + flags + zone name[32] + RSA signature[256])
and running the Salsa20 pass first. inflate() is therefore handed still-encrypted bytes.

Evidence, read out of the live process at the hang:

  • z_stream.msg = "invalid distance too far back"
  • total_in = 3, total_out = 0
  • next_in pointed at file offset 0x13 — i.e. inside the PHEEBs71 tag
  • the 512 KB input buffer was byte-identical to the on-disk .ff, header and payload —
    so the decryption pass had not modified it at all

I have reported the underlying translation problem to FEX as
FEX-Emu/FEX#5966. I am not asking you to support FEX or Android —
issue 2 is arguably theirs. Issue 1 is the one I think is worth fixing on your side,
since it turns every fastfile read failure into an unexplained freeze.

A useful corroborating detail: T4 (WaW) works perfectly on the exact same device, same
client build, same translator.
WaW zones are unencrypted (IWffu100), so they never take
the decrypt path — which isolates the failure to the signed/encrypted zone path rather than
to zone loading in general.

Expected result

inflate() failing should raise the normal COM_ERROR (e.g. "Fastfile for zone '...' is
corrupt or unreadable.") instead of looping on a stale return value forever. Even just
breaking out of that loop on a negative return would turn a mystery freeze into an
actionable message.

Steps to reproduce

  1. BO2 (TU17) with Plutonium r5316 on ARM64 Android, running the client under Wine/Proton
    arm64ec with FEX (libwow64fex.dll) as the 32-bit x86 translator.
  2. Launch T6 Multiplayer from the launcher.
  3. The console window prints Loading fastfile code_pre_gfx_mp and then hangs forever with
    one thread at 100% CPU. It never errors and never times out.
  4. For contrast, launch T4 Multiplayer on the same setup — it loads and runs normally.

On Windows, issue 1 alone should be reproducible by feeding the loader any fastfile that
fails to inflate: expect a hang rather than the corrupt-fastfile error.

Affected game(s)

BO2 Multiplayer (T6MP) — the hang. The spin loop itself is in shared zone-loading code and
would affect any title.

Affected component(s)

Client (game)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    component: clientIssue related to the game clientgame: T6Issue related to T6mode: MPIssue only affecting Multiplayer

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions