X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=prvm_edict.c;h=5a51babb23b0ea47a863fea652306cadb44a14c5;hb=311b10bf7c30a704b06423e603b8264e95cdb442;hp=3af88f168757498a64f2b48fc1f03200e4d01a2c;hpb=c0d54f21bcaba56302f5e9475b8182056f4841c0;p=xonotic%2Fdarkplaces.git diff --git a/prvm_edict.c b/prvm_edict.c index 3af88f16..5a51babb 100644 --- a/prvm_edict.c +++ b/prvm_edict.c @@ -43,12 +43,9 @@ cvar_t prvm_errordump = {0, "prvm_errordump", "0", "write a savegame on crash to cvar_t prvm_reuseedicts_startuptime = {0, "prvm_reuseedicts_startuptime", "2", "allows immediate re-use of freed entity slots during start of new level (value in seconds)"}; cvar_t prvm_reuseedicts_neverinsameframe = {0, "prvm_reuseedicts_neverinsameframe", "1", "never allows re-use of freed entity slots during same frame"}; +static double prvm_reuseedicts_always_allow = 0; qboolean prvm_runawaycheck = true; -// LordHavoc: optional runtime bounds checking (speed drain, but worth it for security, on by default - breaks most QCCX features (used by CRMod and others)) -// enables detection of out of bounds memory access in the QuakeC code being run (in other words, prevents really exceedingly bad QuakeC code from doing nasty things to your computer) -qboolean prvm_boundscheck = true; - extern sizebuf_t vm_tempstringsbuf; //============================================================================ @@ -243,6 +240,8 @@ qboolean PRVM_ED_CanAlloc(prvm_edict_t *e) { if(!e->priv.required->free) return false; + if(prvm_reuseedicts_always_allow == realtime) + return true; if(realtime <= e->priv.required->freetime && prvm_reuseedicts_neverinsameframe.integer) return false; // never allow reuse in same frame (causes networking trouble) if(e->priv.required->freetime < prog->starttime + prvm_reuseedicts_startuptime.value) @@ -549,10 +548,10 @@ char *PRVM_UglyValueString (etype_t type, prvm_eval_t *val) dpsnprintf (line, sizeof (line), "void"); break; case ev_float: - dpsnprintf (line, sizeof (line), "%f", val->_float); + dpsnprintf (line, sizeof (line), "%.9g", val->_float); break; case ev_vector: - dpsnprintf (line, sizeof (line), "%f %f %f", val->vector[0], val->vector[1], val->vector[2]); + dpsnprintf (line, sizeof (line), "%.9g %.9g %.9g", val->vector[0], val->vector[1], val->vector[2]); break; default: dpsnprintf (line, sizeof (line), "bad type %i", type); @@ -1406,6 +1405,7 @@ void PRVM_ED_LoadFromFile (const char *data) spawned = 0; died = 0; + prvm_reuseedicts_always_allow = realtime; // parse ents while (1) @@ -1486,7 +1486,7 @@ void PRVM_ED_LoadFromFile (const char *data) } else { - if (developer.integer) // don't confuse non-developers with errors + if (developer.integer > 0) // don't confuse non-developers with errors { Con_Print("No spawn function for:\n"); PRVM_ED_Print(ent, NULL); @@ -1517,6 +1517,8 @@ void PRVM_ED_LoadFromFile (const char *data) } Con_DPrintf("%s: %i new entities parsed, %i new inhibited, %i (%i new) spawned (whereas %i removed self, %i stayed)\n", PRVM_NAME, parsed, inhibited, prog->num_edicts, spawned, died, spawned - died); + + prvm_reuseedicts_always_allow = 0; } void PRVM_FindOffsets(void) @@ -1573,6 +1575,7 @@ void PRVM_FindOffsets(void) prog->fieldoffsets.dimension_hit = PRVM_ED_FindFieldOffset("dimension_hit"); prog->fieldoffsets.dimension_solid = PRVM_ED_FindFieldOffset("dimension_solid"); prog->fieldoffsets.disableclientprediction = PRVM_ED_FindFieldOffset("disableclientprediction"); + prog->fieldoffsets.discardabledemo = PRVM_ED_FindFieldOffset("discardabledemo"); prog->fieldoffsets.dphitcontentsmask = PRVM_ED_FindFieldOffset("dphitcontentsmask"); prog->fieldoffsets.drawonlytoclient = PRVM_ED_FindFieldOffset("drawonlytoclient"); prog->fieldoffsets.exteriormodeltoclient = PRVM_ED_FindFieldOffset("exteriormodeltoclient"); @@ -1652,6 +1655,12 @@ void PRVM_FindOffsets(void) prog->fieldoffsets.jointtype = PRVM_ED_FindFieldOffset("jointtype"); prog->fieldoffsets.movedir = PRVM_ED_FindFieldOffset("movedir"); + prog->fieldoffsets.camera_transform = PRVM_ED_FindFieldOffset("camera_transform"); + prog->fieldoffsets.userwavefunc_param0 = PRVM_ED_FindFieldOffset("userwavefunc_param0"); + prog->fieldoffsets.userwavefunc_param1 = PRVM_ED_FindFieldOffset("userwavefunc_param1"); + prog->fieldoffsets.userwavefunc_param2 = PRVM_ED_FindFieldOffset("userwavefunc_param2"); + prog->fieldoffsets.userwavefunc_param3 = PRVM_ED_FindFieldOffset("userwavefunc_param3"); + prog->funcoffsets.CSQC_ConsoleCommand = PRVM_ED_FindFunctionOffset("CSQC_ConsoleCommand"); prog->funcoffsets.CSQC_Ent_Remove = PRVM_ED_FindFunctionOffset("CSQC_Ent_Remove"); prog->funcoffsets.CSQC_Ent_Spawn = PRVM_ED_FindFunctionOffset("CSQC_Ent_Spawn"); @@ -1686,6 +1695,7 @@ void PRVM_FindOffsets(void) prog->globaloffsets.dmg_save = PRVM_ED_FindGlobalOffset("dmg_save"); prog->globaloffsets.dmg_take = PRVM_ED_FindGlobalOffset("dmg_take"); prog->globaloffsets.drawfont = PRVM_ED_FindGlobalOffset("drawfont"); + prog->globaloffsets.drawfontscale = PRVM_ED_FindGlobalOffset("drawfontscale"); prog->globaloffsets.gettaginfo_forward = PRVM_ED_FindGlobalOffset("gettaginfo_forward"); prog->globaloffsets.gettaginfo_name = PRVM_ED_FindGlobalOffset("gettaginfo_name"); prog->globaloffsets.gettaginfo_offset = PRVM_ED_FindGlobalOffset("gettaginfo_offset"); @@ -1720,6 +1730,10 @@ void PRVM_FindOffsets(void) prog->globaloffsets.v_up = PRVM_ED_FindGlobalOffset("v_up"); prog->globaloffsets.view_angles = PRVM_ED_FindGlobalOffset("view_angles"); prog->globaloffsets.worldstatus = PRVM_ED_FindGlobalOffset("worldstatus"); + prog->globaloffsets.particles_alphamin = PRVM_ED_FindGlobalOffset("particles_alphamin"); + prog->globaloffsets.particles_alphamax = PRVM_ED_FindGlobalOffset("particles_alphamax"); + prog->globaloffsets.particles_colormin = PRVM_ED_FindGlobalOffset("particles_colormin"); + prog->globaloffsets.particles_colormax = PRVM_ED_FindGlobalOffset("particles_colormax"); // menu qc only uses some functions, nothing else prog->funcoffsets.m_draw = PRVM_ED_FindFunctionOffset("m_draw"); @@ -1928,7 +1942,7 @@ po_t *PRVM_PO_Load(const char *filename, mempool_t *pool) --q; if(*(q-1) != '"') break; - if(q - p >= (ssize_t) sizeof(inbuf)) + if((size_t)(q - p) >= (size_t) sizeof(inbuf)) break; strlcpy(inbuf, p, q - p); // not - 1, because this adds a NUL PRVM_PO_ParseString(decodedbuf + decodedpos, inbuf, sizeof(decodedbuf) - decodedpos); @@ -2308,6 +2322,20 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, char **required // later idea: include a list of authorized .po file checksums with the csprogs { qboolean deftrans = !!strcmp(PRVM_NAME, "client"); + if(deftrans) // once we have dotranslate_ strings, ALWAYS use the opt-in method! + { + for (i=0 ; iprogs->numglobaldefs ; i++) + { + const char *name; + name = PRVM_GetString(prog->globaldefs[i].s_name); + if((prog->globaldefs[i].type & ~DEF_SAVEGLOBAL) == ev_string) + if(name && !strncmp(name, "dotranslate_", 12)) + { + deftrans = false; + break; + } + } + } if(!strcmp(prvm_language.string, "dump")) { qfile_t *f = FS_OpenRealFile(va("%s.%s.po", filename, prvm_language.string), "w", false); @@ -2318,8 +2346,8 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, char **required { const char *name; name = PRVM_GetString(prog->globaldefs[i].s_name); - if(deftrans ? (!name || strncmp(name, "notranslate_", 12)) : (name && !strncmp(name, "dotranslate_"))) if((prog->globaldefs[i].type & ~DEF_SAVEGLOBAL) == ev_string) + if(deftrans ? (!name || strncmp(name, "notranslate_", 12)) : (name && !strncmp(name, "dotranslate_", 12))) { prvm_eval_t *val = (prvm_eval_t *)(prog->globals.generic + prog->globaldefs[i].ofs); const char *value = PRVM_GetString(val->string); @@ -2343,7 +2371,7 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, char **required { const char *name; name = PRVM_GetString(prog->globaldefs[i].s_name); - if(deftrans ? (!name || strncmp(name, "notranslate_", 12)) : (name && !strncmp(name, "dotranslate_"))) + if(deftrans ? (!name || strncmp(name, "notranslate_", 12)) : (name && !strncmp(name, "dotranslate_", 12))) if((prog->globaldefs[i].type & ~DEF_SAVEGLOBAL) == ev_string) { prvm_eval_t *val = (prvm_eval_t *)(prog->globals.generic + prog->globaldefs[i].ofs); @@ -2384,11 +2412,11 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, char **required if((float)((int)(val->_float)) == val->_float) dpsnprintf(buf, sizeof(buf), "%i", (int)(val->_float)); else - dpsnprintf(buf, sizeof(buf), "%f", val->_float); + dpsnprintf(buf, sizeof(buf), "%.9g", val->_float); value = buf; break; case ev_vector: - dpsnprintf(buf, sizeof(buf), "%f %f %f", val->vector[0], val->vector[1], val->vector[2]); value = buf; + dpsnprintf(buf, sizeof(buf), "%.9g %.9g %.9g", val->vector[0], val->vector[1], val->vector[2]); value = buf; break; case ev_string: value = PRVM_GetString(val->string); @@ -2709,9 +2737,6 @@ void PRVM_Init (void) Cmd_AddCommand ("menu_cmd", PRVM_GameCommand_Menu_f, "calls the menu QC function GameCommand with the supplied string as argument"); Cmd_AddCommand ("sv_cmd", PRVM_GameCommand_Server_f, "calls the server QC function GameCommand with the supplied string as argument"); - // COMMANDLINEOPTION: PRVM: -noboundscheck disables the bounds checks (security hole if CSQC is in use!) - prvm_boundscheck = !COM_CheckParm("-noboundscheck"); - Cvar_RegisterVariable (&prvm_language); Cvar_RegisterVariable (&prvm_traceqc); Cvar_RegisterVariable (&prvm_statementprofiling); @@ -2784,52 +2809,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]) { @@ -2844,12 +2855,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]; @@ -2869,16 +2886,14 @@ 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.integer >= 200) - Con_Printf("new engine string %p = \"%s\"\n", s, s); + if (developer_insane.integer) + Con_DPrintf("new engine string %p = \"%s\"\n", s, s); for (i = prog->firstfreeknownstring;i < prog->numknownstrings;i++) if (!prog->knownstrings[i]) break; @@ -2909,7 +2924,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 @@ -2928,8 +2943,8 @@ int PRVM_SetTempString(const char *s) if (!s) return 0; size = (int)strlen(s) + 1; - if (developer.integer >= 300) - Con_Printf("PRVM_SetTempString: cursize %i, size %i\n", vm_tempstringsbuf.cursize, size); + if (developer_insane.integer) + Con_DPrintf("PRVM_SetTempString: cursize %i, size %i\n", vm_tempstringsbuf.cursize, size); if (vm_tempstringsbuf.maxsize < vm_tempstringsbuf.cursize + size) { sizebuf_t old = vm_tempstringsbuf; @@ -2940,8 +2955,7 @@ int PRVM_SetTempString(const char *s) vm_tempstringsbuf.maxsize *= 2; if (vm_tempstringsbuf.maxsize != old.maxsize || vm_tempstringsbuf.data == NULL) { - if (developer.integer >= 100) - Con_Printf("PRVM_SetTempString: enlarging tempstrings buffer (%iKB -> %iKB)\n", old.maxsize/1024, vm_tempstringsbuf.maxsize/1024); + Con_DPrintf("PRVM_SetTempString: enlarging tempstrings buffer (%iKB -> %iKB)\n", old.maxsize/1024, vm_tempstringsbuf.maxsize/1024); vm_tempstringsbuf.data = (unsigned char *) Mem_Alloc(sv_mempool, vm_tempstringsbuf.maxsize); if (old.cursize) memcpy(vm_tempstringsbuf.data, old.data, old.cursize); @@ -2982,7 +2996,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((char **)oldstrings); + if (oldstrings_freeable) + Mem_Free((unsigned char *)oldstrings_freeable); + if (oldstrings_origin) + Mem_Free((char **)oldstrings_origin); } prog->numknownstrings++; } @@ -2993,7 +3012,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) @@ -3002,9 +3021,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])