mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-10 15:22:04 +00:00
[util] Plug a thread-safety hole in plists
This commit is contained in:
parent
84dc73da2c
commit
dfa7af03c6
11 changed files with 41 additions and 28 deletions
|
@ -298,13 +298,15 @@ void ED_PrintNum (progs_t *pr, pr_int_t ent);
|
|||
// pr_parse.c
|
||||
struct script_s;
|
||||
struct plitem_s;
|
||||
struct hashlink_s;
|
||||
qboolean ED_ParseEpair (progs_t *pr, pr_type_t *base, pr_def_t *key,
|
||||
const char *s);
|
||||
struct plitem_s *ED_EntityDict (progs_t *pr, edict_t *ed);
|
||||
struct plitem_s *ED_GlobalsDict (progs_t *pr);
|
||||
void ED_InitGlobals (progs_t *pr, struct plitem_s *globals);
|
||||
void ED_InitEntity (progs_t *pr, struct plitem_s *entity, edict_t *ent);
|
||||
struct plitem_s *ED_ConvertToPlist (struct script_s *script, int nohack);
|
||||
struct plitem_s *ED_ConvertToPlist (struct script_s *script, int nohack,
|
||||
struct hashlink_s **hashlinks);
|
||||
struct plitem_s *ED_Parse (progs_t *pr, const char *data);
|
||||
void ED_LoadFromFile (progs_t *pr, const char *data);
|
||||
void ED_EntityParseFunction (progs_t *pr);
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
#ifndef __QF_qfplist_h
|
||||
#define __QF_qfplist_h
|
||||
|
||||
struct hashlink_s;
|
||||
|
||||
/** \defgroup qfplist Property lists
|
||||
\ingroup utils
|
||||
*/
|
||||
|
@ -115,11 +117,14 @@ typedef struct plelement_s {
|
|||
/** Create an in-memory representation of the contents of a property list.
|
||||
|
||||
\param string the saved plist, as read from a file.
|
||||
\param hashlinks Hashlink chain to use when creating dictionaries (see
|
||||
Hash_NewTable()). May be null.
|
||||
|
||||
\return Returns an object equivalent to the passed-in string.
|
||||
\note You are responsible for freeing the returned object.
|
||||
*/
|
||||
plitem_t *PL_GetPropertyList (const char *string);
|
||||
plitem_t *PL_GetPropertyList (const char *string,
|
||||
struct hashlink_s **hashlinks);
|
||||
|
||||
/** Create a property list string from the in-memory representation.
|
||||
|
||||
|
@ -275,9 +280,11 @@ plitem_t *PL_RemoveObjectAtIndex (plitem_t *array, int index);
|
|||
|
||||
/** Create a new dictionary object.
|
||||
The dictionary will be empty.
|
||||
\param hashlinks Hashlink chain to use when creating dictionaries (see
|
||||
Hash_NewTable()). May be null.
|
||||
\return the new dictionary object
|
||||
*/
|
||||
plitem_t *PL_NewDictionary (void);
|
||||
plitem_t *PL_NewDictionary (struct hashlink_s **hashlinks);
|
||||
|
||||
/** Create a new array object.
|
||||
The array will be empty.
|
||||
|
|
|
@ -172,7 +172,7 @@ Load_Tracklist (void)
|
|||
buffile = calloc (size+10, sizeof (char));
|
||||
Qread (oggfile, buffile, size);
|
||||
|
||||
tracklist = PL_GetPropertyList (buffile);
|
||||
tracklist = PL_GetPropertyList (buffile, 0);
|
||||
if (!tracklist || PL_Type (tracklist) != QFDictionary) {
|
||||
Sys_Printf ("Malformed or empty tracklist file. check mus_ogglist\n");
|
||||
return -1;
|
||||
|
|
|
@ -109,7 +109,7 @@ VISIBLE plitem_t *
|
|||
ED_EntityDict (progs_t *pr, edict_t *ed)
|
||||
{
|
||||
dstring_t *dstr = dstring_newstr ();
|
||||
plitem_t *entity = PL_NewDictionary ();
|
||||
plitem_t *entity = PL_NewDictionary (pr->hashlink_freelist);
|
||||
pr_uint_t i;
|
||||
int j;
|
||||
int type;
|
||||
|
@ -155,7 +155,7 @@ VISIBLE plitem_t *
|
|||
ED_GlobalsDict (progs_t *pr)
|
||||
{
|
||||
dstring_t *dstr = dstring_newstr ();
|
||||
plitem_t *globals = PL_NewDictionary ();
|
||||
plitem_t *globals = PL_NewDictionary (pr->hashlink_freelist);
|
||||
pr_uint_t i;
|
||||
const char *name;
|
||||
const char *value;
|
||||
|
@ -290,7 +290,7 @@ ED_ParseEpair (progs_t *pr, pr_type_t *base, pr_def_t *key, const char *s)
|
|||
*/
|
||||
|
||||
VISIBLE plitem_t *
|
||||
ED_ConvertToPlist (script_t *script, int nohack)
|
||||
ED_ConvertToPlist (script_t *script, int nohack, struct hashlink_s **hashlinks)
|
||||
{
|
||||
dstring_t *dstr = dstring_newstr ();
|
||||
plitem_t *plist = PL_NewArray ();
|
||||
|
@ -304,7 +304,7 @@ ED_ConvertToPlist (script_t *script, int nohack)
|
|||
token = script->token->str;
|
||||
if (!strequal (token, "{"))
|
||||
Sys_Error ("ED_ConvertToPlist: EOF without closing brace");
|
||||
ent = PL_NewDictionary ();
|
||||
ent = PL_NewDictionary (hashlinks);
|
||||
while (1) {
|
||||
int n;
|
||||
|
||||
|
@ -499,11 +499,11 @@ ED_Parse (progs_t *pr, const char *data)
|
|||
if (Script_GetToken (script, 1)) {
|
||||
if (strequal (script->token->str, "(")) {
|
||||
// new style (plist) entity data
|
||||
entity_list = PL_GetPropertyList (data);
|
||||
entity_list = PL_GetPropertyList (data, pr->hashlink_freelist);
|
||||
} else {
|
||||
// oldstyle entity data
|
||||
Script_UngetToken (script);
|
||||
entity_list = ED_ConvertToPlist (script, 0);
|
||||
entity_list = ED_ConvertToPlist (script, 0, pr->hashlink_freelist);
|
||||
}
|
||||
}
|
||||
Script_Delete (script);
|
||||
|
|
|
@ -195,7 +195,7 @@ bi_PL_GetFromFile (progs_t *pr)
|
|||
Qread (file, buf, len);
|
||||
buf[len] = 0;
|
||||
|
||||
plitem = PL_GetPropertyList (buf);
|
||||
plitem = PL_GetPropertyList (buf, pr->hashlink_freelist);
|
||||
|
||||
R_INT (pr) = plist_retain (res, plitem);
|
||||
}
|
||||
|
@ -204,7 +204,8 @@ static void
|
|||
bi_PL_GetPropertyList (progs_t *pr)
|
||||
{
|
||||
plist_resources_t *res = PR_Resources_Find (pr, "plist");
|
||||
plitem_t *plitem = PL_GetPropertyList (P_GSTRING (pr, 0));
|
||||
plitem_t *plitem = PL_GetPropertyList (P_GSTRING (pr, 0),
|
||||
pr->hashlink_freelist);
|
||||
|
||||
R_INT (pr) = plist_retain (res, plitem);
|
||||
}
|
||||
|
@ -373,7 +374,7 @@ static void
|
|||
bi_PL_NewDictionary (progs_t *pr)
|
||||
{
|
||||
plist_resources_t *res = PR_Resources_Find (pr, "plist");
|
||||
plitem_t *plitem = PL_NewDictionary ();
|
||||
plitem_t *plitem = PL_NewDictionary (pr->hashlink_freelist);
|
||||
|
||||
R_INT (pr) = plist_retain (res, plitem);
|
||||
}
|
||||
|
|
|
@ -91,6 +91,7 @@ typedef struct pldata_s { // Unparsed property list string
|
|||
unsigned line;
|
||||
plitem_t *error;
|
||||
va_ctx_t *va_ctx;
|
||||
hashlink_t **hashlinks;
|
||||
} pldata_t;
|
||||
|
||||
// Ugly defines for fast checking and conversion from char to number
|
||||
|
@ -157,11 +158,11 @@ PL_NewItem (pltype_t type)
|
|||
}
|
||||
|
||||
VISIBLE plitem_t *
|
||||
PL_NewDictionary (void)
|
||||
PL_NewDictionary (hashlink_t **hashlinks)
|
||||
{
|
||||
plitem_t *item = PL_NewItem (QFDictionary);
|
||||
//FIXME need a per-thread hashlink freelist for plist to be thread-safe
|
||||
hashtab_t *dict = Hash_NewTable (1021, dict_get_key, dict_free, NULL, 0);
|
||||
hashtab_t *dict = Hash_NewTable (1021, dict_get_key, dict_free, NULL,
|
||||
hashlinks);
|
||||
item->data = dict;
|
||||
return item;
|
||||
}
|
||||
|
@ -722,7 +723,7 @@ PL_ParsePropertyListItem (pldata_t *pl)
|
|||
switch (pl->ptr[pl->pos]) {
|
||||
case '{':
|
||||
{
|
||||
item = PL_NewDictionary ();
|
||||
item = PL_NewDictionary (pl->hashlinks);
|
||||
item->line = pl->line;
|
||||
|
||||
pl->pos++;
|
||||
|
@ -880,7 +881,7 @@ PL_ParsePropertyListItem (pldata_t *pl)
|
|||
}
|
||||
|
||||
VISIBLE plitem_t *
|
||||
PL_GetPropertyList (const char *string)
|
||||
PL_GetPropertyList (const char *string, hashlink_t **hashlinks)
|
||||
{
|
||||
pldata_t *pl = calloc (1, sizeof (pldata_t));
|
||||
plitem_t *newpl = NULL;
|
||||
|
@ -894,6 +895,7 @@ PL_GetPropertyList (const char *string)
|
|||
pl->error = NULL;
|
||||
pl->line = 1;
|
||||
pl->va_ctx = va_create_context (4);
|
||||
pl->hashlinks = hashlinks;
|
||||
|
||||
if ((newpl = PL_ParsePropertyListItem (pl))) {
|
||||
va_destroy_context (pl->va_ctx);
|
||||
|
|
|
@ -672,7 +672,7 @@ qfs_load_config (void)
|
|||
buf[len + 2] = 0;
|
||||
if (qfs_gd_plist)
|
||||
PL_Free (qfs_gd_plist);
|
||||
qfs_gd_plist = PL_GetPropertyList (buf);
|
||||
qfs_gd_plist = PL_GetPropertyList (buf, 0);
|
||||
free (buf);
|
||||
if (qfs_gd_plist && PL_Type (qfs_gd_plist) == QFDictionary)
|
||||
return; // done
|
||||
|
@ -680,7 +680,7 @@ qfs_load_config (void)
|
|||
no_config:
|
||||
if (qfs_gd_plist)
|
||||
PL_Free (qfs_gd_plist);
|
||||
qfs_gd_plist = PL_GetPropertyList (qfs_default_dirconf);
|
||||
qfs_gd_plist = PL_GetPropertyList (qfs_default_dirconf, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -244,7 +244,8 @@ static plitem_t *
|
|||
qfv_load_pipeline (vulkan_ctx_t *ctx, const char *name)
|
||||
{
|
||||
if (!ctx->pipelineDef) {
|
||||
ctx->pipelineDef = PL_GetPropertyList (quakeforge_pipeline);
|
||||
ctx->pipelineDef = PL_GetPropertyList (quakeforge_pipeline,
|
||||
&ctx->hashlinks);
|
||||
}
|
||||
|
||||
plitem_t *item = ctx->pipelineDef;
|
||||
|
|
|
@ -434,7 +434,7 @@ entities_array (void)
|
|||
static plitem_t *
|
||||
game_dict (void)
|
||||
{
|
||||
plitem_t *game = PL_NewDictionary ();
|
||||
plitem_t *game = PL_NewDictionary (0);
|
||||
|
||||
PL_D_AddObject (game, "comment",
|
||||
PL_NewString (va (0, "%-21s kills:%3i/%3i", cl.levelname,
|
||||
|
@ -455,7 +455,7 @@ game_dict (void)
|
|||
static plitem_t *
|
||||
convert_to_game_dict (script_t *script)
|
||||
{
|
||||
plitem_t *game = PL_NewDictionary ();
|
||||
plitem_t *game = PL_NewDictionary (0);
|
||||
plitem_t *item;
|
||||
plitem_t *list;
|
||||
int skill;
|
||||
|
@ -500,7 +500,7 @@ convert_to_game_dict (script_t *script)
|
|||
PL_D_AddObject (game, "lightstyles", item);
|
||||
|
||||
// load the edicts out of the savegame file
|
||||
list = ED_ConvertToPlist (script, 0);
|
||||
list = ED_ConvertToPlist (script, 0, 0);
|
||||
item = PL_RemoveObjectAtIndex (list, 0);
|
||||
PL_D_AddObject (game, "globals", item);
|
||||
PL_D_AddObject (game, "entities", list);
|
||||
|
@ -647,7 +647,7 @@ Host_Loadgame_f (void)
|
|||
Sys_Printf ("Unexpected EOF reading %s\n", name->str);
|
||||
goto end;
|
||||
}
|
||||
game = PL_GetPropertyList (script->p);
|
||||
game = PL_GetPropertyList (script->p, 0);
|
||||
} else {
|
||||
sscanf (script->token->str, "%i", &version);
|
||||
if (version != SAVEGAME_VERSION) {
|
||||
|
|
|
@ -179,7 +179,7 @@ LoadEntities (void)
|
|||
|
||||
script = Script_New ();
|
||||
Script_Start (script, "ent data", bsp->entdata);
|
||||
entity_list = ED_ConvertToPlist (script, 1);
|
||||
entity_list = ED_ConvertToPlist (script, 1, 0);
|
||||
Script_Delete (script);
|
||||
|
||||
// start parsing
|
||||
|
@ -208,7 +208,7 @@ LoadEntities (void)
|
|||
}
|
||||
entity->dict = PL_ObjectAtIndex (entity_list, i);
|
||||
|
||||
dict = PL_NewDictionary ();
|
||||
dict = PL_NewDictionary (0);
|
||||
|
||||
// go through all the keys in this entity
|
||||
keys = PL_D_AllKeys (entity->dict);
|
||||
|
|
|
@ -334,6 +334,6 @@ LoadProperties (const char *filename)
|
|||
Qread (f, buf, len);
|
||||
Qclose (f);
|
||||
buf[len] = 0;
|
||||
properties = PL_GetPropertyList (buf);
|
||||
properties = PL_GetPropertyList (buf, 0);
|
||||
free (buf);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue