From f1f54311f6b0d95874b859dce636bc5f13b2927d Mon Sep 17 00:00:00 2001 From: Spoike Date: Sun, 4 Feb 2018 13:16:25 +0000 Subject: [PATCH] fix some bugs. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5209 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/client/p_script.c | 5 +- engine/client/pr_csqc.c | 31 +++++--- engine/client/wad.c | 3 +- engine/qclib/initlib.c | 155 +++++++++++++++++++++++-------------- engine/qclib/qcc_pr_comp.c | 4 +- engine/server/pr_cmds.c | 4 + engine/server/world.c | 2 +- 7 files changed, 133 insertions(+), 71 deletions(-) diff --git a/engine/client/p_script.c b/engine/client/p_script.c index ad2432b43..b2c24445a 100644 --- a/engine/client/p_script.c +++ b/engine/client/p_script.c @@ -1265,7 +1265,10 @@ void P_ParticleEffect_f(void) ptype->t2 = atof(Cmd_Argv(4))/tscale; ptype->randsmax = atoi(Cmd_Argv(6)); - ptype->texsstride = atof(Cmd_Argv(7)); + if (Cmd_Argc()>7) + ptype->texsstride = atof(Cmd_Argv(7));/*FIXME: divide-by-tscale missing */ + else + ptype->texsstride = 1/tscale; if (ptype->randsmax < 1 || ptype->texsstride == 0) ptype->randsmax = 1; diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index a58f7ca42..1b757259f 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -1576,7 +1576,7 @@ void QCBUILTIN PF_R_PolygonEnd(pubprogfuncs_t *prinst, struct globalvars_s *pr_g else flags &= ~BEF_LINES; - if (flags != csqc_poly_flags) + if (flags != csqc_poly_flags || (cl_numstrisvert-csqc_poly_origvert) >= 32768) { int sv = cl_numstrisvert - nv; cl_numstrisvert -= nv; @@ -2787,18 +2787,14 @@ static void QCBUILTIN PF_cs_SetModelIndex(pubprogfuncs_t *prinst, struct globalv csqc_setmodel(prinst, ent, modelindex); } -static void QCBUILTIN PF_cs_PrecacheModel(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +static int PF_cs_PrecacheModel_Internal(pubprogfuncs_t *prinst, const char *modelname, qboolean queryonly) { int modelindex, freei; - const char *modelname = PR_GetStringOfs(prinst, OFS_PARM0); const char *fixedname; int i; if (!*modelname) - { - G_FLOAT(OFS_RETURN) = 0; - return; - } + return 0; fixedname = Mod_FixName(modelname, csqc_world.worldmodel->publicname); @@ -2816,7 +2812,7 @@ static void QCBUILTIN PF_cs_PrecacheModel(pubprogfuncs_t *prinst, struct globalv modelindex = CS_FindModel(modelname, &freei); //now load it - if (!modelindex) + if (!modelindex && !queryonly) { if (!freei) Host_EndGame("CSQC ran out of model slots\n"); @@ -2828,7 +2824,22 @@ static void QCBUILTIN PF_cs_PrecacheModel(pubprogfuncs_t *prinst, struct globalv cl.model_csqcprecache[-freei] = Mod_ForName(fixedname, MLV_WARN); } - G_FLOAT(OFS_RETURN) = modelindex; + return modelindex; +} +static void QCBUILTIN PF_cs_PrecacheModel (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + const char *s = PR_GetStringOfs(prinst, OFS_PARM0); + + G_INT(OFS_RETURN) = G_INT(OFS_PARM0); + PF_cs_PrecacheModel_Internal(prinst, s, false); +} + +static void QCBUILTIN PF_cs_getmodelindex (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + const char *s = PR_GetStringOfs(prinst, OFS_PARM0); + qboolean queryonly = (prinst->callargc >= 2)?G_FLOAT(OFS_PARM1):false; + + G_FLOAT(OFS_RETURN) = PF_cs_PrecacheModel_Internal(prinst, s, queryonly); } static void QCBUILTIN PF_cs_precachefile(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { @@ -6043,7 +6054,7 @@ static struct { {"localsound", PF_cl_localsound, 177}, //200 - {"getmodelindex", PF_cs_PrecacheModel, 200}, + {"getmodelindex", PF_cs_getmodelindex, 200}, {"externcall", PF_externcall, 201}, {"addprogs", PF_cs_addprogs, 202}, {"externvalue", PF_externvalue, 203}, diff --git a/engine/client/wad.c b/engine/client/wad.c index 6bf7eca04..9b10b6635 100644 --- a/engine/client/wad.c +++ b/engine/client/wad.c @@ -447,7 +447,8 @@ qbyte *W_ConvertWAD3Texture(miptex_t *tex, size_t lumpsize, int *width, int *hei } out += 4; } - BoostGamma(data, tex->width, tex->height); + if (!vid_hardwaregamma.value) + BoostGamma(data, tex->width, tex->height); *usesalpha = !!alpha; return data; } diff --git a/engine/qclib/initlib.c b/engine/qclib/initlib.c index 035748bc8..be6974c7a 100644 --- a/engine/qclib/initlib.c +++ b/engine/qclib/initlib.c @@ -151,35 +151,51 @@ void *PRAddressableExtend(progfuncs_t *progfuncs, void *src, size_t srcsize, int } -#define MARKER 0xF1E3E3E7u +#define MARKER_USED 0xC2A4F5A6u +#define MARKER_FREE 0xF1E3E3E7u typedef struct { +#ifdef _DEBUG + unsigned int marker; +#endif unsigned int next; unsigned int prev; - unsigned int size; + unsigned int size; //includes header size } qcmemfreeblock_t; typedef struct { unsigned int marker; - unsigned int size; +#ifdef _DEBUG + unsigned int next; + unsigned int prev; +#endif + unsigned int size; //includes header size } qcmemusedblock_t; -static void PF_fmem_unlink(progfuncs_t *pr, qcmemfreeblock_t *p) +static void PF_fmem_unlink(progfuncs_t *progfuncs, qcmemfreeblock_t *p) { qcmemfreeblock_t *np; +#ifdef _DEBUG + if (p->marker != MARKER_FREE) + { + printf("PF_fmem_unlink: memory corruption\n"); + PR_StackTrace(&progfuncs->funcs, false); + } + p->marker = 0; +#endif if (p->prev) { - np = (qcmemfreeblock_t*)(pr->funcs.stringtable + p->prev); + np = (qcmemfreeblock_t*)(progfuncs->funcs.stringtable + p->prev); np->next = p->next; } else - pr->inst.mfreelist = p->next; + progfuncs->inst.mfreelist = p->next; if (p->next) { - np = (qcmemfreeblock_t*)(pr->funcs.stringtable + p->next); + np = (qcmemfreeblock_t*)(progfuncs->funcs.stringtable + p->next); np->prev = p->prev; } } -/* + static void PR_memvalidate (progfuncs_t *progfuncs) { qcmemfreeblock_t *p; @@ -197,7 +213,11 @@ static void PR_memvalidate (progfuncs_t *progfuncs) } p = (qcmemfreeblock_t*)(progfuncs->funcs.stringtable + b); - if (p->prev != l || + if ( +#ifdef _DEBUG + p->marker != MARKER_FREE || +#endif + p->prev != l || (p->next && p->next < b + p->size) || p->next >= prinst.addressableused || b + p->size >= prinst.addressableused || @@ -211,7 +231,7 @@ static void PR_memvalidate (progfuncs_t *progfuncs) b = p->next; } } -*/ + static void *PDECL PR_memalloc (pubprogfuncs_t *ppf, unsigned int size) { progfuncs_t *progfuncs = (progfuncs_t*)ppf; @@ -221,6 +241,8 @@ static void *PDECL PR_memalloc (pubprogfuncs_t *ppf, unsigned int size) /*round size up*/ size = (size+sizeof(qcmemusedblock_t) + 63) & ~63; + PR_memvalidate(progfuncs); + b = prinst.mfreelist; while (b) { @@ -249,6 +271,9 @@ static void *PDECL PR_memalloc (pubprogfuncs_t *ppf, unsigned int size) /*make a new header just after it, with basically the same properties, and shift the important fields over*/ n = b + size; np = (qcmemfreeblock_t*)(progfuncs->funcs.stringtable + b + size); +#ifdef _DEBUG + np->marker = MARKER_FREE; +#endif np->prev = p->prev; np->next = p->next; np->size = p->size - size; @@ -289,10 +314,10 @@ static void *PDECL PR_memalloc (pubprogfuncs_t *ppf, unsigned int size) //FIXME: merge with previous block } memset(ub, 0, size); - ub->marker = MARKER; + ub->marker = MARKER_USED; ub->size = size; -// PR_memvalidate(progfuncs); + PR_memvalidate(progfuncs); return ub+1; } @@ -300,7 +325,7 @@ static void PDECL PR_memfree (pubprogfuncs_t *ppf, void *memptr) { progfuncs_t *progfuncs = (progfuncs_t*)ppf; qcmemusedblock_t *ub; - qcmemfreeblock_t *p, *np, *pp; + qcmemfreeblock_t *b, *nb, *pb; unsigned int pa, na; //prev addr, next addr unsigned int size; unsigned int ptr = memptr?((char*)memptr - progfuncs->funcs.stringtable):0; @@ -308,10 +333,12 @@ static void PDECL PR_memfree (pubprogfuncs_t *ppf, void *memptr) /*freeing NULL is ignored*/ if (!ptr) return; -// PR_memvalidate(progfuncs); - if (ptr < sizeof(qcmemusedblock_t) || ptr >= prinst.addressableused) + PR_memvalidate(progfuncs); + ptr -= sizeof(qcmemusedblock_t); + if (/*ptr < 0 ||*/ ptr >= prinst.addressableused) { - if (ptr < sizeof(qcmemusedblock_t) && !*(char*)memptr) + ptr += sizeof(qcmemusedblock_t); + if (ptr < prinst.addressableused && !*(char*)memptr) { //the empty string is a point of contention. while we can detect it from fteqcc, its best to not give any special favours (other than nicer debugging, where possible) //we might not actually spot it from other qccs, so warning about it where possible is probably a very good thing. @@ -323,18 +350,20 @@ static void PDECL PR_memfree (pubprogfuncs_t *ppf, void *memptr) return; } + //this is the used block that we're trying to free ub = (qcmemusedblock_t*)(progfuncs->funcs.stringtable + ptr); - ub--; - ptr = (char*)ub - progfuncs->funcs.stringtable; - if (ub->marker != MARKER || ub->size <= sizeof(*ub) || ptr + ub->size > (unsigned int)prinst.addressableused) + if (ub->marker != MARKER_USED || ub->size <= sizeof(*ub) || ptr + ub->size > (unsigned int)prinst.addressableused) { printf("PR_memfree: pointer lacks marker - double-freed?\n"); PR_StackTrace(&progfuncs->funcs, false); return; } - ub->marker = 0; + ub->marker = 0; //invalidate it size = ub->size; + ub = NULL; + //we have an (ordered) list of free blocks. + //in order to free our memory, we need to find the free block before+after the 'new' block for (na = prinst.mfreelist, pa = 0; ;) { if (/*na < 0 ||*/ na >= prinst.addressableused) @@ -345,60 +374,74 @@ static void PDECL PR_memfree (pubprogfuncs_t *ppf, void *memptr) } if (!na || na >= ptr) { - np = (qcmemfreeblock_t*)(progfuncs->funcs.stringtable + pa); - if (pa && pa+np->size>ptr) - { + pb = pa?(qcmemfreeblock_t*)(progfuncs->funcs.stringtable + pa):NULL; + if (pb && pa+pb->size>ptr) + { //previous free block extends into the block that we're trying to free. printf("PF_memfree: double free\n"); PR_StackTrace(&progfuncs->funcs, false); return; } +#ifdef _DEBUG + if (pb && pb->marker != MARKER_FREE) + { + printf("PF_memfree: use-after-free?\n"); + PR_StackTrace(&progfuncs->funcs, false); + return; + } +#endif + + nb = na?(qcmemfreeblock_t*)(progfuncs->funcs.stringtable + na):NULL; + if (nb && ptr+size > na) + { + printf("PF_memfree: block extends into neighbour\n"); + PR_StackTrace(&progfuncs->funcs, false); + return; + } +#ifdef _DEBUG + if (nb && nb->marker != MARKER_FREE) + { + printf("PF_memfree: use-after-free?\n"); + PR_StackTrace(&progfuncs->funcs, false); + return; + } +#endif /*generate the free block, now we know its proper values*/ - p = (qcmemfreeblock_t*)(progfuncs->funcs.stringtable + ptr); - np = na?(qcmemfreeblock_t*)(progfuncs->funcs.stringtable + na):NULL; - pp = pa?(qcmemfreeblock_t*)(progfuncs->funcs.stringtable + pa):NULL; - - p->prev = pa; - p->next = na; - p->size = size; - - /*update the next's previous*/ + b = (qcmemfreeblock_t*)(progfuncs->funcs.stringtable + ptr); +#ifdef _DEBUG + b->marker = MARKER_FREE; +#endif + b->prev = pa; + b->next = na; + b->size = size; if (na) - { - np->prev = ptr; - - /*extend this block and kill the next if they are adjacent*/ - if (p->next == ptr + size) - { - p->size += np->size; - PF_fmem_unlink(progfuncs, np); - } - } - - /*update the link to get here*/ + nb->prev = ptr; if (!pa) prinst.mfreelist = ptr; else + pb->next = ptr; + + /*extend this block and kill the next if they are adjacent*/ + if (na && b->next == ptr + size) { - pp->next = ptr; - - /*we're adjacent to the previous block, so merge them by killing the newly freed region*/ - if (na && pa + np->size == ptr) - { - p->size += np->size; - PF_fmem_unlink(progfuncs, np); - } - + b->size += nb->size; + PF_fmem_unlink(progfuncs, nb); + } + /*we're adjacent to the previous block, so merge them by killing the newly freed region*/ + if (pa && pa + pb->size == ptr) + { + pb->size += size; + PF_fmem_unlink(progfuncs, b); } break; } pa = na; - p = (qcmemfreeblock_t*)(progfuncs->funcs.stringtable + pa); - na = p->next; + b = (qcmemfreeblock_t*)(progfuncs->funcs.stringtable + pa); + na = b->next; } -// PR_memvalidate(progfuncs); + PR_memvalidate(progfuncs); } void PRAddressableFlush(progfuncs_t *progfuncs, size_t totalammount) diff --git a/engine/qclib/qcc_pr_comp.c b/engine/qclib/qcc_pr_comp.c index b86392f49..9fe987ac6 100644 --- a/engine/qclib/qcc_pr_comp.c +++ b/engine/qclib/qcc_pr_comp.c @@ -5346,7 +5346,7 @@ QCC_sref_t QCC_PR_GenerateFunctionCallRef (QCC_sref_t newself, QCC_sref_t func, if (callconvention == OP_CALL1H) { for (i = 0; i < parm && i < 2; i++) - if (args[i].ref.sym->generatedfor == &def_ret && args[i].ref.sym->refcount == 1) + if (args[i].ref.sym && args[i].ref.sym->generatedfor == &def_ret && args[i].ref.sym->refcount == 1) { QCC_FreeTemp(args[i].ref); args[i].ref.sym = &def_ret; @@ -5427,7 +5427,7 @@ QCC_sref_t QCC_PR_GenerateFunctionCallRef (QCC_sref_t newself, QCC_sref_t func, if (arglist[i]->readonly) { - QCC_PR_ParseWarning(ERR_TYPEMISMATCHPARM, "Unable to write to out argument\n"); + QCC_PR_ParseWarning(ERR_TYPEMISMATCHPARM, "Unable to write to read-only out argument"); continue; } if (parm>=MAX_PARMS) diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index bc604184d..d4d9e47ff 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -7213,6 +7213,7 @@ const char *SV_CheckRejectConnection(netadr_t *adr, const char *uinfo, unsigned } return ret; } +#ifndef SERVERONLY void SV_AddDebugPolygons(void) { int i; @@ -7227,11 +7228,14 @@ void SV_AddDebugPolygons(void) if (svs.clients[i].netchan.remote_address.type == NA_LOOPBACK) pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, svs.clients[i].edict); PR_ExecuteProgram (svprogfuncs, gfuncs.AddDebugPolygons); + if (R2D_Flush) + R2D_Flush(); #ifdef PROGS_DAT csqc_dp_lastwas3d = false; #endif } } +#endif #ifdef HEXEN2 static void QCBUILTIN PF_h2AdvanceFrame(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) diff --git a/engine/server/world.c b/engine/server/world.c index 5e5a2d488..d299bd419 100644 --- a/engine/server/world.c +++ b/engine/server/world.c @@ -1254,7 +1254,7 @@ static trace_t World_ClipMoveToEntity (world_t *w, wedict_t *ent, vec3_t eorg, v VectorSubtract (ent->v->mins, maxs, boxmins); VectorSubtract (ent->v->maxs, mins, boxmaxs); - if (hitcontentsmask & ((ent->v->solid == SOLID_CORPSE)?FTECONTENTS_CORPSE:FTECONTENTS_BODY)) + if (hitcontentsmask & ((ent->v->solid == SOLID_CORPSE && w->usesolidcorpse)?FTECONTENTS_CORPSE:FTECONTENTS_BODY)) hitcontentsmask = FTECONTENTS_CORPSE|FTECONTENTS_BODY; else hitcontentsmask = 0;