cvar_t prvm_coverage = {0, "prvm_coverage", "0", "report and count coverage events (1: per-function, 2: coverage() builtin, 4: per-statement)"};
cvar_t prvm_backtraceforwarnings = {0, "prvm_backtraceforwarnings", "0", "print a backtrace for warnings too"};
cvar_t prvm_leaktest = {0, "prvm_leaktest", "0", "try to detect memory leaks in strings or entities"};
+cvar_t prvm_leaktest_follow_targetname = {0, "prvm_leaktest_follow_targetname", "0", "if set, target/targetname links are considered when leak testing; this should normally not be required, as entities created during startup - e.g. info_notnull - are never considered leaky"};
cvar_t prvm_leaktest_ignore_classnames = {0, "prvm_leaktest_ignore_classnames", "", "classnames of entities to NOT leak check because they are found by find(world, classname, ...) but are actually spawned by QC code (NOT map entities)"};
cvar_t prvm_errordump = {0, "prvm_errordump", "0", "write a savegame on crash to crash-server.dmp"};
cvar_t prvm_breakpointdump = {0, "prvm_breakpointdump", "0", "write a savegame on breakpoint to breakpoint-server.dmp"};
=================
PRVM_ED_ClearEdict
-Sets everything to NULL
+Sets everything to NULL.
+
+Nota bene: this also marks the entity as allocated if it has been previously
+freed and sets the allocation origin.
=================
*/
void PRVM_ED_ClearEdict(prvm_prog_t *prog, prvm_edict_t *e)
{
memset(e->fields.fp, 0, prog->entityfields * sizeof(prvm_vec_t));
e->priv.required->free = false;
+ e->priv.required->freetime = realtime;
+ if(e->priv.required->allocation_origin)
+ Mem_Free((char *)e->priv.required->allocation_origin);
+ e->priv.required->allocation_origin = PRVM_AllocationOrigin(prog);
// AK: Let the init_edict function determine if something needs to be initialized
prog->init_edict(prog, e);
if(PRVM_ED_CanAlloc(prog, e))
{
PRVM_ED_ClearEdict (prog, e);
- e->priv.required->allocation_origin = PRVM_AllocationOrigin(prog);
return e;
}
}
PRVM_MEM_IncreaseEdicts(prog);
e = PRVM_EDICT_NUM(i);
- PRVM_ED_ClearEdict(prog, e);
-
- e->priv.required->allocation_origin = PRVM_AllocationOrigin(prog);
+ PRVM_ED_ClearEdict(prog, e);
return e;
}
prog->error_cmd("PRVM_ED_ParseEdict: parse error");
}
- if (!init)
+ if (!init) {
ent->priv.required->free = true;
+ ent->priv.required->freetime = realtime;
+ }
return data;
}
// init mempools
PRVM_MEM_Alloc(prog);
+
+ // Inittime is at least the time when this function finished. However,
+ // later events may bump it.
+ prog->inittime = realtime;
}
Cvar_RegisterVariable (&prvm_coverage);
Cvar_RegisterVariable (&prvm_backtraceforwarnings);
Cvar_RegisterVariable (&prvm_leaktest);
+ Cvar_RegisterVariable (&prvm_leaktest_follow_targetname);
Cvar_RegisterVariable (&prvm_leaktest_ignore_classnames);
Cvar_RegisterVariable (&prvm_errordump);
Cvar_RegisterVariable (&prvm_breakpointdump);
char vabuf2[1024];
if(PRVM_NUM_FOR_EDICT(edict) <= prog->reserved_edicts)
return true; // world or clients
+ if (edict->priv.required->freetime <= prog->inittime)
+ return true; // created during startup
if (prog == SVVM_prog)
{
if(PRVM_serveredictfloat(edict, solid)) // can block other stuff, or is a trigger?
int edictnum = PRVM_NUM_FOR_EDICT(edict);
const char *targetname = NULL;
- if (prog == SVVM_prog)
+ if (prog == SVVM_prog && prvm_leaktest_follow_targetname.integer)
targetname = PRVM_GetString(prog, PRVM_serveredictstring(edict, targetname));
if(targetname)