Race condition in GetFunctionSig_Write() and other function signatures

Hi, I believe there’s a race condition in GetFunctionSig_Write() where multiple worker threads can progress past if (!Sig.IsValid()) and stomp on each other writing to the static FNiagaraVariable EmitVar (and potentially the static FNiagaraFunctionSignature Sig). We have seen this manifest when many Effect Instances using Data Channel write are spawned at the same time from a single system.

To mitigate, I moved the signature initialisation inside a static lambda.

		static const FNiagaraFunctionSignature OutSig = []
		{
			FNiagaraFunctionSignature Sig;
			static FNiagaraVariable EmitVar(FNiagaraTypeDefinition::GetBoolDef(), TEXT("Emit"));
			EmitVar.SetValue(FNiagaraBool(true));
			Sig.Name = TEXT("Write");
#if WITH_EDITORONLY_DATA
			NIAGARA_ADD_FUNCTION_SOURCE_INFO(Sig)
			Sig.Description = LOCTEXT("WriteFunctionDescription", "Writes data into the Data Channel at a specific index. Values in the DataChannel that are not written here are set to their defaults. Returns success if the index was valid and data was written into the Data Channel.");
#endif
			Sig.bMemberFunction = true;
			Sig.bRequiresExecPin = true;
			Sig.bWriteFunction = true;
			Sig.bSupportsGPU = false;//Cannot use direct index writes on GPU as we write into one shared buffer with all DIs using the same NDC data.
			Sig.AddInput(FNiagaraVariable(FNiagaraTypeDefinition(UNiagaraDataInterfaceDataChannelWrite::StaticClass()), TEXT("DataChannel interface")));
			Sig.AddInput(EmitVar, LOCTEXT("ExecuteWriteFlagTooltip", "If true then the write is executed, if false then this call is ignored and no write occurs."));
			Sig.AddInput(FNiagaraVariable(FNiagaraTypeDefinition::GetIntDef(), TEXT("Index")));
			Sig.AddOutput(FNiagaraVariable(FNiagaraTypeDefinition::GetBoolDef(), TEXT("Success")));
			Sig.RequiredInputs = IntCastChecked<int16>(Sig.Inputs.Num());//The user defines what we write in the graph.
			return Sig;
		}();
		return OutSig;



[Attachment Removed]

Steps to Reproduce[Attachment Removed]

Hi Ben,

This does look like a potential race condition and your fix is likely something we’ll also implement. It looks like the same issue may impact other FNiagaraFunctionSignature lazy initializers in NiagaraDataInterfaceDataChannelWrite and NiagaraDataInterfaceDataChannelRead, have you fixed those too?

I’ve created the following issue for tracking which should be visible publicly soon https://issues.unrealengine.com/issue/UE\-396123

[Attachment Removed]

Hi, yes I did the same thing in all the places where a static FNiagaraFunctionSignature was lazily initialised. Thanks

[Attachment Removed]

Thanks, we’ve applied a similar fix in UE6 CL#58113338 (afc0cf) - Niagara: Fix race condition in Niagara Data Channel function signature lazy init

[Attachment Removed]