// LordHavoc: counts usage of each QuakeC statement
cvar_t prvm_statementprofiling = {0, "prvm_statementprofiling", "0", "counts how many times each QuakeC statement has been executed, these counts are displayed in prvm_printfunction output (if enabled)"};
cvar_t prvm_timeprofiling = {0, "prvm_timeprofiling", "0", "counts how long each function has been executed, these counts are displayed in prvm_profile output (if enabled)"};
+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;
}
(unsigned int)LittleLong( header[ 5 ] ) == (unsigned int)prog->progs_numstatements )
{
prog->statement_linenums = (int *)Mem_Alloc(prog->progs_mempool, prog->progs_numstatements * sizeof( int ) );
- memcpy( prog->statement_linenums, (int *) lno + 6, prog->progs_numstatements * sizeof( int ) );
+ memcpy( prog->statement_linenums, header + 6, prog->progs_numstatements * sizeof( int ) );
+
+ /* gmqcc suports columnums */
+ if ((unsigned int)filesize > ((6 + 2 * prog->progs_numstatements) * sizeof( int )))
+ {
+ prog->statement_columnnums = (int *)Mem_Alloc(prog->progs_mempool, prog->progs_numstatements * sizeof( int ) );
+ memcpy( prog->statement_columnnums, header + 6 + prog->progs_numstatements, prog->progs_numstatements * sizeof( int ) );
+ }
}
Mem_Free( lno );
}
prog->statements = (mstatement_t *)Mem_Alloc(prog->progs_mempool, prog->progs_numstatements * sizeof(mstatement_t));
// allocate space for profiling statement usage
prog->statement_profile = (double *)Mem_Alloc(prog->progs_mempool, prog->progs_numstatements * sizeof(*prog->statement_profile));
+ prog->explicit_profile = (double *)Mem_Alloc(prog->progs_mempool, prog->progs_numstatements * sizeof(*prog->statement_profile));
// functions need to be converted to the memory format
prog->functions = (mfunction_t *)Mem_Alloc(prog->progs_mempool, sizeof(mfunction_t) * prog->progs_numfunctions);
break;
// 1 global
case OP_CALL0:
+ if ( a < prog->progs_numglobals)
+ if ( prog->globals.ip[remapglobal(a)] >= 0 )
+ if ( prog->globals.ip[remapglobal(a)] < prog->progs_numfunctions )
+ if ( prog->functions[prog->globals.ip[remapglobal(a)]].first_statement == -642 )
+ ++prog->numexplicitcoveragestatements;
case OP_CALL1:
case OP_CALL2:
case OP_CALL3:
// 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_traceqc);
Cvar_RegisterVariable (&prvm_statementprofiling);
Cvar_RegisterVariable (&prvm_timeprofiling);
+ 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);
{
Con_DPrintf("PRVM_SetTempString: enlarging tempstrings buffer (%iKB -> %iKB)\n", old.maxsize/1024, prog->tempstringsbuf.maxsize/1024);
prog->tempstringsbuf.data = (unsigned char *) Mem_Alloc(prog->progs_mempool, prog->tempstringsbuf.maxsize);
- if (old.cursize)
- memcpy(prog->tempstringsbuf.data, old.data, old.cursize);
if (old.data)
+ {
+ if (old.cursize)
+ memcpy(prog->tempstringsbuf.data, old.data, old.cursize);
Mem_Free(old.data);
+ }
}
}
t = (char *)prog->tempstringsbuf.data + prog->tempstringsbuf.cursize;
{
int i;
if (!bufferlength)
+ {
+ if (pointer)
+ *pointer = NULL;
return 0;
+ }
for (i = prog->firstfreeknownstring;i < prog->numknownstrings;i++)
if (!prog->knownstrings[i])
break;
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)