Skip to content

hkbClipGenerator_Generate: missing null-guard after GetLastBlendingClipGenerator → AV when blending clip list is non-empty but deque element is stale #21

Description

@WraithFallen

Summary

hkbClipGenerator_Generate is missing a null/sentinel guard after ActiveClip::GetLastBlendingClipGenerator. When the blending-clip list is non-empty but the stored deque element is stale/recycled, the returned hkbClipGenerator* is garbage and is passed straight to the game trampoline, causing an EXCEPTION_ACCESS_VIOLATION.

Affected versions

  • 3.0.2 and 3.1.5 confirmed (both ship the byte-identical function at 0x180148CB0 in their respective DLLs).

Crash signature

  • EXCEPTION_ACCESS_VIOLATION at SkyrimSE.exe+0A0C98Amovaps [rdx+rax*1], xmm2
  • OpenAnimationReplacer.dll+0148D5C in frame [1]

Root cause (decompile)

// hkbClipGenerator_Generate @ 0x180148CB0 (from PDB)
if ((this != NULL) && (this->_blendingClipGenerators.size() != 0) && (param_1->_padding_ != 0xc)) {
    phVar1 = ActiveClip::GetLastBlendingClipGenerator(this);
    // NO NULL/SENTINEL GUARD HERE
    (*(code *)_hkbClipGenerator_Generate._impl)(phVar1, param_2, param_3, param_4);
    return;
}

GetLastBlendingClipGenerator reads from a std::deque backing array. If the stored hkbClipGenerator* is a dangling/recycled pointer (deque inconsistency or use-after-free on a recycled clip object), the returned value is garbage. It is passed directly to the game trampoline → the game does a clip-ID lookup → returns the Havok -1 sentinel → that is used as a buffer write offset → AV.

Suggested fix

phVar1 = ActiveClip::GetLastBlendingClipGenerator(this);
if (phVar1 == nullptr) {
    // fall through to the normal (non-blending) path below
} else {
    (*(code *)_hkbClipGenerator_Generate._impl)(phVar1, param_2, param_3, param_4);
    return;
}

(A stronger guard would additionally validate the returned pointer's vtable against the known hkbClipGenerator vtable before dispatch, to also reject a recycled object that still holds a committed-but-freed vtable.)

Context

  • Observed on Skyrim SE 1.6.1170 (Apostasy 3.2.2 modlist).
  • Repro NPC: a DragonCultDraugr playing AlcoveLayingIdle in Snow Veil Sanctum.
  • Behavior-graph mods present on the affected NPC type: MCO Draugr Boss Addon and TDC - Draugr MCO (both modify the draugr behavior graph).
  • A downstream consumer (a MinHook-based GetLast interceptor that validates the returned pointer before dispatch) has been confirmed to eliminate the crash in this configuration, which corroborates the null/stale-pointer diagnosis.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions