Page 1 of 1

GetPropertyText fails beyond 1024+x chars

Posted: Wed Oct 10, 2018 4:23 am
by Barbie
GetPropertyText() causes an UT crash if the text exceeds 1024+some more. Is there a possibility to clamp the text at - lets say 1023 characters?

Core of my test code (there is a SpecialEvent with a text of a length of 1030):

Code: Select all

if (FindActorByName('SpecialEvent0', SE)) {
	// this works:
	//TextLen = Len(SpecialEvent(SE).Message);
	// but this not:
	TextLen = Len(SE.GetPropertyText("Message"));
	BroadcastMessage(SE @ "text lenght is" @ TextLen);
}
Test map is attached (beware - it will crash your UT if you touch the Trigger.)

Re: GetPropertyText fails beyond 1024+x chars

Posted: Wed Oct 10, 2018 5:16 am
by Chris
The native side of UT sometimes relies on the function

Code: Select all

GetStaticString1024();
This is intended to interface a static string stack for temporary strings to avoid allocating/deallocating strings heavily due to the cost of malloc/dealloc.
It's very useful in that it saves a lot of processor time. The downside is that the blocksize is limited. Thus each string is limited to 1024 (1023 + nullterminator). In most cases it doesn't hurt to use more than 1023 in terms of risking
heap corruption because, if I recall, the stack is [512][1024], so there are 512 x 1024 * sizeof(wchar_t) (which is 2 on MSVC). So unless you're on the last row in the stack, it wont go out of bounds completely. Of course, when the function is called next time it will overwrite anything beyond 1024 and destroy the null-terminator, thus causing havoc in other ways.

Conclusion? Don't ever use strings larger than 1023, Ever!
A string that large is very rare, and would most often never be seen other than during testing. It also takes forever to process for obvious reasons.

You can clamp the text using Str = Left(Str, 1023);
It may or may not help, depends on GetPropertyText and how it handles the result.
The string itself isn't limited, but the static string stack is, thus any function that uses it together with a string larger than 1023 will cause corruption.
So don't use GetPropertyText here, use the member access operator and then clamp the message using Left().

P.S That special event should be thrown away and tucked under something that will never see daylight again. :loool:

Re: GetPropertyText fails beyond 1024+x chars

Posted: Wed Oct 10, 2018 7:23 am
by Higor
It uses a local stack buffer, and they knew exactly what they were doing (check the //!! comment)

Code: Select all

void UObject::execGetPropertyText( FFrame& Stack, RESULT_DECL )
{
	P_GET_STR(PropName);
	P_FINISH;

	UProperty* Property=FindField<UProperty>( Class, *PropName );
	if( Property && (Property->GetFlags() & RF_Public) )
	{
		TCHAR Temp[1024]=TEXT("");//!!
		Property->ExportText( 0, Temp, (BYTE*)this, (BYTE*)this, PPF_Localized );
		*(FString*)Result = Temp;
	}
	else *(FString*)Result = TEXT("");
}

Re: GetPropertyText fails beyond 1024+x chars

Posted: Wed Oct 10, 2018 4:23 pm
by Barbie
I run into this on the attempt to patch a map on loading: Because the Translator does not work in UT I wanted to add a Trigger/SpecialEvent at every TranslatorEvent, copy the properties, and display the message if a player touches the Trigger. Unfortunately the mapper has used a custom version of TranslatorEvent and did it not as a sub class of TranslatorEvent. So I had to read the message via "GetPropertyText()".

It seems there will be no way to do that via UScript...

Re: GetPropertyText fails beyond 1024+x chars

Posted: Wed Oct 10, 2018 6:39 pm
by Chris
Higor wrote:It uses a local stack buffer, and they knew exactly what they were doing (check the //!! comment)

Code: Select all

void UObject::execGetPropertyText( FFrame& Stack, RESULT_DECL )
{
	P_GET_STR(PropName);
	P_FINISH;

	UProperty* Property=FindField<UProperty>( Class, *PropName );
	if( Property && (Property->GetFlags() & RF_Public) )
	{
		TCHAR Temp[1024]=TEXT("");//!!
		Property->ExportText( 0, Temp, (BYTE*)this, (BYTE*)this, PPF_Localized );
		*(FString*)Result = Temp;
	}
	else *(FString*)Result = TEXT("");
}
They may have known what they were doing, yet they failed to make sure a stack corruption would never occur. It could easily have been avoided by not writing outside the buffer.