State
Summary
On 1.9, the dedicated server compiles a large script set without errors, then crashes in #InitGlobals with "NULL pointer to instance". The trigger is the number of distinct generic instantiations (array<T>, map<K, V> and similar). At the edge of the limit, adding 30 classes, 450 functions or 80 KB of static data still boots, but adding 10 new array<T> types crashes. The stack trace names a vanilla line that never runs at startup, so the real cause is hard to find.
Steps to reproduce
It reproduces on a vanilla server with no mods. All it needs is one script file that declares enough distinct generic types.
Make an addon that depends only on the base game (58D0FB3206B6F859).
Add one script, Scripts/Game/ZZ_VanillaGenericProbe.c, with a class whose static methods declare locals of distinct generic types over vanilla classes: array<SCR_Timer>, array<SCR_TimerInternal> and so on, then map<int, T> and set<T> over the same classes. Each method holds 60 locals, under the 64-local cap. The method bodies never run.
Start the dedicated server (1.9.0.37, Diag build) with -gproj set to that addon on worlds/Eden/EmptyEden.ent.
Distinct generic types in the file Result Game module after compile
0 Boots 5,723 files, 11,093 classes, 31,246 KB static memory
6,000 Boots 17,092 classes, 53,430 KB
9,000 Boots 20,092 classes, 64,547 KB
9,093 Boots 20,185 classes, 64,904 KB
9,187 Crashes in #InitGlobals not printed
12,000 and 18,000 Crashes in #InitGlobals not printed
Two ready-made addons are attached: GenericProbeBoots (9,000 types) and GenericProbeCrash (9,500 types), plus the generator script and the class list used.
Expected and actual
Expected: the server starts, or fails with an error that names the limit, the count reached and the script that passed it.
Actual (Diag build): every script compiles, then the global initializer crashes:
SCRIPT (E): Virtual Machine Exception
Reason: NULL pointer to instance
Function: '#InitGlobals'
Stack trace:
scripts/Game/UI/HUD/AvailableActions/Conditions/Game/Character/SCR_CharacterHasGadgetInHandCondition.c:9 Function #InitGlobals
ENGINE (F): Crashed
Line 9 of that file is a return inside IsAvailable(), which doesn't run at startup. The location is the same whatever pushed the count over.
The release dedicated server prints only ENGINE (F): Crashed after "Compiling Game scripts", with no VM exception at all.
The "Module: Game; loaded …" summary line is never printed for a crashing run, so the log gives no count to compare against.
How we isolated it
We built a large script set that boots right at the edge, then added one kind of script at a time. Only new generic types tipped it over.
Added on top of the edge (Game module: 9,109 files, 20,174 classes, 60,469 KB) Classes after Static memory after Result
Nothing 20,174 60,469 KB Boots
30 empty classes 20,204 60,470 KB Boots
One class with static float s_ZZData[20000] 20,175 60,547 KB Boots
One class with 450 static functions 20,175 60,541 KB Boots
10 classes with 45 methods each 20,184 60,529 KB Boots
10 more array<T> locals over unused vanilla classes about 20,184 about 60,507 KB Crashes
Class count, static memory and plain method count are not the trigger on their own: each passed the values of the crashing run and still booted.
In the vanilla repro the threshold is much higher (about 9,100 extra types). So the limit seems to count something per generic instantiation that we can't see from script, for example entries the instantiations create inside the engine.
Load order made no difference.
Not ARMD-85 / T200535 or ARMD-96
Both existing issues describe different limits.
This report (dedicated server, 1.9)
- Fails: after compiling, in #InitGlobals
- Error: VM exception, "NULL pointer to instance"
- Trigger: distinct generic instantiations
ARMD-85 / T200535 (static initializer function)
- Fails: at compile time
- Error: "Too many instructions per function"
- Trigger: static initializers
ARMD-96 (Workbench, 1.8)
- Fails: at compile time
- Error: cascade of false errors in vanilla files
- Trigger: more than 8,092 .c files
Not the static-initializer budget. A crashing script set still had about 700 units of that budget spare, measured with const string probes. Moving about 1,880 units of vanilla static initializers out of that budget didn't stop the crash.
Not the file count. Our live server compiles 8,978 files and boots, and the vanilla repro crashes with only 5,723 files.
Why it matters to server communities
Large communities hit this limit within days of 1.9, and nothing in the log tells them what it is.
Whatever loads last gets blamed. Any script that pushes the total over triggers it, even when it works fine on its own.
The error points elsewhere. Owners chase a vanilla HUD condition file, and the release server shows only "Crashed".
Finding room costs days. The only way is boot-testing combinations; isolating this took several hundred boots. Owners remove content by trial and error.
Routine updates can break a server overnight. An update that adds a few generic types can push a setup that ran yesterday over the limit.
Script authors can't see it. They test alone or in small setups, where the limit is far away.
Requests
Raise or remove the limit.
Report it plainly when it's hit: an error that names the limit, the count reached and the module or script that passed it, instead of a NULL pointer at an unrelated vanilla line.
Log the count and the headroom in the "Module: Game; loaded …" summary on every start, so owners can see how close they are before adding more content.
Document what counts against it, so script authors can keep their generic types down (for example by sharing container types).
Activity
You are not signed in. Please sign in to see more details and to reply.
State