Skip to content

Intermittent ACCESS_VIOLATION (0xC0000005) in Adobe AIR.dll sampler record parser during startup #4178

@bobaoapae

Description

@bobaoapae

Summary

Intermittent native crash (0xC0000005 — ACCESS_VIOLATION) in Adobe AIR.dll during application startup when flash.sampler.* APIs are used early in the app lifecycle. The crash does not occur every time — the same build may crash on one launch and work perfectly on the next, with no code changes.

Environment

  • AIR SDK: 51.1.3.10
  • Platform: Windows 11 Pro (10.0.26200), x86 (32-bit ADL)
  • GPU Driver: DirectX 11 (Standard Extended profile)
  • Launch method: adl.exe -profile extendedDesktop

Windows Event Log

Faulting application: adl.exe, version: 51.1.3.10, timestamp: 0x67e42a03
Faulting module: Adobe AIR.dll, version: 51.1.3.10, timestamp: 0x67e42c3f
Exception code: 0xc0000005
Fault offset: 0x000b8a71

Binary Analysis of the Crash Site

I disassembled Adobe AIR.dll at the faulting offset. The crash is inside an internal sampler record parser function (not exported, starts at RVA 0x000B8A08):

; Function: parses individual sample records from the GC sampler buffer
; Signature: void parseSampleRecord(SampleRecord* out [esi], uint8** cursor [edx])

0x000B8A08: push  esi
0x000B8A09: mov   esi, [esp+0xC]       ; out struct (48 bytes)
0x000B8A0D: push  0x30
0x000B8A0F: push  0
0x000B8A11: push  esi
0x000B8A12: call  memset               ; zero-init output struct

; Read first pair (8 bytes) from cursor
0x000B8A1E: mov   ecx, [edx]           ; ecx = current stream position
0x000B8A20: mov   eax, [ecx]           ; read dword 1
0x000B8A22: mov   [esi], eax
0x000B8A24: mov   eax, [ecx+4]         ; read dword 2
0x000B8A27: mov   [esi+4], eax
0x000B8A2A: add   dword ptr [edx], 8   ; advance cursor

; Read type tag
0x000B8A2F: mov   eax, [[edx]]
0x000B8A31: mov   [esi+8], eax         ; store type tag
0x000B8A34: add   dword ptr [edx], 4

; Branch on type tag sentinel values:
0x000B8A37: cmp   [esi+8], 0xDDDDDDDD  ; stack-trace sample?
0x000B8A62: cmp   [esi+8], 0x55555555  ; DeleteObjectSample? → skip to end
0x000B8A7F: cmp   [esi+8], 0xAAAAAAAA  ; NewObjectSample?
0x000B8A8A: cmp   [esi+8], 0xEEEEEEEE  ; other sample type?

; >>> CRASH HERE: reading next record data
0x000B8A6F: mov   ecx, [edx]           ; ecx = current cursor position
0x000B8A71: mov   eax, [ecx]           ; CRASH! ecx is NULL or invalid

The function has 3 internal callers (at RVAs 0x000B8831, 0x000B8B81, 0x0045045A), all in sampler iteration loops. The caller at 0x000B8831 checks for 0xAAAAAAAA (NewObjectSample) immediately after the call, confirming this is the avmplus sampler subsystem.

Root Cause Analysis

The crash occurs because the sampler buffer read cursor ([edx]) points past valid data or into uninitialized memory. This is a race condition during early startup:

  1. Application calls sampleInternalAllocs(true) + startSampling() + setSamplerCallback() early in initialization
  2. The GC immediately begins writing sample records into the internal buffer
  3. The sampler callback fires (or the runtime iterates the buffer internally) before the buffer management is fully stabilized
  4. The cursor reads beyond valid data → ACCESS_VIOLATION

The intermittent nature confirms a timing-dependent race: sometimes the runtime initializes fast enough, sometimes it doesn't.

Minimal Reproduction

package {
    import flash.display.Sprite;
    import flash.sampler.sampleInternalAllocs;
    import flash.sampler.startSampling;
    import flash.sampler.setSamplerCallback;
    import flash.sampler.getSamples;
    import flash.sampler.clearSamples;

    public class SamplerCrashRepro extends Sprite {
        public function SamplerCrashRepro() {
            // Start sampler immediately at construction time
            sampleInternalAllocs(true);
            startSampling();
            setSamplerCallback(onSamplerFull);

            // Allocate objects to fill the sampler buffer quickly
            for (var i:int = 0; i < 10000; i++) {
                new Object();
            }
        }

        private function onSamplerFull():void {
            for each (var s:* in getSamples()) { /* process */ }
            clearSamples();
        }
    }
}

Note: The crash is non-deterministic. It may take 5-20 launches to reproduce. Using adl.exe with -profile extendedDesktop and ANE extensions loaded increases the likelihood, possibly due to additional initialization work competing with the sampler.

Workaround

Delaying sampler initialization by ~500ms via setTimeout avoids the race condition:

// Instead of immediate init:
setTimeout(function():void {
    sampleInternalAllocs(true);
    startSampling();
    setSamplerCallback(onSamplerFull);
}, 500);

Expected Behavior

Calling startSampling() + setSamplerCallback() at any point during application startup should be safe and not cause a native crash.

Additional Notes

  • mm.cfg has AS3Sampling=1 and AS3AutoStartSampling=1 (these are safe and do NOT trigger the MemoryTelemetrySampler conflict)
  • The SWF is not compiled with -advanced-telemetry (which would create a conflicting MemoryTelemetrySampler)
  • .telemetry.cfg only has TelemetryAddress (no SamplerEnabled or CPUCapture flags)
  • The crash is in the .text section at a non-exported internal function — no debug symbols available for Adobe AIR.dll

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions