halflife icon indicating copy to clipboard operation
halflife copied to clipboard

[HL][TFC] Crash while parsing command menu (menu item length)

Open pizzahut2 opened this issue 1 month ago • 4 comments

Not related to https://github.com/ValveSoftware/halflife/issues/1730 apart from that it also happens in the command menu.

There have been reports by French TFC players experiencing a crash when trying to join a server, with the proposed work-around being to delete the "tfc_french" folder. I tried to reproduce the crash and find out what's causing it, with success.

It seems to be HL25 specific, so not happening when using the steam_legacy branch.

Quoting myself:

I fixed the "tfc_french" folder. The culprit was the "commandmenu.txt". There is a bug in the current version of TFC which causes it to crash if a menu item is longer than 31 characters. The old version of TFC (steam_legacy) is not affected. So this is a bug introduced with the 25th anniversary update of Half-Life.

On a side note, the French command menu file uses ANSI instead of UTF-8. Diacritics show up, so I guess it's not an issue.

Related discussion: https://steamcommunity.com/app/20/discussions/0/601891815092683482/

Diff: french_commandmenu.diff.txt I only removed the single quotes to fit more letters into the maximum of 31 characters. The command string can be longer.

Test case 1 "8" "You finish building the dispenser." "say OK" A buffer overflow occurs if the original string is too long in the button text.

Test case 2 "8" "#Dispenser_finish" "say OK" A buffer overflow occurs if the substituted string is too long in the button text.

These are triggered in two different code segments of "CHudTextMessage::LocaliseTextString" in "cl_dll/text_message.cpp".

pizzahut2 avatar Nov 12 '25 20:11 pizzahut2

Work-around for German language: german_commandmenu.diff.txt

No other languages are affected.

pizzahut2 avatar Nov 16 '25 17:11 pizzahut2

I'm looking at cl_dll/vgui_TeamFortressViewport.cpp#L817-L821 and cl_dll/text_message.cpp#L47-L85 . This is the client DLL for Half-Life.

At CHudTextMessage::LocaliseTextString , line 85 it adds a zero behind the current position.

			dst++, src++;
			*dst = 0;

If the source string is longer than the destination, then this means a zero is added behind the buffer (buffer overflow).

Though I don't know if this is actually causing the crash, and also this is the HL client DLL, not the one for TFC.

vgui_TeamFortressViewport.cpp#L817-L821

			cText[31] = '\0';

			// Get the button text
			pfile = gEngfuncs.COM_ParseFile(pfile, token);
			CHudTextMessage::LocaliseTextString( token, cText, sizeof( cText ) );

As a work-around, "sizeof( cText )" could be decreased by one. But the actual bug is in "CHudTextMessage::LocaliseTextString" as described above.

text_message.cpp#L47-L87

char *CHudTextMessage::LocaliseTextString( const char *msg, char *dst_buffer, int buffer_size )
{
	int len = buffer_size;
	char *dst = dst_buffer;
	for ( char *src = (char*)msg; *src != 0 && buffer_size > 0; buffer_size-- )
	{
		if ( *src == '#' )
[...]
		else
		{
			*dst = *src;
			dst++, src++;
			*dst = 0;
		}
	}

The "if" part looks dangerous as well. If a "#" is found, and a corresponding entry in "titles.txt", it copies to the destination without checking if the buffer is long enough.

			// copy string into message over the msg name
			for ( char *wsrc = (char*)clmsg->pMessage; *wsrc != 0; wsrc++, dst++ )
			{
				*dst = *wsrc;
			}
			*dst = 0;

The call to "CHudTextMessage::LocaliseTextString" was added to "vgui_TeamFortressViewport.cpp" with the HL25 SDK Update.

Image

Test case 1 "8" "You finish building the dispenser." "say OK" A buffer overflow occurs if the original string is too long in the button text.

Test case 2 "8" "#Dispenser_finish" "say OK" A buffer overflow occurs if the substituted string is too long in the button text.

These are triggered in two different code segments of "CHudTextMessage::LocaliseTextString" in "cl_dll/text_message.cpp".

pizzahut2 avatar Nov 18 '25 01:11 pizzahut2

Proposing a fix for "CHudTextMessage::LocaliseTextString" in "cl_dll/text_message.cpp". It's untested, maybe someone could check if it works? @SamVanheer @kisak-valve @shawns-valve

https://github.com/ValveSoftware/halflife/compare/b1b5cf5892918535619b2937bb927e46cb097ba1...pizzahut2:halflife:patch-1

pizzahut2 avatar Nov 21 '25 12:11 pizzahut2

In the latest English build version 10210 of Half-Life, if a command menu button text exceeds 32 characters (including the null terminator), the game writes past the end of the fixed size cText[32] buffer, causing a crash. This does not appear to be caused by using non-English characters, but some locale specific builds of TFC, such as German and French, will immediately crash to desktop upon creating or connecting to a server on the Windows build, because the button text simply exceeds the buffer size. I was unable to reproduce this issue on Linux or in Counter-Strike 1.6 on Windows. I have tested the proposed patch to CHudTextMessage::LocaliseTextString, and it appears to fix the crash reliably.

0Ky avatar Nov 21 '25 19:11 0Ky