Minimal reproduction — flutter/flutter#190809
Loading a FragmentProgram on Windows kills the process with 0xC0000005
inside d3dcompiler_47.dll, while Impeller's ANGLE backend compiles the runtime
stage.
flutter pub get
flutter run -d windowsThe app dies within a few seconds and flutter run prints
Lost connection to device. No environment variables, no scripts, nothing else
required.
To see the faulting stack instead of a silent exit, set one variable first:
$env:FLUTTER_REPRO_CRASH_TRACE = '1'
flutter run -d windowsThat enables a small vectored exception handler in the runner
(windows/runner/native_crash_reporter.cpp) which prints module+offset frames
to stderr. It is off by default and is not part of the bug.
Expected: the app paints two shaders for 30 seconds, prints
clean timeout reached; exiting normally, exits 0.
Actual: access violation in d3dcompiler_47.dll, exit 0xC0000005.
| Item | Value |
|---|---|
| Flutter | 3.47.0-0.1.pre (beta) |
| Framework revision | bd1e75d918605c91b411e8789fb911e6c9a84534 |
| Engine revision | bbd15867c003dc66e678cb3c218649fa8bf914f2 |
flutter_windows.dll SHA-256 |
7902667F7BE09E606AEC1A8679AD53EC02B1E25CA580F525C114FEE8AD697635 |
| OS | Windows 11 Pro build 26200 x64 |
| GPU | NVIDIA RTX 3080, driver 595.95 (32.0.15.9595) |
| Toolchain | VS 2022 17.14.36, Windows SDK 10.0.26100.0 |
| Backend | Using the Impeller rendering backend (OpenGLESSDF) |
Module offsets are only comparable within a single engine revision.
Also reproduces on 3.47.0-0.3.pre (engine effb186f31…) and on the current
beta 3.47.0-0.4.pre (engine f88005a259…).
A default Flutter app, one main.dart, and two .frag files. Dependencies are
flutter, flutter_test, flutter_lints only. There are no image or media
assets — the shaders are the only declared assets, and sampler inputs are
synthetic in-memory 64×64 solid colours. The two shaders are production sources
with comments and whitespace stripped; their compiled blobs are 9,632 bytes
(parallax) and 23,096 bytes (lighting).
--dart-define=SHADER_MODE= selects what runs: both (default), lighting,
parallax, or load_only. That switch exists because it isolates the two
findings below.
1. Neither program has to be used for painting. With
--dart-define=SHADER_MODE=load_only the app never calls
FragmentProgram.fragmentShader() and never issues a canvas draw with either
program — and still dies with the same signature. Loading is sufficient.
Ordinary Flutter UI still renders, so this rules out use of the runtime effect,
not rendering in general. The Dart future from FragmentProgram.fromAsset
completes normally first; the fault lands afterwards.
2. It is specific to one of the two shaders. SHADER_MODE=lighting loads
only the larger program and crashes. SHADER_MODE=parallax loads only the
smaller one, configures it, paints with it, and exits cleanly. Since lighting
skips the parallax load entirely, this is not a load-ordering effect.
The responsible shader property is not isolated. The two differ at once in uniform count (~161 vs 9 float components), sampler count (4 vs 2), array declarations, control flow, generated HLSL and blob size. No delta-reduction was run to find a threshold.
Symbolized under cdb; d3dcompiler_47 symbols come from the Microsoft public
symbol server.
d3dcompiler_47!CShaderProgram::AssignCBSlots_Misc+0x2bc <-- faults here
d3dcompiler_47!CShaderProgram::AssignCBSlots+0x112
d3dcompiler_47!CD3D10Program::GenerateCode+0x2f9
d3dcompiler_47!CCompiler::EmitAndGenerateCode+0x161
d3dcompiler_47!CCompiler::CompileInternal+0x511
d3dcompiler_47!D3DCompileShader+0x177
d3dcompiler_47!D3DCompileImpl+0x1b2
d3dcompiler_47!D3DCompileSaveReplay+0xed
d3dcompiler_47!D3DCompile2+0xc9
d3dcompiler_47!D3DCompile+0x6c
flutter_windows+0xefa13d (ANGLE, called D3DCompile)
flutter_windows+0xeb70d0
flutter_windows+0xf084a2
flutter_windows+0xefeac8
Fault address d3dcompiler_47.dll+0x77ebc, READ at 0xffffffffffffffff. This
address and the whole d3dcompiler_47 chain are identical on all three engines
tested, because that DLL is a Windows system library rather than a Flutter
artifact; only the ANGLE frames move.
The top public symbol is AssignCBSlots_Misc — HLSL constant-buffer slot
assignment. That is suggestive given the uniform-count difference, but it is a
candidate explanation, not an isolated cause.
Caveats: .ecxr returns Unable to get exception context, HRESULT 0x8000FFFF,
so frames come from the break-in context at the first-chance AV. There are no
public PDBs for flutter_windows.dll, so the debugger resolves its frames to
the nearest exported symbol plus a huge offset; those names are meaningless and
only module+offset is quoted. To capture a dump yourself, use
.dump /mrR — /mp includes the process environment block.
Everything above needs only flutter run. run_repro.ps1 exists to run the
controls reproducibly and record evidence; it is tooling, not part of the bug.
.\run_repro.ps1 -Mode both -DurationSeconds 30 -Clean-Mode |
Impeller | Result | Exit code |
|---|---|---|---|
both (clean build) ×2 |
on | crash, signature matched | 0xC0000005 |
lighting |
on | crash, signature matched | 0xC0000005 |
load_only |
on | crash, signature matched | 0xC0000005 |
parallax |
on | control passed | 0 |
both |
off | control passed | 0 |
Each run used a 30-second configured timeout; crashing runs end earlier. Logs
are retained under logs\. Add -AllowAnyEngine to test a different SDK, which
classifies on fault module and fault type rather than exact offsets.
One trap worth knowing if you write your own controls: flutter run does not
propagate FLUTTER_ENGINE_SWITCHES to the application process. An
"Impeller disabled" run launched through flutter run still starts Impeller and
still crashes, which reads as "not Impeller-specific." My first Impeller-off
control was invalid for exactly that reason. run_repro.ps1 builds and launches
the .exe directly to avoid it, and fails if -ImpellerOff is requested but
Impeller starts anyway. flutter run also reported exit code 0 after the app
had died of an access violation, so classify from the log, not the CLI.