From 8a812544ecbb2d154b07c83a106029c0c6a0cf1b Mon Sep 17 00:00:00 2001 From: rubidium Date: Wed, 27 Dec 2006 18:25:17 +0000 Subject: [PATCH] (svn r7582) -Fix (r7490): appending static GRFs to the list of to-be loaded GRF for a game could result in duplicate GRFs in that list, which can cause a segmentation fault while loading the GRFs. --- newgrf_config.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++- newgrf_config.h | 1 + 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/newgrf_config.c b/newgrf_config.c index f07e869e97..421333ba8e 100644 --- a/newgrf_config.c +++ b/newgrf_config.c @@ -131,6 +131,50 @@ GRFConfig **CopyGRFConfigList(GRFConfig **dst, const GRFConfig *src) return dst; } +/** + * Removes duplicates from lists of GRFConfigs. These duplicates + * are introduced when the _grfconfig_static GRFs are appended + * to the _grfconfig on a newgame or savegame. As the parameters + * of the static GRFs could be different that the parameters of + * the ones used non-statically. This can result in desyncs in + * multiplayers, so the duplicate static GRFs have to be removed. + * + * This function _assumes_ that all static GRFs are placed after + * the non-static GRFs. + * + * @param list the list to remove the duplicates from + */ +static void RemoveDuplicatesFromGRFConfigList(GRFConfig *list) +{ + GRFConfig *prev; + GRFConfig *cur; + + if (list == NULL) return; + + for (prev = list, cur = list->next; cur != NULL; prev = cur, cur = cur->next) { + if (cur->grfid != list->grfid) continue; + assert(HASBIT(cur->flags, GCF_STATIC)); + prev->next = cur->next; + ClearGRFConfig(&cur); + cur = prev; // Just go back one so it continues as normal later on + } + + RemoveDuplicatesFromGRFConfigList(list->next); +} + +/** + * Appends the static GRFs to a list of GRFs + * @param dst the head of the list to add to + */ +void AppendStaticGRFConfigs(GRFConfig **dst) +{ + GRFConfig **tail = dst; + while (*tail != NULL) tail = &(*tail)->next; + + CopyGRFConfigList(tail, _grfconfig_static); + RemoveDuplicatesFromGRFConfigList(*dst); +} + /* Reset the current GRF Config to either blank or newgame settings */ void ResetGRFConfig(bool defaults) @@ -138,7 +182,7 @@ void ResetGRFConfig(bool defaults) GRFConfig **c = &_grfconfig; if (defaults) c = CopyGRFConfigList(c, _grfconfig_newgame); - CopyGRFConfigList(c, _grfconfig_static); + AppendStaticGRFConfigs(&_grfconfig); } @@ -400,6 +444,7 @@ static void Load_NGRF(void) ClearGRFConfigList(&_grfconfig); _grfconfig = first; + AppendStaticGRFConfigs(&_grfconfig); } const ChunkHandler _newgrf_chunk_handlers[] = { diff --git a/newgrf_config.h b/newgrf_config.h index 24721a555d..37f5c6d866 100644 --- a/newgrf_config.h +++ b/newgrf_config.h @@ -44,6 +44,7 @@ void ScanNewGRFFiles(void); const GRFConfig *FindGRFConfig(uint32 grfid, uint8 *md5sum); GRFConfig *GetGRFConfig(uint32 grfid); GRFConfig **CopyGRFConfigList(GRFConfig **dst, const GRFConfig *src); +void AppendStaticGRFConfigs(GRFConfig **dst); void ClearGRFConfig(GRFConfig **config); void ClearGRFConfigList(GRFConfig **config); void ResetGRFConfig(bool defaults);