From 32ad14f60b7967e3ec092687b193350771804cf2 Mon Sep 17 00:00:00 2001
From: havoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Date: Sun, 4 Apr 2010 23:14:40 +0000
Subject: [PATCH] change representation of string offsets for allocated strings
 and engine buffers to use 0x4000000 as base offset instead of using negative
 values, to reduce possibility of && and || operators (which do float compares
 to 0 in the vm) breaking on string variables

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@10066 d7cf8633-e32d-0410-b094-e92efae38249
::stable-branch::merge=d0129de1a042fd4244533d2a25663259588a1f8f
---
 prvm_edict.c | 85 +++++++++++++++++++++++++---------------------------
 1 file changed, 40 insertions(+), 45 deletions(-)

diff --git a/prvm_edict.c b/prvm_edict.c
index 2e137672..e227d612 100644
--- a/prvm_edict.c
+++ b/prvm_edict.c
@@ -2786,52 +2786,38 @@ unsigned int PRVM_EDICT_NUM_ERROR(unsigned int n, char *filename, int fileline)
 }
 
 sizebuf_t vm_tempstringsbuf;
+#define PRVM_KNOWNSTRINGBASE 0x40000000
 
 const char *PRVM_GetString(int num)
 {
-	if (num >= 0)
+	if (num < 0)
 	{
-		if (num < prog->stringssize)
-			return prog->strings + num;
-		else
-#if 1
-		if (num <= prog->stringssize + vm_tempstringsbuf.maxsize)
-		{
-			num -= prog->stringssize;
-			if (num < vm_tempstringsbuf.cursize)
-				return (char *)vm_tempstringsbuf.data + num;
-			else
-			{
-				VM_Warning("PRVM_GetString: Invalid temp-string offset (%i >= %i vm_tempstringsbuf.cursize)\n", num, vm_tempstringsbuf.cursize);
-				return "";
-			}
-		}
+		// invalid
+		VM_Warning("PRVM_GetString: Invalid string offset (%i < 0)\n", num);
+		return "";
+	}
+	else if (num < prog->stringssize)
+	{
+		// constant string from progs.dat
+		return prog->strings + num;
+	}
+	else if (num <= prog->stringssize + vm_tempstringsbuf.maxsize)
+	{
+		// tempstring returned by engine to QC (becomes invalid after returning to engine)
+		num -= prog->stringssize;
+		if (num < vm_tempstringsbuf.cursize)
+			return (char *)vm_tempstringsbuf.data + num;
 		else
-#endif
 		{
-			VM_Warning("PRVM_GetString: Invalid constant-string offset (%i >= %i prog->stringssize)\n", num, prog->stringssize);
+			VM_Warning("PRVM_GetString: Invalid temp-string offset (%i >= %i vm_tempstringsbuf.cursize)\n", num, vm_tempstringsbuf.cursize);
 			return "";
 		}
 	}
-	else
+	else if (num & PRVM_KNOWNSTRINGBASE)
 	{
-		num = -1 - num;
-#if 0
-		if (num >= (1<<30))
-		{
-			// special range reserved for tempstrings
-			num -= (1<<30);
-			if (num < vm_tempstringsbuf.cursize)
-				return (char *)vm_tempstringsbuf.data + num;
-			else
-			{
-				VM_Warning("PRVM_GetString: Invalid temp-string offset (%i >= %i vm_tempstringsbuf.cursize)\n", num, vm_tempstringsbuf.cursize);
-				return "";
-			}
-		}
-		else
-#endif
-		if (num < prog->numknownstrings)
+		// allocated string
+		num = num - PRVM_KNOWNSTRINGBASE;
+		if (num >= 0 && num < prog->numknownstrings)
 		{
 			if (!prog->knownstrings[num])
 			{
@@ -2846,12 +2832,18 @@ const char *PRVM_GetString(int num)
 			return "";
 		}
 	}
+	else
+	{
+		// invalid string offset
+		VM_Warning("PRVM_GetString: Invalid constant-string offset (%i >= %i prog->stringssize)\n", num, prog->stringssize);
+		return "";
+	}
 }
 
 const char *PRVM_ChangeEngineString(int i, const char *s)
 {
 	const char *old;
-	i = -1 - i;
+	i = i - PRVM_KNOWNSTRINGBASE;
 	if(i < 0 || i >= prog->numknownstrings)
 		PRVM_ERROR("PRVM_ChangeEngineString: s is not an engine string");
 	old = prog->knownstrings[i];
@@ -2871,13 +2863,11 @@ int PRVM_SetEngineString(const char *s)
 	if (s >= (char *)vm_tempstringsbuf.data && s < (char *)vm_tempstringsbuf.data + vm_tempstringsbuf.maxsize)
 #if 1
 		return prog->stringssize + (s - (char *)vm_tempstringsbuf.data);
-#else
-		return -1 - ((1<<30) + (s - (char *)vm_tempstringsbuf.data));
 #endif
 	// see if it's a known string address
 	for (i = 0;i < prog->numknownstrings;i++)
 		if (prog->knownstrings[i] == s)
-			return -1 - i;
+			return PRVM_KNOWNSTRINGBASE + i;
 	// new unknown engine string
 	if (developer_insane.integer)
 		Con_DPrintf("new engine string %p = \"%s\"\n", s, s);
@@ -2911,7 +2901,7 @@ int PRVM_SetEngineString(const char *s)
 	prog->knownstrings_freeable[i] = false;
 	if(prog->leaktest_active)
 		prog->knownstrings_origin[i] = NULL;
-	return -1 - i;
+	return PRVM_KNOWNSTRINGBASE + i;
 }
 
 // temp string handling
@@ -2983,7 +2973,12 @@ int PRVM_AllocString(size_t bufferlength, char **pointer)
 				if(prog->leaktest_active)
 					memcpy((char **)prog->knownstrings_origin, oldstrings_origin, prog->numknownstrings * sizeof(char *));
 			}
-			// TODO why not Mem_Free the old ones?
+			if (oldstrings)
+				Mem_Free(oldstrings);
+			if (oldstrings_freeable)
+				Mem_Free((unsigned char *)oldstrings_freeable);
+			if (oldstrings_origin)
+				Mem_Free(oldstrings_origin);
 		}
 		prog->numknownstrings++;
 	}
@@ -2994,7 +2989,7 @@ int PRVM_AllocString(size_t bufferlength, char **pointer)
 		prog->knownstrings_origin[i] = PRVM_AllocationOrigin();
 	if (pointer)
 		*pointer = (char *)(prog->knownstrings[i]);
-	return -1 - i;
+	return PRVM_KNOWNSTRINGBASE + i;
 }
 
 void PRVM_FreeString(int num)
@@ -3003,9 +2998,9 @@ void PRVM_FreeString(int num)
 		PRVM_ERROR("PRVM_FreeString: attempt to free a NULL string");
 	else if (num >= 0 && num < prog->stringssize)
 		PRVM_ERROR("PRVM_FreeString: attempt to free a constant string");
-	else if (num < 0 && num >= -prog->numknownstrings)
+	else if (num >= PRVM_KNOWNSTRINGBASE && num < PRVM_KNOWNSTRINGBASE + prog->numknownstrings)
 	{
-		num = -1 - num;
+		num = num - PRVM_KNOWNSTRINGBASE;
 		if (!prog->knownstrings[num])
 			PRVM_ERROR("PRVM_FreeString: attempt to free a non-existent or already freed string");
 		if (!prog->knownstrings_freeable[num])
-- 
2.39.5