Page MenuHomeFeedback Tracker

Nested array initalizer builder pattern script-vm bug
Assigned, NormalPublic

Description

This is going to be a convoluted mess but it is as simple as I could make it to reproduce. The following code uses a builder pattern to construct values to be put into an array that is initialized via the {...} syntax.
There is a nullptr for arguments passed in the chain as well as sometimes some crash to deaths but ONLY if the builder is used at least twice in the array. There seems to be something going on with the reference counting because a "workaround" is to store each instance created in the builder chain in a static strong ref array which keeps them alive for sure. With it everything works.

So here is the code that will cause the nullptr/crash:

class REPRODUCE_Builder
{
	//------------------------------------------------------------------------------------------------
	static REPRODUCE_FirstSelector BuildFirst()
	{
		return REPRODUCE_FirstSelector.Create();
	}
};

class REPRODUCE_FirstSelector
{
	protected static ref array<ref REPRODUCE_FirstSelector>> ALLOC_BUFFER = {null};

	//------------------------------------------------------------------------------------------------
	REPRODUCE_SecondSelector SelectOption()
	{
		return REPRODUCE_SecondSelector.Create(new REPORDUCE_InvokeOn());
	}

	//------------------------------------------------------------------------------------------------
	static REPRODUCE_FirstSelector Create()
	{
		auto inst = new REPRODUCE_FirstSelector();
		//ALLOC_BUFFER.Set(0, inst);
		return inst;
	}
};

class REPRODUCE_SecondSelector
{
	protected static ref array<ref REPRODUCE_SecondSelector>> ALLOC_BUFFER = {null};

	protected ref REPORDUCE_InvokeOn m_pInvokeOn;

	//------------------------------------------------------------------------------------------------
	bool BuildResult()
	{
		m_pInvokeOn.DoSomething();
		return true;
	}

	//------------------------------------------------------------------------------------------------
	static REPRODUCE_SecondSelector Create(REPORDUCE_InvokeOn invoker)
	{
		auto inst = new REPRODUCE_SecondSelector();
		inst.m_pInvokeOn = invoker;
		//ALLOC_BUFFER.Set(0, inst);
		return inst;
	}
};

class REPORDUCE_InvokeOn
{
	void DoSomething()
	{
		Print("hello!");
	}
};

void ReproduceCrash()
{
	array<bool> data = {
		REPRODUCE_Builder.BuildFirst().SelectOption().BuildResult(),
		REPRODUCE_Builder.BuildFirst().SelectOption().BuildResult()
	};
	Print(data);
};

When calling ReproduceCrash, you will see just one hello printing and on the second time it reaches that code the m_pInvokeOn variable is now null

13:11:37.135 SCRIPT : hello!
13:11:37.136 SCRIPT (E): NULL pointer to instance
Class: 'REPRODUCE_SecondSelector'
Function: 'BuildResult'
Stack trace:
Scripts/Game/EnscriptReproduction.c:38 Function BuildResult
Scripts/Game/EnscriptReproduction.c:62 Function ReproduceCrash

Notice the commented lines with ALLOC_BUFFER calls. If those 2 lines inside the static create methods are uncommented then the whole thing works as intended and produces the following output:

SCRIPT       : hello!
SCRIPT       : hello!
SCRIPT       : array<bool> data = 0x0000017431B59A38 {1,1}

Details

Severity
Crash
Resolution
Open
Reproducibility
Always
Operating System
Windows 10 x64
Category
General

Event Timeline

Arkensor created this task.Jun 4 2023, 1:13 PM
Geez changed the task status from New to Assigned.Jun 6 2023, 2:46 PM
Geez closed this task as Resolved.Jun 9 2023, 11:01 AM
Geez claimed this task.
Geez added a subscriber: Geez.

Resolved for one of the future updates.

Some cases appear to be fixed, but there are still issues associated with this issue. Please reopen.

2023-07-17 15:20:42 (UTC) : Version: 0.9.9.38 - Report Successful (Crash GUID: d98af92c-32e4-4a9c-bfdd-30be6eb5b356)

I have forwarded the reproduction details to Mario.

Geez reopened this task as Assigned.Jul 18 2023, 9:43 AM