Access violation at startup — `ConstructorHelpers` in CDOs vs. the `PostConfigInit` loading phase
Describe the bug
Adding the Carla plugin to any project whose startup ordering differs from
CarlaUnreal's kills the process before a map is ever opened:
Unhandled Exception: EXCEPTION_ACCESS_VIOLATION reading address 0x120
ATrafficLightManager::ATrafficLightManager()
ConstructorHelpers::FClassFinder<AActor>::FClassFinder<AActor>()
StaticLoadClass() -> LoadPackage() -> FlushAsyncLoading()
FLinkerLoad::CreateExport()
FBlueprintCompilationManager::FlushCompilationQueue()
UE::ProjectUtilities::FindModuleDescriptorHostType()
FModuleManager::LoadModule()
FLiveCodingModule::StartupModule() <-- faults here
UClass::CreateDefaultObject()
UObjectLoadAllCompiledInDefaultProperties()
ProcessNewlyLoadedUObjects()
FEngineLoop::PreInitPostStartupScreen()Cause
Carla.uplugin sets "LoadingPhase": "PostConfigInit", which it must: the
module registers global shaders (IMPLEMENT_SHADER_TYPE in
Util/CameraModelUtil.cpp) and those have to exist before the engine
initialises shader types — moving the module to Default instead trips
Assertion failed: !AreShaderTypesInitialized().
But that same phase means every CDO in the module is constructed inside
FEngineLoop::PreInitPostStartupScreen, and several of those constructors load
/Game/ packages:
| file | what it loads |
|---|---|
Traffic/TrafficLightManager.cpp |
14 FClassFinders (traffic lights, stop/yield/speed-limit signs) |
Commandlet/LoadAssetMaterialsCommandlet.cpp |
RoadPainterPreset blueprint |
Commandlet/PrepareAssetsForCookingCommandlet.cpp |
7 material instances |
Loading a Blueprint there drags the Kismet compilation manager into PreInit,
which lazily loads the LiveCoding module, whose StartupModule then creates a
CDO and dies in CastChecked<UPackage>. -NoLiveCoding does not help: it
disables the feature, not the module load.
LoadAssetMaterialsCommandlet additionally dereferences the finder result with
no null check (RoadPainterBlueprint.Object->GeneratedClass), so a genuinely
missing asset is an access violation rather than a log line.
Suggested fix
Do not load /Game/ assets from CDO constructors in a PostConfigInit module.
Resolve them on first use with LoadObject/LoadClass instead. For
ATrafficLightManager that means moving the 14 finders into a
LoadDefaultModels() called from GenerateSignalsAndTrafficLights(), which
already null-checks the models it needs. Plugin-mounted paths (/Carla/...,
as in OpenDriveActor.cpp) are fine — they mount with the module.
This is not hypothetical for other projects only: it is why the plugin cannot currently be dropped into an existing Unreal project.
Environment
- CARLA
ue58-dev-carla@de3f38e64, CARLA fork of UE 5.8, Windows 11
Source: carla-simulator/carla