From 5c8a68e1dee9736a1c22a5945394ceb2789cda07 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 13 Oct 2015 16:05:32 +0200 Subject: [PATCH 01/62] always call seen_done to eliminate memory leaks in tests. --- src/seen.test.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/seen.test.c b/src/seen.test.c index fb6a42517..504d79ada 100644 --- a/src/seen.test.c +++ b/src/seen.test.c @@ -108,6 +108,7 @@ static void test_seen_travelthru(CuTest *tc) { sr = find_seen(f->seen, r); CuAssertPtrEquals(tc, r, sr->r); CuAssertIntEquals(tc, see_travel, sr->mode); + seen_done(f->seen); test_cleanup(); } @@ -141,6 +142,7 @@ static void test_seen_interval_backward(CuTest *tc) { get_seen_interval(seen, &first, &last); CuAssertPtrEquals(tc, regions, first); CuAssertPtrEquals(tc, 0, last); + seen_done(seen); test_cleanup(); } @@ -159,6 +161,7 @@ static void test_seen_interval_forward(CuTest *tc) { get_seen_interval(seen, &first, &last); CuAssertPtrEquals(tc, regions, first); CuAssertPtrEquals(tc, 0, last); + seen_done(seen); test_cleanup(); } From 422476409ce44ff78786b84a979bf61afe093412 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 13 Oct 2015 20:58:03 +0200 Subject: [PATCH 02/62] eliminate memory leak from locales --- src/util/language.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/util/language.c b/src/util/language.c index 1972b38da..05ddf50c9 100644 --- a/src/util/language.c +++ b/src/util/language.c @@ -315,9 +315,23 @@ void reset_locales(void) { void free_locales(void) { locale_init = 0; while (locales) { - int i; + int i, index = locales->index; locale * next = locales->next; + for (i = UT_PARAMS; i != UT_RACES; ++i) { + struct critbit_tree ** cb = (struct critbit_tree **)get_translations(locales, i); + if (*cb) { + // TODO: this crashes? + cb_clear(*cb); + free(*cb); + } + } + for (i = UT_RACES; i != UT_MAX; ++i) { + void *tokens = lstrs[index].tokens[i]; + if (tokens) { + freetokens(tokens); + } + } for (i = 0; i != SMAXHASH; ++i) { while (locales->strings[i]) { struct locale_str * strings = locales->strings[i]; From 3741a19437ce06888dfd7ef0238b2fda531f77cf Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 13 Oct 2015 21:21:31 +0200 Subject: [PATCH 03/62] prevent memory leak of cJSON structures in tests --- src/kernel/jsonconf.test.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/kernel/jsonconf.test.c b/src/kernel/jsonconf.test.c index 2d9394749..6441ad424 100644 --- a/src/kernel/jsonconf.test.c +++ b/src/kernel/jsonconf.test.c @@ -31,6 +31,7 @@ static const struct race * race_with_flag(const char * name) { json = cJSON_Parse(data); free_races(); json_config(json); + cJSON_Delete(json); return rc_find("orc"); } @@ -78,6 +79,7 @@ static void test_settings(CuTest * tc) CuAssertStrEquals(tc, "1d4", get_param(global.parameters, "string")); CuAssertIntEquals(tc, 14, get_param_int(global.parameters, "integer", 0)); CuAssertDblEquals(tc, 1.5f, get_param_flt(global.parameters, "float", 0), 0.01); + cJSON_Delete(json); test_cleanup(); } @@ -96,6 +98,7 @@ static void test_prefixes(CuTest * tc) CuAssertStrEquals(tc, "snow", race_prefixes[0]); CuAssertStrEquals(tc, "dark", race_prefixes[2]); CuAssertPtrEquals(tc, 0, race_prefixes[3]); + cJSON_Delete(json); test_cleanup(); } @@ -121,6 +124,7 @@ static void test_disable(CuTest * tc) CuAssertTrue(tc, keyword_disabled(K_PAY)); CuAssertTrue(tc, keyword_disabled(K_BESIEGE)); CuAssertIntEquals(tc, 0, get_param_int(global.parameters, "module.enabled", 1)); + cJSON_Delete(json); test_cleanup(); } @@ -164,6 +168,7 @@ static void test_races(CuTest * tc) CuAssertIntEquals(tc, 4, rc->capacity); CuAssertIntEquals(tc, 5, rc->hitpoints); CuAssertIntEquals(tc, 6, rc->armor); + cJSON_Delete(json); test_cleanup(); } @@ -183,6 +188,7 @@ static void test_findrace(CuTest *tc) { rc = findrace("Zwerg", lang); CuAssertPtrNotNull(tc, rc); CuAssertStrEquals(tc, "dwarf", rc->_name); + cJSON_Delete(json); test_cleanup(); } @@ -216,6 +222,8 @@ static void test_items(CuTest * tc) CuAssertPtrNotNull(tc, rt_find("axe")); CuAssertPtrNotNull(tc, (void *)get_resourcetype(R_HORSE)); + cJSON_Delete(json); + test_cleanup(); } static void test_ships(CuTest * tc) @@ -254,6 +262,7 @@ static void test_ships(CuTest * tc) CuAssertPtrEquals(tc, (void *)ter, (void *)st->coasts[0]); CuAssertPtrEquals(tc, 0, (void *)st->coasts[1]); + cJSON_Delete(json); test_cleanup(); } @@ -281,6 +290,8 @@ static void test_castles(CuTest *tc) { CuAssertPtrNotNull(tc, bt->construction->improvement); CuAssertIntEquals(tc, 6, bt->construction->improvement->maxsize); CuAssertPtrEquals(tc, 0, bt->construction->improvement->improvement); + cJSON_Delete(json); + test_cleanup(); } static void test_spells(CuTest * tc) @@ -299,6 +310,7 @@ static void test_spells(CuTest * tc) CuAssertPtrNotNull(tc, sp); CuAssertStrEquals(tc, "u+", sp->syntax); + cJSON_Delete(json); test_cleanup(); CuAssertPtrEquals(tc, 0, find_spell("fireball")); } @@ -364,6 +376,7 @@ static void test_buildings(CuTest * tc) CuAssertIntEquals(tc, 20, bt->construction->maxsize); CuAssertIntEquals(tc, 1, bt->construction->minskill); CuAssertPtrEquals(tc, 0, bt->construction->improvement); + cJSON_Delete(json); test_cleanup(); } @@ -388,6 +401,7 @@ static void test_buildings_default(CuTest * tc) CuAssertPtrEquals(tc, (void *)bt, (void *)bt_find("house")); CuAssertIntEquals(tc, 0, memcmp(bt, &clone, sizeof(building_type))); + cJSON_Delete(json); test_cleanup(); } @@ -412,6 +426,7 @@ static void test_ships_default(CuTest * tc) CuAssertPtrEquals(tc, (void *)st, (void *)st_find("hodor")); CuAssertIntEquals(tc, 0, memcmp(st, &clone, sizeof(ship_type))); + cJSON_Delete(json); test_cleanup(); } @@ -431,6 +446,7 @@ static void test_configs(CuTest * tc) json_config(json); CuAssertPtrNotNull(tc, buildingtypes); unlink("test.json"); + cJSON_Delete(json); test_cleanup(); } @@ -472,6 +488,7 @@ static void test_terrains(CuTest * tc) CuAssertPtrEquals(tc, rt_get_or_create("iron"), (resource_type *)ter->production[1].type); CuAssertPtrEquals(tc, 0, (void *)ter->production[2].type); + cJSON_Delete(json); test_cleanup(); } @@ -493,6 +510,7 @@ static void test_directions(CuTest * tc) CuAssertIntEquals(tc, D_NORTHWEST, get_direction("nordwest", lang)); CuAssertIntEquals(tc, D_PAUSE, get_direction("pause", lang)); + cJSON_Delete(json); test_cleanup(); } @@ -517,6 +535,7 @@ static void test_skills(CuTest * tc) CuAssertStrEquals(tc, "ALCHEMIE", LOC(lang, "skill::alchemy")); CuAssertStrEquals(tc, "ARMBRUST", LOC(lang, "skill::crossbow")); + cJSON_Delete(json); test_cleanup(); } @@ -540,6 +559,7 @@ static void test_keywords(CuTest * tc) CuAssertStrEquals(tc, "LERNEN", LOC(lang, "keyword::study")); CuAssertStrEquals(tc, "NACH", LOC(lang, "keyword::move")); + cJSON_Delete(json); test_cleanup(); } @@ -558,6 +578,8 @@ static void test_strings(CuTest * tc) json_config(json); CuAssertStrEquals(tc, "NACH", LOC(lang, "move")); CuAssertStrEquals(tc, "LERNEN", LOC(lang, "study")); + cJSON_Delete(json); + test_cleanup(); } static void test_infinitive_from_config(CuTest *tc) { @@ -578,6 +600,7 @@ static void test_infinitive_from_config(CuTest *tc) { ord = create_order(K_STUDY, lang, ""); CuAssertStrEquals(tc, "LERNE", get_command(ord, buffer, sizeof(buffer))); free_order(ord); + cJSON_Delete(json); test_cleanup(); } From 6de8e4466a5173035c3448b78a191624d3349087 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 13 Oct 2015 21:26:48 +0200 Subject: [PATCH 04/62] stop memory leak from function registry. --- src/eressea.c | 2 ++ src/util/functions.c | 4 ++++ src/util/functions.h | 1 + 3 files changed, 7 insertions(+) diff --git a/src/eressea.c b/src/eressea.c index 14cce6267..703334993 100755 --- a/src/eressea.c +++ b/src/eressea.c @@ -13,6 +13,7 @@ #endif #include #include +#include #include #include #include @@ -46,6 +47,7 @@ void game_done(void) #endif calendar_cleanup(); #endif + free_functions(); kernel_done(); } diff --git a/src/util/functions.c b/src/util/functions.c index 9d0afb63d..82792faaf 100644 --- a/src/util/functions.c +++ b/src/util/functions.c @@ -48,3 +48,7 @@ void register_function(pf_generic fun, const char *name) len = cb_new_kv(name, len, &fun, sizeof(fun), buffer); cb_insert(&cb_functions, buffer, len); } + +void free_functions(void) { + cb_clear(&cb_functions); +} \ No newline at end of file diff --git a/src/util/functions.h b/src/util/functions.h index dcf9e908f..944ce0466 100644 --- a/src/util/functions.h +++ b/src/util/functions.h @@ -26,6 +26,7 @@ extern "C" { pf_generic get_function(const char *name); void register_function(pf_generic fun, const char *name); + void free_functions(void); #ifdef __cplusplus } From ff0bbce4f93111cc9f99b244e731930bcfd27b60 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 13 Oct 2015 21:30:10 +0200 Subject: [PATCH 05/62] weird things happen when you name locales something else? --- src/give.test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/give.test.c b/src/give.test.c index 401cd1fb8..18637f256 100644 --- a/src/give.test.c +++ b/src/give.test.c @@ -334,7 +334,7 @@ static void test_give_invalid_target(CuTest *tc) { setup_give(&env); i_change(&env.src->items, env.itype, 10); - lang = get_or_create_locale("test"); + lang = get_or_create_locale("de"); env.f1->locale = lang; locale_setstring(lang, "KRAEUTER", "KRAUT"); init_locale(lang); From 2f35246f8c241ee100686d4b239be944dfbad980 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 13 Oct 2015 21:47:45 +0200 Subject: [PATCH 06/62] memory leak: when freeing factions, also free their spellbooks --- src/kernel/faction.c | 1 + src/magic.c | 10 +++++++--- src/magic.h | 1 + 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/kernel/faction.c b/src/kernel/faction.c index 5fd0b4d25..6f4fb5b38 100755 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -86,6 +86,7 @@ void free_faction(faction * f) } freelist(f->allies); + free_spellbook(f->spellbook); free(f->email); free(f->banner); free(f->passw); diff --git a/src/magic.c b/src/magic.c index be98bcadd..4d801e7ff 100644 --- a/src/magic.c +++ b/src/magic.c @@ -2984,11 +2984,15 @@ spellbook * get_spellbook(const char * name) return result; } -int free_spellbook_cb(const void *match, const void *key, size_t keylen, void *data) { - spellbook *sb; - cb_get_kv(match, &sb, sizeof(sb)); +void free_spellbook(spellbook *sb) { spellbook_clear(sb); free(sb); +} + +static int free_spellbook_cb(const void *match, const void *key, size_t keylen, void *data) { + spellbook *sb; + cb_get_kv(match, &sb, sizeof(sb)); + free_spellbook(sb); return 0; } diff --git a/src/magic.h b/src/magic.h index ee4c20996..c33d9917e 100644 --- a/src/magic.h +++ b/src/magic.h @@ -363,6 +363,7 @@ extern "C" { struct spellbook * get_spellbook(const char * name); void free_spellbooks(void); + void free_spellbook(struct spellbook *sb); #ifdef __cplusplus } #endif From 67135c8ea3e270601e1c8256020b0c1fbf56dea4 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 13 Oct 2015 21:50:23 +0200 Subject: [PATCH 07/62] avoid triggering null-pointer assert --- src/kernel/faction.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/kernel/faction.c b/src/kernel/faction.c index 6f4fb5b38..4348b6214 100755 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -79,6 +79,10 @@ void free_faction(faction * f) free(bm); } + if (f->spellbook) { + free_spellbook(f->spellbook); + } + while (f->groups) { group *g = f->groups; f->groups = g->next; @@ -86,7 +90,6 @@ void free_faction(faction * f) } freelist(f->allies); - free_spellbook(f->spellbook); free(f->email); free(f->banner); free(f->passw); From 7e9c36b599274f4616271d05a2104f8b586066bd Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 13 Oct 2015 22:02:58 +0200 Subject: [PATCH 08/62] memory leak: free spell components and spells at exit --- src/kernel/spell.c | 7 +++++++ src/kernel/spell.h | 10 +++++----- src/magic.test.c | 1 + 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/kernel/spell.c b/src/kernel/spell.c index b9a8b5895..e5b9a7772 100644 --- a/src/kernel/spell.c +++ b/src/kernel/spell.c @@ -36,8 +36,15 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. static critbit_tree cb_spells; quicklist * spells; +static void free_spell_cb(void *cbdata) { + spell *sp = (spell *)cbdata; + free(sp->components); + free(sp); +} + void free_spells(void) { cb_clear(&cb_spells); + ql_foreach(spells, free_spell_cb); ql_free(spells); spells = 0; } diff --git a/src/kernel/spell.h b/src/kernel/spell.h index 0782a24ee..a69b61989 100644 --- a/src/kernel/spell.h +++ b/src/kernel/spell.h @@ -50,11 +50,11 @@ extern "C" { void showspells(struct region *r, struct unit *u); int sp_antimagiczone(struct castorder *co); - extern struct spell * create_spell(const char * name, unsigned int id); - extern struct spell * find_spell(const char *name); - extern struct spell * find_spellbyid(unsigned int i); - extern void add_spell(struct quicklist **slistp, spell * sp); - extern void free_spells(void); + struct spell * create_spell(const char * name, unsigned int id); + struct spell * find_spell(const char *name); + struct spell * find_spellbyid(unsigned int i); + void add_spell(struct quicklist **slistp, spell * sp); + void free_spells(void); /** globals **/ extern struct attrib_type at_unitdissolve; diff --git a/src/magic.test.c b/src/magic.test.c index 600f724ca..f356fa686 100644 --- a/src/magic.test.c +++ b/src/magic.test.c @@ -40,6 +40,7 @@ void test_updatespells(CuTest * tc) CuAssertPtrNotNull(tc, f->spellbook); CuAssertIntEquals(tc, 1, ql_length(f->spellbook->spells)); CuAssertPtrNotNull(tc, spellbook_get(f->spellbook, sp)); + free_spellbook(book); test_cleanup(); } From 7c2c520911e03fb6f78b569a0bfc9b07b80ce901 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 13 Oct 2015 22:09:41 +0200 Subject: [PATCH 09/62] memory leak: at_travelunit contains a quicklist, needs custom cleanup code. --- src/travelthru.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/travelthru.c b/src/travelthru.c index 754a93530..32607ae5c 100644 --- a/src/travelthru.c +++ b/src/travelthru.c @@ -38,13 +38,18 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include +static void travel_done(attrib *a) { + quicklist *ql = (quicklist *)a->data.v; + ql_free(ql); +} + /*********************/ /* at_travelunit */ /*********************/ attrib_type at_travelunit = { "travelunit", DEFAULT_INIT, - DEFAULT_FINALIZE, + travel_done, DEFAULT_AGE, NO_WRITE, NO_READ From 1f1850dafc6536f86c8988e128686e400c2bcb00 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 13 Oct 2015 22:11:45 +0200 Subject: [PATCH 10/62] memory leak: always cleanup at the end of a test that creates game data. --- src/reports.test.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/reports.test.c b/src/reports.test.c index 892c5ea62..ecb053c14 100644 --- a/src/reports.test.c +++ b/src/reports.test.c @@ -66,6 +66,7 @@ static void test_reorder_units(CuTest * tc) CuAssertPtrEquals(tc, u1, u2->next); CuAssertPtrEquals(tc, u0, u1->next); CuAssertPtrEquals(tc, 0, u0->next); + test_cleanup(); } static void test_regionid(CuTest * tc) { @@ -88,11 +89,15 @@ static void test_regionid(CuTest * tc) { CuAssertIntEquals(tc, 10, (int)len); CuAssertStrEquals(tc, "plain (0,0", buffer); CuAssertIntEquals(tc, 0x7d, buffer[11]); + test_cleanup(); } static void test_seen_faction(CuTest *tc) { faction *f1, *f2; - race *rc = test_create_race("human"); + race *rc; + + test_cleanup(); + rc = test_create_race("human"); f1 = test_create_faction(rc); f2 = test_create_faction(rc); add_seen_faction(f1, f2); @@ -105,6 +110,7 @@ static void test_seen_faction(CuTest *tc) { f2 = (faction *)ql_get(f1->seen_factions, 1); f1 = (faction *)ql_get(f1->seen_factions, 0); CuAssertTrue(tc, f1->no < f2->no); + test_cleanup(); } static void test_write_spaces(CuTest *tc) { From d264c454b8945938eee0cf1afa2deb10a7c8f48f Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 13 Oct 2015 22:13:50 +0200 Subject: [PATCH 11/62] memory leak: building_type::construction was never released --- src/kernel/building.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/kernel/building.c b/src/kernel/building.c index 48241c398..3f3bf8ec1 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -94,6 +94,7 @@ void bt_register(building_type * type) void free_buildingtype(void *ptr) { building_type *btype = (building_type *)ptr; + free(btype->construction); free(btype->_name); free(btype); } From 0facb386a80891fe1ec299ef540f8d120ce68b29 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 13 Oct 2015 22:21:05 +0200 Subject: [PATCH 12/62] memory leaks: call test_cleanup, free strlist, free message --- src/kernel/config.test.c | 3 +++ src/reports.test.c | 1 + src/spells/magicresistance.test.c | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/kernel/config.test.c b/src/kernel/config.test.c index a8894a7f6..de1d0173e 100644 --- a/src/kernel/config.test.c +++ b/src/kernel/config.test.c @@ -132,6 +132,7 @@ static void test_get_set_param(CuTest * tc) CuAssertStrEquals(tc, "foo", get_param(par, "bar")); set_param(&par, "bar", NULL); CuAssertPtrEquals(tc, NULL, (void *)get_param(par, "bar")); + test_cleanup(); } static void test_param_int(CuTest * tc) @@ -143,6 +144,7 @@ static void test_param_int(CuTest * tc) set_param(&par, "bar", "42"); CuAssertIntEquals(tc, 23, get_param_int(par, "foo", 0)); CuAssertIntEquals(tc, 42, get_param_int(par, "bar", 0)); + test_cleanup(); } static void test_param_flt(CuTest * tc) @@ -154,6 +156,7 @@ static void test_param_flt(CuTest * tc) set_param(&par, "bar", "42.0"); CuAssertDblEquals(tc, 23.0, get_param_flt(par, "foo", 0.0), 0.01); CuAssertDblEquals(tc, 42.0, get_param_flt(par, "bar", 0.0), 0.01); + test_cleanup(); } static void test_forbiddenid(CuTest *tc) { diff --git a/src/reports.test.c b/src/reports.test.c index ecb053c14..0e3912401 100644 --- a/src/reports.test.c +++ b/src/reports.test.c @@ -165,6 +165,7 @@ static void test_sparagraph(CuTest *tc) { CuAssertPtrNotNull(tc, sp->next->next); CuAssertStrEquals(tc, "12345678", sp->next->next->s); CuAssertPtrEquals(tc, 0, sp->next->next->next); + freestrlist(sp); } static void test_cr_unit(CuTest *tc) { diff --git a/src/spells/magicresistance.test.c b/src/spells/magicresistance.test.c index cceafd4b7..55a5effaa 100644 --- a/src/spells/magicresistance.test.c +++ b/src/spells/magicresistance.test.c @@ -70,7 +70,7 @@ static void test_magicresistance_building(CuTest *tc) { msg = c->type->curseinfo(b1, TYP_BUILDING, c, 1); CuAssertPtrNotNull(tc, msg); CuAssertStrEquals(tc, "curseinfo::magicresistance_building", test_get_messagetype(msg)); - + msg_release(msg); test_cleanup(); } From c70d987c09fe400b07cab87884dd28ed0a1c5b4f Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 13 Oct 2015 22:27:43 +0200 Subject: [PATCH 13/62] memory leak: free weapon data --- src/kernel/item.c | 12 ++++++++++-- src/kernel/item.h | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/kernel/item.c b/src/kernel/item.c index 4aab13112..ba6504746 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -1178,12 +1178,17 @@ static item *default_spoil(const struct race *rc, int size) return itm; } -int free_itype(item_type *itype) { +static void free_itype(item_type *itype) { free(itype->construction); free(itype->_appearance[0]); free(itype->_appearance[1]); free(itype); - return 0; +} + +static void free_wtype(weapon_type *wtype) { + free(wtype->damage[0]); + free(wtype->damage[1]); + free(wtype); } int free_rtype_cb(const void * match, const void * key, size_t keylen, void *cbdata) { @@ -1193,6 +1198,9 @@ int free_rtype_cb(const void * match, const void * key, size_t keylen, void *cbd if (rtype->itype) { free_itype(rtype->itype); } + if (rtype->wtype) { + free_wtype(rtype->wtype); + } free(rtype); return 0; } diff --git a/src/kernel/item.h b/src/kernel/item.h index 449445a7d..fc3c2c909 100644 --- a/src/kernel/item.h +++ b/src/kernel/item.h @@ -211,7 +211,7 @@ extern "C" { typedef struct weapon_type { const item_type *itype; - const char *damage[2]; + char *damage[2]; unsigned int flags; skill_t skill; int minskill; From cd1467f66895e33dcf6d3d8eec48c1f352951a60 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 13 Oct 2015 22:31:03 +0200 Subject: [PATCH 14/62] cleanup: test_create_world is lazy --- src/economy.test.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/economy.test.c b/src/economy.test.c index 08b8bea56..09fa1157f 100644 --- a/src/economy.test.c +++ b/src/economy.test.c @@ -28,9 +28,8 @@ static void test_give_control_building(CuTest * tc) region *r; test_cleanup(); - test_create_world(); f = test_create_faction(0); - r = findregion(0, 0); + r = test_create_region(0, 0, 0); b = test_create_building(r, 0); u1 = test_create_unit(f, r); u_set_building(u1, b); @@ -50,9 +49,8 @@ static void test_give_control_ship(CuTest * tc) region *r; test_cleanup(); - test_create_world(); f = test_create_faction(0); - r = findregion(0, 0); + r = test_create_region(0, 0, 0); sh = test_create_ship(r, 0); u1 = test_create_unit(f, r); u_set_ship(u1, sh); From 333c27403f9d82108ce76237dfa0679cc9a41644 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 13 Oct 2015 22:33:13 +0200 Subject: [PATCH 15/62] memory leaks: ship_type.construction, give_cmd return values --- src/give.test.c | 6 +++++- src/kernel/ship.c | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/give.test.c b/src/give.test.c index 18637f256..3e3b98a16 100644 --- a/src/give.test.c +++ b/src/give.test.c @@ -177,6 +177,7 @@ static void test_give_men_none(CuTest * tc) { CuAssertStrEquals(tc, "error96", test_get_messagetype(msg)); CuAssertIntEquals(tc, 1, env.dst->number); CuAssertIntEquals(tc, 1, env.src->number); + msg_release(msg); test_cleanup(); } @@ -193,6 +194,7 @@ static void test_give_men_other_faction(CuTest * tc) { CuAssertStrEquals(tc, "give_person", (const char *)msg->parameters[0].v); CuAssertIntEquals(tc, 2, env.dst->number); CuAssertIntEquals(tc, 0, env.src->number); + msg_release(msg); test_cleanup(); } @@ -217,8 +219,9 @@ static void test_give_men_requires_contact(CuTest * tc) { give_cmd(env.src, ord); CuAssertPtrEquals(tc, 0, test_find_messagetype(env.f1->msgs, "give_person")); CuAssertPtrNotNull(tc, test_find_messagetype(env.f1->msgs, "feedback_no_contact")); - free_order(ord); + msg_release(msg); + free_order(ord); test_cleanup(); } @@ -231,6 +234,7 @@ static void test_give_men_not_to_self(CuTest * tc) { msg = give_men(1, env.src, env.src, NULL); CuAssertStrEquals(tc, "error10", test_get_messagetype(msg)); CuAssertIntEquals(tc, 1, env.src->number); + msg_release(msg); test_cleanup(); } diff --git a/src/kernel/ship.c b/src/kernel/ship.c index d33ac5aaf..a2b7c556e 100644 --- a/src/kernel/ship.c +++ b/src/kernel/ship.c @@ -245,6 +245,7 @@ static void free_shiptype(void *ptr) { ship_type *stype = (ship_type *)ptr; free(stype->_name); free(stype->coasts); + free(stype->construction); free(stype); } From 457465b4a226d682753992351e16985d62e16ad3 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 13 Oct 2015 22:37:45 +0200 Subject: [PATCH 16/62] memory leak: free message_list objects --- src/give.test.c | 1 + src/kernel/messages.test.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/give.test.c b/src/give.test.c index 3e3b98a16..04870baa2 100644 --- a/src/give.test.c +++ b/src/give.test.c @@ -152,6 +152,7 @@ static void test_give_men_in_ocean(CuTest * tc) { msg = disband_men(1, env.src, NULL); CuAssertStrEquals(tc, "give_person_ocean", (const char *)msg->parameters[0].v); CuAssertIntEquals(tc, 0, env.src->number); + msg_release(msg); test_cleanup(); } diff --git a/src/kernel/messages.test.c b/src/kernel/messages.test.c index 295f4f576..af95ecf26 100644 --- a/src/kernel/messages.test.c +++ b/src/kernel/messages.test.c @@ -57,6 +57,8 @@ static void test_merge_split(CuTest *tc) { CuAssertPtrEquals(tc, append->begin, mlist->begin->next); split_messages(mlist, split); CuAssertPtrEquals(tc, 0, mlist->begin->next); + free_messagelist(mlist); + free_messagelist(append); test_cleanup(); } From 26f5b592bddf424fc848164bacee0951cb14b8d7 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 13 Oct 2015 22:41:54 +0200 Subject: [PATCH 17/62] leak: free construction materials --- src/kernel/building.c | 5 ++++- src/kernel/ship.c | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/kernel/building.c b/src/kernel/building.c index 3f3bf8ec1..b1a2915f9 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -94,7 +94,10 @@ void bt_register(building_type * type) void free_buildingtype(void *ptr) { building_type *btype = (building_type *)ptr; - free(btype->construction); + if (btype->construction) { + free(btype->construction->materials); + free(btype->construction); + } free(btype->_name); free(btype); } diff --git a/src/kernel/ship.c b/src/kernel/ship.c index a2b7c556e..6eb6116eb 100644 --- a/src/kernel/ship.c +++ b/src/kernel/ship.c @@ -245,7 +245,10 @@ static void free_shiptype(void *ptr) { ship_type *stype = (ship_type *)ptr; free(stype->_name); free(stype->coasts); - free(stype->construction); + if (stype->construction) { + free(stype->construction->materials); + free(stype->construction); + } free(stype); } From a6ca489d9a8da916b6aa94d71a3c7b97c46e5940 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 13 Oct 2015 22:56:16 +0200 Subject: [PATCH 18/62] free multi-level construction correctly, avoid duplication --- src/kernel/build.c | 9 +++++++++ src/kernel/build.h | 1 + src/kernel/building.c | 5 +---- src/kernel/ship.c | 5 +---- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/kernel/build.c b/src/kernel/build.c index 4ce08c39a..931c730f0 100644 --- a/src/kernel/build.c +++ b/src/kernel/build.c @@ -977,3 +977,12 @@ void continue_ship(unit * u, int want) build_ship(u, sh, want); } +void free_construction(struct construction *cons) +{ + while (cons) { + construction *next = cons->improvement; + free(cons->materials); + free(cons); + cons = next; + } +} diff --git a/src/kernel/build.h b/src/kernel/build.h index 5e231b198..38fefb88a 100644 --- a/src/kernel/build.h +++ b/src/kernel/build.h @@ -65,6 +65,7 @@ extern "C" { } construction; + void free_construction(struct construction *cons); extern int destroy_cmd(struct unit *u, struct order *ord); extern int leave_cmd(struct unit *u, struct order *ord); diff --git a/src/kernel/building.c b/src/kernel/building.c index b1a2915f9..a234f55a6 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -94,10 +94,7 @@ void bt_register(building_type * type) void free_buildingtype(void *ptr) { building_type *btype = (building_type *)ptr; - if (btype->construction) { - free(btype->construction->materials); - free(btype->construction); - } + free_construction(btype->construction); free(btype->_name); free(btype); } diff --git a/src/kernel/ship.c b/src/kernel/ship.c index 6eb6116eb..c77a10bd4 100644 --- a/src/kernel/ship.c +++ b/src/kernel/ship.c @@ -245,10 +245,7 @@ static void free_shiptype(void *ptr) { ship_type *stype = (ship_type *)ptr; free(stype->_name); free(stype->coasts); - if (stype->construction) { - free(stype->construction->materials); - free(stype->construction); - } + free_construction(stype->construction); free(stype); } From 24f1f82e93ab07103c66359645461479405eee33 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 13 Oct 2015 23:02:01 +0200 Subject: [PATCH 19/62] release order reference used to create castorder, message --- src/give.test.c | 1 + src/spells.test.c | 31 +++++++++++++++++-------------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/give.test.c b/src/give.test.c index 04870baa2..517411c4c 100644 --- a/src/give.test.c +++ b/src/give.test.c @@ -252,6 +252,7 @@ static void test_give_peasants(CuTest * tc) { CuAssertStrEquals(tc, "give_person_peasants", (const char*)msg->parameters[0].v); CuAssertIntEquals(tc, 0, env.src->number); CuAssertIntEquals(tc, 1, env.r->land->peasants); + msg_release(msg); test_cleanup(); } diff --git a/src/spells.test.c b/src/spells.test.c index d6fc752e5..ce008b13f 100644 --- a/src/spells.test.c +++ b/src/spells.test.c @@ -20,10 +20,13 @@ #include -static void test_create_castorder(castorder *order, unit *u, int level, float force, int range) { +static void test_create_castorder(castorder *co, unit *u, int level, float force, int range) { struct locale * lang; + order *ord; + lang = get_or_create_locale("en"); - create_castorder(order, u, NULL, NULL, u->region, level, force, range, create_order(K_CAST, lang, ""), NULL); + create_castorder(co, u, NULL, NULL, u->region, level, force, range, ord = create_order(K_CAST, lang, ""), NULL); + free_order(ord); } static void test_good_dreams(CuTest *tc) { @@ -31,7 +34,7 @@ static void test_good_dreams(CuTest *tc) { struct faction *f1, *f2; unit *u1, *u2; int level; - castorder order; + castorder co; test_cleanup(); test_create_world(); @@ -41,9 +44,9 @@ static void test_good_dreams(CuTest *tc) { u1 = test_create_unit(f1, r); u2 = test_create_unit(f2, r); - test_create_castorder(&order, u1, 10, 10., 0); + test_create_castorder(&co, u1, 10, 10., 0); - level = sp_gooddreams(&order); + level = sp_gooddreams(&co); CuAssertIntEquals(tc, 10, level); curse *curse = get_curse(r->attribs, ct_find("gbdream")); CuAssertTrue(tc, curse && curse->duration > 1); @@ -58,7 +61,7 @@ static void test_dreams(CuTest *tc) { struct region *r; struct faction *f1, *f2; unit *u1, *u2; - castorder order; + castorder co; test_cleanup(); test_create_world(); @@ -68,15 +71,15 @@ static void test_dreams(CuTest *tc) { u1 = test_create_unit(f1, r); u2 = test_create_unit(f2, r); - test_create_castorder(&order, u1, 10, 10., 0); + test_create_castorder(&co, u1, 10, 10., 0); - sp_gooddreams(&order); - sp_baddreams(&order); + sp_gooddreams(&co); + sp_baddreams(&co); a_age(&r->attribs); CuAssertIntEquals_Msg(tc, "good dreams in same region as bad dreams", 1, get_modifier(u1, SK_MELEE, 11, r, false)); CuAssertIntEquals_Msg(tc, "bad dreams in same region as good dreams", -1, get_modifier(u2, SK_MELEE, 11, r, false)); - free_castorder(&order); + free_castorder(&co); test_cleanup(); } @@ -85,7 +88,7 @@ static void test_bad_dreams(CuTest *tc) { struct faction *f1, *f2; unit *u1, *u2; int level; - castorder order; + castorder co; test_cleanup(); test_create_world(); @@ -95,9 +98,9 @@ static void test_bad_dreams(CuTest *tc) { u1 = test_create_unit(f1, r); u2 = test_create_unit(f2, r); - test_create_castorder(&order, u1, 10, 10., 0); + test_create_castorder(&co, u1, 10, 10., 0); - level = sp_baddreams(&order); + level = sp_baddreams(&co); CuAssertIntEquals(tc, 10, level); curse *curse = get_curse(r->attribs, ct_find("gbdream")); CuAssertTrue(tc, curse && curse->duration > 1); @@ -107,7 +110,7 @@ static void test_bad_dreams(CuTest *tc) { CuAssertIntEquals_Msg(tc, "bad dreams have no effect on allies", 0, get_modifier(u1, SK_MELEE, 11, r, false)); CuAssertIntEquals_Msg(tc, "bad dreams give -1 to non-allies", -1, get_modifier(u2, SK_MELEE, 11, r, false)); - free_castorder(&order); + free_castorder(&co); test_cleanup(); } From f4f038c23cb342584d83e898a1e7e7592afa49a0 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 13 Oct 2015 23:06:33 +0200 Subject: [PATCH 20/62] leak: free strlist result of split_paragraph --- src/reports.test.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/reports.test.c b/src/reports.test.c index 0e3912401..1dd9f5928 100644 --- a/src/reports.test.c +++ b/src/reports.test.c @@ -145,18 +145,25 @@ static void test_write_many_spaces(CuTest *tc) { static void test_sparagraph(CuTest *tc) { strlist *sp = 0; + split_paragraph(&sp, "Hello World", 0, 16, 0); CuAssertPtrNotNull(tc, sp); CuAssertStrEquals(tc, "Hello World", sp->s); CuAssertPtrEquals(tc, 0, sp->next); + freestrlist(sp); + split_paragraph(&sp, "Hello World", 4, 16, 0); CuAssertPtrNotNull(tc, sp); CuAssertStrEquals(tc, " Hello World", sp->s); CuAssertPtrEquals(tc, 0, sp->next); + freestrlist(sp); + split_paragraph(&sp, "Hello World", 4, 16, '*'); CuAssertPtrNotNull(tc, sp); CuAssertStrEquals(tc, " * Hello World", sp->s); CuAssertPtrEquals(tc, 0, sp->next); + freestrlist(sp); + split_paragraph(&sp, "12345678 90 12345678", 0, 8, '*'); CuAssertPtrNotNull(tc, sp); CuAssertStrEquals(tc, "12345678", sp->s); From 377b0d030550ffba4a9575f889fff049ff351546 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 13 Oct 2015 23:09:50 +0200 Subject: [PATCH 21/62] leak: teardown build tests, free construction data --- src/kernel/build.test.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/kernel/build.test.c b/src/kernel/build.test.c index 2befe6733..b879295e1 100644 --- a/src/kernel/build.test.c +++ b/src/kernel/build.test.c @@ -45,6 +45,11 @@ static unit * setup_build(build_fixture *bf) { return bf->u; } +static void teardown_build(build_fixture *bf) { + free(bf->cons.materials); + test_cleanup(); +} + static void test_build_requires_materials(CuTest *tc) { build_fixture bf = { 0 }; unit *u; @@ -57,7 +62,7 @@ static void test_build_requires_materials(CuTest *tc) { i_change(&u->items, itype, 2); CuAssertIntEquals(tc, 1, build(u, &bf.cons, 0, 1)); CuAssertIntEquals(tc, 1, i_get(u->items, itype)); - test_cleanup(); + teardown_build(&bf); } static void test_build_requires_building(CuTest *tc) { @@ -79,7 +84,7 @@ static void test_build_requires_building(CuTest *tc) { CuAssertIntEquals(tc, 1, build(u, &bf.cons, 0, 1)); btype->maxcapacity = 0; CuAssertIntEquals_Msg(tc, "cannot build when production building capacity exceeded", EBUILDINGREQ, build(u, &bf.cons, 0, 1)); - test_cleanup(); + teardown_build(&bf); } static void test_build_failure_missing_skill(CuTest *tc) { @@ -91,7 +96,7 @@ static void test_build_failure_missing_skill(CuTest *tc) { rtype = bf.cons.materials[0].rtype; i_change(&u->items, rtype->itype, 1); CuAssertIntEquals(tc, ENEEDSKILL, build(u, &bf.cons, 1, 1)); - test_cleanup(); + teardown_build(&bf); } static void test_build_failure_low_skill(CuTest *tc) { @@ -104,7 +109,7 @@ static void test_build_failure_low_skill(CuTest *tc) { i_change(&u->items, rtype->itype, 1); set_level(u, SK_ARMORER, bf.cons.minskill - 1); CuAssertIntEquals(tc, ELOWSKILL, build(u, &bf.cons, 0, 10)); - test_cleanup(); + teardown_build(&bf); } static void test_build_failure_completed(CuTest *tc) { @@ -119,7 +124,7 @@ static void test_build_failure_completed(CuTest *tc) { bf.cons.maxsize = 1; CuAssertIntEquals(tc, ECOMPLETE, build(u, &bf.cons, bf.cons.maxsize, 10)); CuAssertIntEquals(tc, 1, i_get(u->items, rtype->itype)); - test_cleanup(); + teardown_build(&bf); } static void test_build_limits(CuTest *tc) { @@ -145,7 +150,7 @@ static void test_build_limits(CuTest *tc) { i_change(&u->items, rtype->itype, 4); CuAssertIntEquals(tc, 4, build(u, &bf.cons, 0, 10)); CuAssertIntEquals(tc, 0, i_get(u->items, rtype->itype)); - test_cleanup(); + teardown_build(&bf); } static void test_build_with_ring(CuTest *tc) { @@ -164,7 +169,7 @@ static void test_build_with_ring(CuTest *tc) { i_change(&u->items, ring, 1); CuAssertIntEquals(tc, 10, build(u, &bf.cons, 0, 20)); CuAssertIntEquals(tc, 10, i_get(u->items, rtype->itype)); - test_cleanup(); + teardown_build(&bf); } static void test_build_with_potion(CuTest *tc) { @@ -192,7 +197,7 @@ static void test_build_with_potion(CuTest *tc) { CuAssertIntEquals(tc, 4, get_effect(u, ptype)); CuAssertIntEquals(tc, 4, build(u, &bf.cons, 0, 20)); CuAssertIntEquals(tc, 2, get_effect(u, ptype)); - test_cleanup(); + teardown_build(&bf); } static void test_build_building_no_materials(CuTest *tc) { @@ -208,7 +213,7 @@ static void test_build_building_no_materials(CuTest *tc) { CuAssertIntEquals(tc, ENOMATERIALS, build_building(u, btype, 0, 4, u->orders)); CuAssertPtrEquals(tc, 0, u->region->buildings); CuAssertPtrEquals(tc, 0, u->building); - test_cleanup(); + teardown_build(&bf); } static void test_build_building_with_golem(CuTest *tc) { @@ -228,7 +233,7 @@ static void test_build_building_with_golem(CuTest *tc) { CuAssertPtrNotNull(tc, u->region->buildings); CuAssertIntEquals(tc, 1, u->region->buildings->size); CuAssertIntEquals(tc, 0, u->number); - test_cleanup(); + teardown_build(&bf); } static void test_build_building_success(CuTest *tc) { @@ -253,7 +258,7 @@ static void test_build_building_success(CuTest *tc) { CuAssertPtrEquals(tc, u->region->buildings, u->building); CuAssertIntEquals(tc, 1, u->building->size); CuAssertIntEquals(tc, 0, i_get(u->items, rtype->itype)); - test_cleanup(); + teardown_build(&bf); } CuSuite *get_build_suite(void) From a3210aaed785bcaf6e3d12d8fd3f2891a77fde80 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 13 Oct 2015 23:25:44 +0200 Subject: [PATCH 22/62] leak: free per-locale cached order data (has additional refcount) --- src/kernel/order.c | 7 +++++++ src/kernel/order.h | 2 ++ src/tests.c | 2 ++ 3 files changed, 11 insertions(+) diff --git a/src/kernel/order.c b/src/kernel/order.c index 90bea11d3..356fec80d 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -267,6 +267,13 @@ static void free_localedata(int lindex) { locale_array[lindex]->lang = 0; } +void close_orders(void) { + int i; + for (i = 0; i != MAXLOCALES; ++i) { + if (locale_array[i]) free_localedata(i); + } +} + static order *create_order_i(keyword_t kwd, const char *sptr, bool persistent, const struct locale *lang) { diff --git a/src/kernel/order.h b/src/kernel/order.h index 75d741e42..8ad5592b7 100644 --- a/src/kernel/order.h +++ b/src/kernel/order.h @@ -61,6 +61,8 @@ extern "C" { char *write_order(const order * ord, char *buffer, size_t size); keyword_t init_order(const struct order *ord); + void close_orders(void); + #ifdef __cplusplus } #endif diff --git a/src/tests.c b/src/tests.c index 741812590..8e4b3ef57 100644 --- a/src/tests.c +++ b/src/tests.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -79,6 +80,7 @@ void test_cleanup(void) global.functions.wage = NULL; free_params(&global.parameters); default_locale = 0; + close_orders(); free_locales(); free_spells(); free_buildingtypes(); From 66dd7e2320fa6304700f49040210848b57174aa2 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 13 Oct 2015 23:27:13 +0200 Subject: [PATCH 23/62] eliminate unused variable warning (gcc) --- src/piracy.test.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/piracy.test.c b/src/piracy.test.c index 9074c1e33..53907f4df 100644 --- a/src/piracy.test.c +++ b/src/piracy.test.c @@ -18,7 +18,6 @@ static void setup_piracy(void) { struct locale *lang; - terrain_type *t_ocean; ship_type *st_boat; test_cleanup(); @@ -26,7 +25,7 @@ static void setup_piracy(void) { lang = get_or_create_locale("de"); locale_setstring(lang, directions[D_EAST], "OSTEN"); init_directions(lang); - t_ocean = test_create_terrain("ocean", SAIL_INTO | SEA_REGION); + test_create_terrain("ocean", SAIL_INTO | SEA_REGION); st_boat = test_create_shiptype("boat"); st_boat->cargo = 1000; } From f0671aafdae6a38881290e5b086312a508aa2573 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 13 Oct 2015 23:33:11 +0200 Subject: [PATCH 24/62] leak: some tests were leaking seen_factions becaus they don't call destroyfaction or render reports --- src/kernel/faction.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/kernel/faction.c b/src/kernel/faction.c index 4348b6214..193a582ae 100755 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -94,6 +94,10 @@ void free_faction(faction * f) free(f->banner); free(f->passw); free(f->name); + if (f->seen_factions) { + ql_free(f->seen_factions); + f->seen_factions = 0; + } while (f->attribs) { a_remove(&f->attribs, f->attribs); From 20c9fb60dc302c0b327e7266de757e56342e23fb Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 14 Oct 2015 11:58:54 +0200 Subject: [PATCH 25/62] release additional reference to recruit order --- src/economy.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/economy.c b/src/economy.c index 4aea89f80..acccca8f1 100644 --- a/src/economy.c +++ b/src/economy.c @@ -399,6 +399,7 @@ void free_recruitments(recruitment * recruits) while (rec->requests) { request *req = rec->requests; rec->requests = req->next; + free_order(req->ord); free(req); } free(rec); @@ -953,8 +954,9 @@ void economics(region * r) } } - if (recruitorders) + if (recruitorders) { expandrecruit(r, recruitorders); + } remove_empty_units_in_region(r); for (u = r->units; u; u = u->next) { From 3cfb22876bea94bc5c6848e7a8f4eaef22a007ca Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 14 Oct 2015 12:01:33 +0200 Subject: [PATCH 26/62] memory leak: free params after test --- src/kernel/config.test.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/kernel/config.test.c b/src/kernel/config.test.c index de1d0173e..fab30fc6e 100644 --- a/src/kernel/config.test.c +++ b/src/kernel/config.test.c @@ -132,6 +132,7 @@ static void test_get_set_param(CuTest * tc) CuAssertStrEquals(tc, "foo", get_param(par, "bar")); set_param(&par, "bar", NULL); CuAssertPtrEquals(tc, NULL, (void *)get_param(par, "bar")); + free_params(&par); test_cleanup(); } @@ -144,6 +145,7 @@ static void test_param_int(CuTest * tc) set_param(&par, "bar", "42"); CuAssertIntEquals(tc, 23, get_param_int(par, "foo", 0)); CuAssertIntEquals(tc, 42, get_param_int(par, "bar", 0)); + free_params(&par); test_cleanup(); } @@ -156,6 +158,7 @@ static void test_param_flt(CuTest * tc) set_param(&par, "bar", "42.0"); CuAssertDblEquals(tc, 23.0, get_param_flt(par, "foo", 0.0), 0.01); CuAssertDblEquals(tc, 42.0, get_param_flt(par, "bar", 0.0), 0.01); + free_params(&par); test_cleanup(); } From acda22ae1bee6d2a6228c38d2de2adf1efcfdeba Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 14 Oct 2015 12:03:19 +0200 Subject: [PATCH 27/62] leak: free route at the end of the test --- src/move.test.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/move.test.c b/src/move.test.c index 79544d998..5c24ca72e 100644 --- a/src/move.test.c +++ b/src/move.test.c @@ -269,6 +269,7 @@ static void test_ship_trails(CuTest *tc) { CuAssertPtrEquals(tc, 0, a_find(r1->attribs, &at_shiptrail)); CuAssertPtrNotNull(tc, a_find(r2->attribs, &at_shiptrail)); CuAssertPtrNotNull(tc, a_find(r3->attribs, &at_shiptrail)); + free_regionlist(route); test_cleanup(); } @@ -290,6 +291,7 @@ static void test_age_trails(CuTest *tc) { CuAssertPtrNotNull(tc, r1->attribs); a_age(&r1->attribs); CuAssertPtrEquals(tc, 0, r1->attribs); + free_regionlist(route); test_cleanup(); } From 2b59922d8d0e3afb81f1b5b02d3156242484f807 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 14 Oct 2015 12:05:29 +0200 Subject: [PATCH 28/62] memory leak: tests should call cleanup instead of trying to restore original state --- src/laws.test.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/laws.test.c b/src/laws.test.c index 474f95276..5a91d54d4 100644 --- a/src/laws.test.c +++ b/src/laws.test.c @@ -724,30 +724,24 @@ static void statistic_test(CuTest *tc, int peasants, int luck, int maxp, } static void test_peasant_luck_effect(CuTest *tc) { - const char *plf = get_param(global.parameters, "rules.peasants.peasantluck.factor"); - const char *gf = get_param(global.parameters, "rules.peasants.growth.factor"); + test_cleanup(); set_param(&global.parameters, "rules.peasants.peasantluck.factor", "10"); set_param(&global.parameters, "rules.peasants.growth.factor", "0.001"); statistic_test(tc, 100, 0, 1000, 0, 0, 0); statistic_test(tc, 100, 2, 1000, 0, 1, 1); -/* - statistic_test(tc, 1000, 400, 1000, 0, (int)(400 * 10 * 0.001 * .75), - (int)(400 * 10 * 0.001 * .75)); - */ statistic_test(tc, 1000, 400, 1000, 0, 3, 3); statistic_test(tc, 1000, 1000, 2000, .5, 1, 501); set_param(&global.parameters, "rules.peasants.growth.factor", "1"); statistic_test(tc, 1000, 1000, 1000, 0, 501, 501); - - set_param(&global.parameters, "rules.peasants.peasantluck.factor", plf); - set_param(&global.parameters, "rules.peasants.growth.factor", gf); + test_cleanup(); } static void test_luck_message(CuTest *tc) { region* r; + test_cleanup(); r = test_create_region(0, 0, NULL); rsetpeasants(r, 1); From 1fc5273f63d2ab7155ca55fb4bc7e35d36169139 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 14 Oct 2015 12:09:35 +0200 Subject: [PATCH 29/62] memory leak: bad call to register_buildings, replace test_create_world. --- src/battle.test.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/battle.test.c b/src/battle.test.c index 53ec91922..264e9c0be 100644 --- a/src/battle.test.c +++ b/src/battle.test.c @@ -185,11 +185,10 @@ static void test_building_defence_bonus(CuTest * tc) building_type * btype; faction * f; int def; + test_cleanup(); - test_create_world(); - r = findregion(0, 0); - register_buildings(); - btype = bt_get_or_create("castle"); + r = test_create_region(0, 0, 0); + btype = test_create_buildingtype("castle"); btype->protection = (int(*)(struct building *, struct unit *, building_bonus))get_function("building_protection"); btype->construction->defense_bonus = 3; bld = test_create_building(r, btype); From 2c659c1f47746b204fc3998f7a92544c8f054bf1 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 14 Oct 2015 12:13:05 +0200 Subject: [PATCH 30/62] memory leak: free building maintenance data --- src/kernel/building.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/kernel/building.c b/src/kernel/building.c index a234f55a6..7ffba178e 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -95,6 +95,7 @@ void bt_register(building_type * type) void free_buildingtype(void *ptr) { building_type *btype = (building_type *)ptr; free_construction(btype->construction); + free_construction(btype->maintenance); free(btype->_name); free(btype); } From ae3210ec87cc5d1a71bf70fd8875c54b536ccf4a Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 14 Oct 2015 12:14:33 +0200 Subject: [PATCH 31/62] pervious commit did not compile: small copy/paste error --- src/kernel/building.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel/building.c b/src/kernel/building.c index 7ffba178e..da4f58867 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -95,7 +95,7 @@ void bt_register(building_type * type) void free_buildingtype(void *ptr) { building_type *btype = (building_type *)ptr; free_construction(btype->construction); - free_construction(btype->maintenance); + free(btype->maintenance); free(btype->_name); free(btype); } From 8e9e9c9c0f22fa40cf958deb06cb1375c35e843c Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 14 Oct 2015 12:21:13 +0200 Subject: [PATCH 32/62] eliminate leak from duplicate call to test_create_buildingtype --- src/tests.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/tests.c b/src/tests.c index 8e4b3ef57..6e9ec31a8 100644 --- a/src/tests.c +++ b/src/tests.c @@ -155,15 +155,19 @@ building_type * test_create_buildingtype(const char * name) building_type *btype = bt_get_or_create(name); btype->flags = BTF_NAMECHANGE; btype->_name = _strdup(name); - btype->construction = (construction *)calloc(sizeof(construction), 1); - btype->construction->skill = SK_BUILDING; - btype->construction->maxsize = -1; - btype->construction->minskill = 1; - btype->construction->reqsize = 1; - btype->construction->materials = (requirement *)calloc(sizeof(requirement), 2); - btype->construction->materials[1].number = 0; - btype->construction->materials[0].number = 1; - btype->construction->materials[0].rtype = get_resourcetype(R_STONE); + if (!btype->construction) { + btype->construction = (construction *)calloc(sizeof(construction), 1); + btype->construction->skill = SK_BUILDING; + btype->construction->maxsize = -1; + btype->construction->minskill = 1; + btype->construction->reqsize = 1; + } + if (!btype->construction->materials) { + btype->construction->materials = (requirement *)calloc(sizeof(requirement), 2); + btype->construction->materials[1].number = 0; + btype->construction->materials[0].number = 1; + btype->construction->materials[0].rtype = get_resourcetype(R_STONE); + } if (default_locale) { locale_setstring(default_locale, name, name); } From bdf4834dc2ac0f96fbcf8f886080272f88f66b92 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 14 Oct 2015 12:22:37 +0200 Subject: [PATCH 33/62] leak: region_owner data was never released --- src/kernel/region.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/kernel/region.c b/src/kernel/region.c index 1b4bf838e..dd83af4e6 100644 --- a/src/kernel/region.c +++ b/src/kernel/region.c @@ -753,6 +753,7 @@ void remove_region(region ** rlist, region * r) static void freeland(land_region * lr) { + free(lr->ownership); while (lr->demands) { struct demand *d = lr->demands; lr->demands = d->next; From 469d31233983ea8a31c85ba65d477e1b7405810c Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 14 Oct 2015 12:23:58 +0200 Subject: [PATCH 34/62] leak: test must free castorder and call cleanup --- src/spells.test.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/spells.test.c b/src/spells.test.c index ce008b13f..471a043de 100644 --- a/src/spells.test.c +++ b/src/spells.test.c @@ -55,6 +55,8 @@ static void test_good_dreams(CuTest *tc) { a_age(&r->attribs); CuAssertIntEquals_Msg(tc, "good dreams give +1 to allies", 1, get_modifier(u1, SK_MELEE, 11, r, false)); CuAssertIntEquals_Msg(tc, "good dreams have no effect on non-allies", 0, get_modifier(u2, SK_MELEE, 11, r, false)); + free_castorder(&co); + test_cleanup(); } static void test_dreams(CuTest *tc) { From 4fc5ac7740ffa6a0863f4c0054c136e5e6cf675c Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 14 Oct 2015 12:51:45 +0200 Subject: [PATCH 35/62] there is a memory leak in test_long_order_hungry, but the root cause lies deeper --- src/kernel/config.c | 2 ++ src/kernel/curse.test.c | 3 ++- src/laws.test.c | 3 ++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/kernel/config.c b/src/kernel/config.c index 1db17a495..3410f7bff 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -1611,6 +1611,8 @@ void set_default_order(int kwd) { default_keyword = (keyword_t)kwd; } +// TODO: outside of tests, default_keyword is never used, why is this here? +// see also test_long_order_hungry order *default_order(const struct locale *lang) { static int usedefault = 1; diff --git a/src/kernel/curse.test.c b/src/kernel/curse.test.c index 0df115397..bf9f1c85c 100644 --- a/src/kernel/curse.test.c +++ b/src/kernel/curse.test.c @@ -33,9 +33,10 @@ static void test_curse(CuTest * tc) cid = c->no; result = findcurse(cid); CuAssertPtrEquals(tc, c, result); - destroy_curse(c); + a_remove(&attrs, attrs); result = findcurse(cid); CuAssertPtrEquals(tc, NULL, result); + test_cleanup(); } typedef struct { diff --git a/src/laws.test.c b/src/laws.test.c index 5a91d54d4..3c0be9b6a 100644 --- a/src/laws.test.c +++ b/src/laws.test.c @@ -999,7 +999,8 @@ static void test_long_order_buy_cast(CuTest *tc) { } static void test_long_order_hungry(CuTest *tc) { - // TODO: write more tests + // FIXME: set_default_order is a test-only function, this is a bad test. + // see also default_order unit *u; test_cleanup(); set_param(&global.parameters, "hunger.long", "1"); From 254cda86e8887d6fd0255c1928c9381929889a61 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 14 Oct 2015 13:20:27 +0200 Subject: [PATCH 36/62] short commands speedup wasn't working (never got assigned) --- src/kernel/order.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/kernel/order.c b/src/kernel/order.c index 356fec80d..245f6c6b5 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -245,6 +245,7 @@ static order_data *create_data(keyword_t kwd, const char *sptr, int lindex) if (data == NULL) { mkdata(&data, 0, kwd, lindex, 0); data->_refcount = 1; + locale_array[lindex]->short_orders[kwd] = data; } ++data->_refcount; return data; From 78a87953058ed86ce24e52e4599233d7b7bc9b68 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 14 Oct 2015 13:33:10 +0200 Subject: [PATCH 37/62] there is a bug in umlaut.c, adding a FIXME. this happens during test_umlaut, and valgrind detects it. --- src/util/umlaut.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/umlaut.c b/src/util/umlaut.c index 0bf7e0c34..1ba06a53e 100644 --- a/src/util/umlaut.c +++ b/src/util/umlaut.c @@ -181,7 +181,7 @@ void addtoken(void ** root, const char *str, variant id) ref->ucs = lcs; ref->node = node; ref->nexthash = tk->next[index]; - tk->next[index] = ref; + tk->next[index] = ref; // FIXME: memory leak of tk->next[index] } next = ref; } From cd9cb24b4899e6561bc13aa789e7025e08f57d9a Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 14 Oct 2015 13:42:12 +0200 Subject: [PATCH 38/62] extend test_umlaut a bit, which doesn't trigger issue #316 --- src/util/umlaut.test.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/util/umlaut.test.c b/src/util/umlaut.test.c index e36c9f3c9..f9f8f5d15 100644 --- a/src/util/umlaut.test.c +++ b/src/util/umlaut.test.c @@ -49,8 +49,12 @@ static void test_umlaut(CuTest * tc) CuAssertIntEquals(tc, E_TOK_SUCCESS, result); CuAssertIntEquals(tc, 1, id.i); - result = findtoken(tokens, "DERP", &id); - CuAssertIntEquals(tc, E_TOK_SUCCESS, result); + CuAssertIntEquals(tc, E_TOK_SUCCESS, findtoken(tokens, "derp", &id)); + CuAssertIntEquals(tc, E_TOK_SUCCESS, findtoken(tokens, "Derp", &id)); + CuAssertIntEquals(tc, E_TOK_SUCCESS, findtoken(tokens, "dErp", &id)); + CuAssertIntEquals(tc, E_TOK_SUCCESS, findtoken(tokens, "deRp", &id)); + CuAssertIntEquals(tc, E_TOK_SUCCESS, findtoken(tokens, "derP", &id)); + CuAssertIntEquals(tc, E_TOK_SUCCESS, findtoken(tokens, "DERP", &id)); CuAssertIntEquals(tc, 2, id.i); result = findtoken(tokens, umlauts, &id); From 5f9c2e13a88fe750e58d87dc52ada36767842366 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 14 Oct 2015 13:56:19 +0200 Subject: [PATCH 39/62] I hate umlaut.c, it's basically magic, and the magic doesn't work right (it leaks memory from line 158) --- src/util/umlaut.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/util/umlaut.c b/src/util/umlaut.c index 1ba06a53e..f20045b2c 100644 --- a/src/util/umlaut.c +++ b/src/util/umlaut.c @@ -155,7 +155,7 @@ void addtoken(void ** root, const char *str, variant id) next = next->nexthash; if (!next) { tref *ref; - tnode *node = (tnode *)calloc(1, sizeof(tnode)); + tnode *node = (tnode *)calloc(1, sizeof(tnode)); // TODO: what is the reason for this empty node to exist? if (ucs < 'a' || ucs > 'z') { lcs = towlower((wint_t)ucs); @@ -166,6 +166,7 @@ void addtoken(void ** root, const char *str, variant id) ref = (tref *)malloc(sizeof(tref)); ref->ucs = ucs; + ref->node = 0; ref->node = node; ref->nexthash = tk->next[index]; tk->next[index] = ref; @@ -181,7 +182,7 @@ void addtoken(void ** root, const char *str, variant id) ref->ucs = lcs; ref->node = node; ref->nexthash = tk->next[index]; - tk->next[index] = ref; // FIXME: memory leak of tk->next[index] + tk->next[index] = ref; } next = ref; } @@ -216,6 +217,7 @@ void freetokens(void * root) while (*refs) { tref * ref = *refs; *refs = ref->nexthash; +// free(ref->node); free(ref); } } From 1c2922aafade9cc147f99c80231980bfd4368edf Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 14 Oct 2015 13:57:46 +0200 Subject: [PATCH 40/62] leak: spell names and other strings need to be released. --- src/kernel/spell.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/kernel/spell.c b/src/kernel/spell.c index e5b9a7772..6b161fc99 100644 --- a/src/kernel/spell.c +++ b/src/kernel/spell.c @@ -38,6 +38,9 @@ quicklist * spells; static void free_spell_cb(void *cbdata) { spell *sp = (spell *)cbdata; + free(sp->syntax); + free(sp->parameter); + free(sp->sname); free(sp->components); free(sp); } From 2abdba9e8a019dff21bdaee64a58ff5bfbadb6eb Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 14 Oct 2015 14:08:50 +0200 Subject: [PATCH 41/62] refactor free_messagelist, fix leak in test_merge_split --- src/kernel/faction.c | 12 ++++++++---- src/kernel/messages.c | 15 ++++++--------- src/kernel/messages.h | 2 +- src/kernel/messages.test.c | 9 ++++++--- src/kernel/region.c | 9 ++++++--- src/tests.c | 7 +++++-- 6 files changed, 32 insertions(+), 22 deletions(-) diff --git a/src/kernel/faction.c b/src/kernel/faction.c index 193a582ae..636619310 100755 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -69,13 +69,17 @@ faction *factions; void free_faction(faction * f) { funhash(f); - if (f->msgs) - free_messagelist(f->msgs); + if (f->msgs) { + free_messagelist(f->msgs->begin); + free(f->msgs); + } while (f->battles) { struct bmsg *bm = f->battles; f->battles = bm->next; - if (bm->msgs) - free_messagelist(bm->msgs); + if (bm->msgs) { + free_messagelist(bm->msgs->begin); + free(bm->msgs); + } free(bm); } diff --git a/src/kernel/messages.c b/src/kernel/messages.c index ea45bc835..77b15ea23 100644 --- a/src/kernel/messages.c +++ b/src/kernel/messages.c @@ -283,17 +283,14 @@ void syntax_error(const struct unit *u, struct order *ord) extern unsigned int new_hashstring(const char *s); -void free_messagelist(message_list * msgs) +void free_messagelist(mlist *msgs) { struct mlist **mlistptr; - if (msgs) { - for (mlistptr = &msgs->begin; *mlistptr;) { - struct mlist *ml = *mlistptr; - *mlistptr = ml->next; - msg_release(ml->msg); - free(ml); - } - free(msgs); + for (mlistptr = &msgs; *mlistptr;) { + struct mlist *ml = *mlistptr; + *mlistptr = ml->next; + msg_release(ml->msg); + free(ml); } } diff --git a/src/kernel/messages.h b/src/kernel/messages.h index 6891de586..866eecba7 100644 --- a/src/kernel/messages.h +++ b/src/kernel/messages.h @@ -37,7 +37,7 @@ extern "C" { struct mlist *begin, **end; } message_list; - void free_messagelist(message_list * msgs); + void free_messagelist(struct mlist *msgs); typedef struct msglevel { /* used to set specialized msg-levels */ diff --git a/src/kernel/messages.test.c b/src/kernel/messages.test.c index af95ecf26..e18dd54e8 100644 --- a/src/kernel/messages.test.c +++ b/src/kernel/messages.test.c @@ -39,7 +39,7 @@ void test_message(CuTest *tc) { static void test_merge_split(CuTest *tc) { message_list *mlist = 0, *append = 0; - struct mlist **split; + struct mlist **split; // TODO: why is this a double asterisk? message_type *mtype = mt_new("custom", NULL); test_cleanup(); @@ -57,8 +57,11 @@ static void test_merge_split(CuTest *tc) { CuAssertPtrEquals(tc, append->begin, mlist->begin->next); split_messages(mlist, split); CuAssertPtrEquals(tc, 0, mlist->begin->next); - free_messagelist(mlist); - free_messagelist(append); + free_messagelist(*split); + free_messagelist(mlist->begin); + free(mlist); + free_messagelist(append->begin); + free(append); test_cleanup(); } diff --git a/src/kernel/region.c b/src/kernel/region.c index dd83af4e6..4b57b9e51 100644 --- a/src/kernel/region.c +++ b/src/kernel/region.c @@ -820,15 +820,18 @@ void free_region(region * r) freeland(r->land); if (r->msgs) { - free_messagelist(r->msgs); + free_messagelist(r->msgs->begin); + free(r->msgs); r->msgs = 0; } while (r->individual_messages) { struct individual_message *msg = r->individual_messages; r->individual_messages = msg->next; - if (msg->msgs) - free_messagelist(msg->msgs); + if (msg->msgs) { + free_messagelist(msg->msgs->begin); + free(msg->msgs); + } free(msg); } diff --git a/src/tests.c b/src/tests.c index 6e9ec31a8..00188edca 100644 --- a/src/tests.c +++ b/src/tests.c @@ -286,8 +286,11 @@ struct message * test_find_messagetype(struct message_list *msgs, const char *na } void test_clear_messages(faction *f) { - free_messagelist(f->msgs); - f->msgs = 0; + if (f->msgs) { + free_messagelist(f->msgs->begin); + free(f->msgs); + f->msgs = 0; + } } void disabled_test(void *suite, void (*test)(CuTest *), const char *name) { From e6f2864327d6d14e4b3c6d99e5401805b97532ce Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 14 Oct 2015 14:10:35 +0200 Subject: [PATCH 42/62] leak: duplicate assignment to building_type.name in tests --- src/tests.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tests.c b/src/tests.c index 00188edca..45f2036f6 100644 --- a/src/tests.c +++ b/src/tests.c @@ -154,7 +154,6 @@ building_type * test_create_buildingtype(const char * name) { building_type *btype = bt_get_or_create(name); btype->flags = BTF_NAMECHANGE; - btype->_name = _strdup(name); if (!btype->construction) { btype->construction = (construction *)calloc(sizeof(construction), 1); btype->construction->skill = SK_BUILDING; From ba0828afd4914dc8478863699739d531788e3f64 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 14 Oct 2015 18:34:41 +0200 Subject: [PATCH 43/62] rather complex implementation of selective test running (CuTest does not have this feature). --- src/test_eressea.c | 214 ++++++++++++++++++++++++++++----------------- 1 file changed, 133 insertions(+), 81 deletions(-) diff --git a/src/test_eressea.c b/src/test_eressea.c index ec39f3134..9da222f96 100644 --- a/src/test_eressea.c +++ b/src/test_eressea.c @@ -3,10 +3,42 @@ #include #include #include +#include +#include #include #pragma warning(disable: 4210) +typedef struct suite { + struct suite *next; + CuSuite *csuite; + char *name; +} suite; + +static suite *suites; + +static void add_suite(CuSuite *(*csuite)(void), const char *name, int argc, const char *argv[]) { + suite *s = 0; + if (argc > 1) { + int i; + for (i = 0; i != argc; ++i) { + if (strcmp(argv[i], name) == 0) { + s = malloc(sizeof(suite)); + break; + } + } + } + else { + s = malloc(sizeof(suite)); + } + if (s) { + s->next = suites; + s->name = _strdup(name); + s->csuite = csuite(); + suites = s; + } +} + void RunTests(CuSuite * suite, const char *name) { CuString *output = CuStringNew(); @@ -17,95 +49,115 @@ void RunTests(CuSuite * suite, const char *name) { CuStringDelete(output); } -#define RUN_TESTS(suite, name) \ +bool list = false; + +#define ADD_SUITE(name) \ CuSuite *get_##name##_suite(void); \ - CuSuite *name = get_##name##_suite(); \ - RunTests(name, #name); \ - suite->failCount += name->failCount; \ - suite->count += name->count; \ - CuSuiteDelete(name); + if (list) printf("%s\n", #name); \ + if (!list || argc>0) add_suite(get_##name##_suite, #name, argc, argv) -int RunAllTests(void) +int RunAllTests(int argc, char *argv[]) { - CuSuite *suite = CuSuiteNew(); - int fail_count, flags = log_flags; + CuSuite *summary = CuSuiteNew(); + int flags = log_flags; - log_flags = LOG_FLUSH | LOG_CPERROR; - game_init(); + log_flags = LOG_FLUSH | LOG_CPERROR; + game_init(); - /* self-test */ - RUN_TESTS(suite, tests); - RUN_TESTS(suite, callback); - RUN_TESTS(suite, seen); - RUN_TESTS(suite, json); - RUN_TESTS(suite, jsonconf); - RUN_TESTS(suite, direction); - RUN_TESTS(suite, skill); - RUN_TESTS(suite, keyword); - RUN_TESTS(suite, order); - RUN_TESTS(suite, race); - /* util */ - RUN_TESTS(suite, config); - RUN_TESTS(suite, attrib); - RUN_TESTS(suite, base36); - RUN_TESTS(suite, bsdstring); - RUN_TESTS(suite, functions); - RUN_TESTS(suite, parser); - RUN_TESTS(suite, umlaut); - RUN_TESTS(suite, unicode); - RUN_TESTS(suite, strings); - RUN_TESTS(suite, rng); - /* items */ - RUN_TESTS(suite, xerewards); - /* kernel */ - RUN_TESTS(suite, alliance); - RUN_TESTS(suite, unit); - RUN_TESTS(suite, faction); - RUN_TESTS(suite, group); - RUN_TESTS(suite, build); - RUN_TESTS(suite, pool); - RUN_TESTS(suite, curse); - RUN_TESTS(suite, equipment); - RUN_TESTS(suite, item); - RUN_TESTS(suite, magic); - RUN_TESTS(suite, alchemy); - RUN_TESTS(suite, reports); - RUN_TESTS(suite, save); - RUN_TESTS(suite, ship); - RUN_TESTS(suite, spellbook); - RUN_TESTS(suite, building); - RUN_TESTS(suite, spell); - RUN_TESTS(suite, spells); - RUN_TESTS(suite, magicresistance); - RUN_TESTS(suite, ally); - RUN_TESTS(suite, messages); - /* gamecode */ - RUN_TESTS(suite, prefix); - RUN_TESTS(suite, battle); - RUN_TESTS(suite, donations); - RUN_TESTS(suite, travelthru); - RUN_TESTS(suite, economy); - RUN_TESTS(suite, give); - RUN_TESTS(suite, laws); - RUN_TESTS(suite, market); - RUN_TESTS(suite, move); - RUN_TESTS(suite, piracy); - RUN_TESTS(suite, stealth); - RUN_TESTS(suite, upkeep); - RUN_TESTS(suite, vortex); - RUN_TESTS(suite, wormhole); - RUN_TESTS(suite, spy); - RUN_TESTS(suite, study); + /* self-test */ + ADD_SUITE(tests); + ADD_SUITE(callback); + ADD_SUITE(seen); + ADD_SUITE(json); + ADD_SUITE(jsonconf); + ADD_SUITE(direction); + ADD_SUITE(skill); + ADD_SUITE(keyword); + ADD_SUITE(order); + ADD_SUITE(race); + /* util */ + ADD_SUITE(config); + ADD_SUITE(attrib); + ADD_SUITE(base36); + ADD_SUITE(bsdstring); + ADD_SUITE(functions); + ADD_SUITE(parser); + ADD_SUITE(umlaut); + ADD_SUITE(unicode); + ADD_SUITE(strings); + ADD_SUITE(rng); + /* items */ + ADD_SUITE(xerewards); + /* kernel */ + ADD_SUITE(alliance); + ADD_SUITE(unit); + ADD_SUITE(faction); + ADD_SUITE(group); + ADD_SUITE(build); + ADD_SUITE(pool); + ADD_SUITE(curse); + ADD_SUITE(equipment); + ADD_SUITE(item); + ADD_SUITE(magic); + ADD_SUITE(alchemy); + ADD_SUITE(reports); + ADD_SUITE(save); + ADD_SUITE(ship); + ADD_SUITE(spellbook); + ADD_SUITE(building); + ADD_SUITE(spell); + ADD_SUITE(spells); + ADD_SUITE(magicresistance); + ADD_SUITE(ally); + ADD_SUITE(messages); + /* gamecode */ + ADD_SUITE(prefix); + ADD_SUITE(battle); + ADD_SUITE(donations); + ADD_SUITE(travelthru); + ADD_SUITE(economy); + ADD_SUITE(give); + ADD_SUITE(laws); + ADD_SUITE(market); + ADD_SUITE(move); + ADD_SUITE(piracy); + ADD_SUITE(stealth); + ADD_SUITE(upkeep); + ADD_SUITE(vortex); + ADD_SUITE(wormhole); + ADD_SUITE(spy); + ADD_SUITE(study); - printf("\ntest summary: %d tests, %d failed\n", suite->count, suite->failCount); - log_flags = flags; - fail_count = suite->failCount; - CuSuiteDelete(suite); - game_done(); - return fail_count; + if (suites) { + int fail_count; + while (suites) { + suite *s = suites->next; + RunTests(suites->csuite, suites->name); + summary->failCount += suites->csuite->failCount; + summary->count += suites->csuite->count; + CuSuiteDelete(suites->csuite); + free(suites->name); + free(suites); + suites = s; + } + printf("\ntest summary: %d tests, %d failed\n", summary->count, summary->failCount); + log_flags = flags; + fail_count = summary->failCount; + CuSuiteDelete(summary); + game_done(); + return fail_count; + } + return 0; } int main(int argc, char ** argv) { log_stderr = 0; - return RunAllTests(); + ++argv; + --argc; + if (argc > 0 && strcmp("--list", argv[0]) == 0) { + list = true; + ++argv; + --argc; + } + return RunAllTests(argc, argv); } From 5d192cb4c9c9cb127c072b04da0ee7d3b21f7629 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 14 Oct 2015 18:38:10 +0200 Subject: [PATCH 44/62] fix compile: gcc is extra picky about const char** conversions. --- src/test_eressea.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test_eressea.c b/src/test_eressea.c index 9da222f96..6879d314e 100644 --- a/src/test_eressea.c +++ b/src/test_eressea.c @@ -17,7 +17,7 @@ typedef struct suite { static suite *suites; -static void add_suite(CuSuite *(*csuite)(void), const char *name, int argc, const char *argv[]) { +static void add_suite(CuSuite *(*csuite)(void), const char *name, int argc, char *argv[]) { suite *s = 0; if (argc > 1) { int i; From 47eee298138d8536bc3631b7281b81eb7948fc72 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 14 Oct 2015 18:40:37 +0200 Subject: [PATCH 45/62] correct argument count --- src/test_eressea.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test_eressea.c b/src/test_eressea.c index 6879d314e..71b7137ee 100644 --- a/src/test_eressea.c +++ b/src/test_eressea.c @@ -19,7 +19,7 @@ static suite *suites; static void add_suite(CuSuite *(*csuite)(void), const char *name, int argc, char *argv[]) { suite *s = 0; - if (argc > 1) { + if (argc > 0) { int i; for (i = 0; i != argc; ++i) { if (strcmp(argv[i], name) == 0) { From 203b058166133304f6f1cd7a4b2d3a8ff3ee6b35 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 14 Oct 2015 20:04:03 +0200 Subject: [PATCH 46/62] avoid memory leaks when running with --list --- src/test_eressea.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test_eressea.c b/src/test_eressea.c index 71b7137ee..aad65c539 100644 --- a/src/test_eressea.c +++ b/src/test_eressea.c @@ -58,11 +58,9 @@ bool list = false; int RunAllTests(int argc, char *argv[]) { - CuSuite *summary = CuSuiteNew(); int flags = log_flags; log_flags = LOG_FLUSH | LOG_CPERROR; - game_init(); /* self-test */ ADD_SUITE(tests); @@ -129,7 +127,9 @@ int RunAllTests(int argc, char *argv[]) ADD_SUITE(study); if (suites) { + CuSuite *summary = CuSuiteNew(); int fail_count; + game_init(); while (suites) { suite *s = suites->next; RunTests(suites->csuite, suites->name); From 5018bbb0c0c99aa53787ccfd4b20c620ccfd4e52 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 14 Oct 2015 20:21:38 +0200 Subject: [PATCH 47/62] correctly release messages created in test_merge_split --- src/kernel/messages.test.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/kernel/messages.test.c b/src/kernel/messages.test.c index e18dd54e8..fc6079dfe 100644 --- a/src/kernel/messages.test.c +++ b/src/kernel/messages.test.c @@ -41,11 +41,14 @@ static void test_merge_split(CuTest *tc) { message_list *mlist = 0, *append = 0; struct mlist **split; // TODO: why is this a double asterisk? message_type *mtype = mt_new("custom", NULL); + message *msg; test_cleanup(); mt_register(mtype); - add_message(&mlist, msg_message(mtype->name, "")); - add_message(&append, msg_message(mtype->name, "")); + add_message(&mlist, msg = msg_message(mtype->name, "")); + msg_release(msg); + add_message(&append, msg = msg_message(mtype->name, "")); + msg_release(msg); CuAssertPtrEquals(tc, 0, mlist->begin->next); CuAssertPtrEquals(tc, &mlist->begin->next, mlist->end); From 0f3263059029d31dbcfddc6879af232ba68bfeb4 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 14 Oct 2015 20:22:51 +0200 Subject: [PATCH 48/62] leak: release message in test --- src/spells/magicresistance.test.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/spells/magicresistance.test.c b/src/spells/magicresistance.test.c index 55a5effaa..4b0d69388 100644 --- a/src/spells/magicresistance.test.c +++ b/src/spells/magicresistance.test.c @@ -44,6 +44,7 @@ static void test_magicresistance_unit(CuTest *tc) { msg = c->type->curseinfo(u2, TYP_UNIT, c, 1); CuAssertPtrNotNull(tc, msg); CuAssertStrEquals(tc, "curseinfo::magicresistance_unit", test_get_messagetype(msg)); + msg_release(msg); test_cleanup(); } From 144aeb23ac35d643ea5a496e632137ea3c82f079 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 14 Oct 2015 20:29:07 +0200 Subject: [PATCH 49/62] leaks: call cleanup, free triggers --- src/kernel/pool.test.c | 1 + src/util/event.c | 1 + 2 files changed, 2 insertions(+) diff --git a/src/kernel/pool.test.c b/src/kernel/pool.test.c index 711803970..4cc44388f 100644 --- a/src/kernel/pool.test.c +++ b/src/kernel/pool.test.c @@ -178,6 +178,7 @@ void test_change_resource(CuTest * tc) CuAssertIntEquals(tc, have + 1, change_resource(u, rtype, 1)); CuAssertIntEquals(tc, have + 1, get_resource(u, rtype)); } + test_cleanup(); } CuSuite *get_pool_suite(void) diff --git a/src/util/event.c b/src/util/event.c index 594a5b962..5784a116a 100644 --- a/src/util/event.c +++ b/src/util/event.c @@ -94,6 +94,7 @@ void free_triggers(trigger * triggers) trigger *t = triggers; triggers = t->next; t_free(t); + free(t); } } From f740f2829a881eed3de9722de4d52f010812fcfd Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 14 Oct 2015 20:41:42 +0200 Subject: [PATCH 50/62] leak: in tests, when correct message_type doesn't exist, arguments should not leak --- src/kernel/build.c | 10 +++++++++- src/reports.c | 19 ++++++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/kernel/build.c b/src/kernel/build.c index 931c730f0..bc5df861d 100644 --- a/src/kernel/build.c +++ b/src/kernel/build.c @@ -627,19 +627,27 @@ message *msg_materials_required(unit * u, order * ord, const construction * ctype, int multi) { int c; + message *msg; /* something missing from the list of materials */ resource *reslist = NULL; if (multi <= 0 || multi == INT_MAX) multi = 1; for (c = 0; ctype && ctype->materials[c].number; ++c) { + // TODO: lots of alloc/dealloc calls here (make var_copy_resources take an array) resource *res = malloc(sizeof(resource)); res->number = multi * ctype->materials[c].number / ctype->reqsize; res->type = ctype->materials[c].rtype; res->next = reslist; reslist = res; } - return msg_feedback(u, ord, "build_required", "required", reslist); + msg = msg_feedback(u, ord, "build_required", "required", reslist); + while (reslist) { + resource *res = reslist->next; + free(reslist); + reslist = res; + } + return msg; } int maxbuild(const unit * u, const construction * cons) diff --git a/src/reports.c b/src/reports.c index eed25cd45..f09344ee1 100644 --- a/src/reports.c +++ b/src/reports.c @@ -1733,6 +1733,23 @@ static variant var_copy_items(variant x) return x; } +static variant var_copy_resources(variant x) +{ + resource *rsrc; + resource *rdst = NULL, **rptr = &rdst; + + for (rsrc = (resource *)x.v; rsrc != NULL; rsrc = rsrc->next) { + resource *res = malloc(sizeof(resource)); + res->number = rsrc->number; + res->type = rsrc->type; + *rptr = res; + rptr = &res->next; + } + *rptr = NULL; + x.v = rdst; + return x; +} + static void var_free_resources(variant x) { resource *rsrc = (resource *)x.v; @@ -2295,7 +2312,7 @@ void register_reports(void) register_argtype("int", NULL, NULL, VAR_INT); register_argtype("string", var_free_string, var_copy_string, VAR_VOIDPTR); register_argtype("order", var_free_order, var_copy_order, VAR_VOIDPTR); - register_argtype("resources", var_free_resources, NULL, VAR_VOIDPTR); + register_argtype("resources", var_free_resources, var_copy_resources, VAR_VOIDPTR); register_argtype("items", var_free_resources, var_copy_items, VAR_VOIDPTR); register_argtype("regions", var_free_regions, NULL, VAR_VOIDPTR); From 284a74c87871f36e49e7bb166f1681e8afb3e0b2 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 14 Oct 2015 20:45:43 +0200 Subject: [PATCH 51/62] leak: deleting a config entry did not free its name --- src/kernel/config.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/kernel/config.c b/src/kernel/config.c index 3410f7bff..e2ae97c55 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -1144,6 +1144,7 @@ void set_param(struct param **p, const char *key, const char *data) } else { *p = par->next; + free(par->name); free(par); } return; From 03ff8f612da033a7547563afd677eb7ac6cf373a Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 14 Oct 2015 20:48:01 +0200 Subject: [PATCH 52/62] leaks: remember to call test_cleanup --- src/kernel/order.test.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/kernel/order.test.c b/src/kernel/order.test.c index 84dc61323..d0ba58619 100644 --- a/src/kernel/order.test.c +++ b/src/kernel/order.test.c @@ -99,8 +99,11 @@ static void test_parse_make_temp(CuTest *tc) { static void test_parse_maketemp(CuTest *tc) { char cmd[32]; order *ord; - struct locale * lang = get_or_create_locale("en"); + struct locale * lang; + + test_cleanup(); + lang = get_or_create_locale("en"); locale_setstring(lang, keyword(K_MAKE), "MAKE"); locale_setstring(lang, keyword(K_MAKETEMP), "MAKETEMP"); locale_setstring(lang, "TEMP", "TEMP"); @@ -113,17 +116,22 @@ static void test_parse_maketemp(CuTest *tc) { CuAssertIntEquals(tc, K_MAKETEMP, init_order(ord)); CuAssertStrEquals(tc, "herp", getstrtoken()); free_order(ord); + test_cleanup(); } static void test_init_order(CuTest *tc) { order *ord; - struct locale * lang = get_or_create_locale("en"); + struct locale * lang; + test_cleanup(); + + lang = get_or_create_locale("en"); ord = create_order(K_MAKETEMP, lang, "hurr durr"); CuAssertIntEquals(tc, K_MAKETEMP, init_order(ord)); CuAssertStrEquals(tc, "hurr", getstrtoken()); CuAssertStrEquals(tc, "durr", getstrtoken()); free_order(ord); + test_cleanup(); } static void test_getstrtoken(CuTest *tc) { From a3b27ad6d2b3f79d5f01890ea5a31d8eaa571fb2 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 14 Oct 2015 20:49:30 +0200 Subject: [PATCH 53/62] leak: remember to call test_cleanup --- src/kernel/order.test.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/kernel/order.test.c b/src/kernel/order.test.c index d0ba58619..b53fd9d05 100644 --- a/src/kernel/order.test.c +++ b/src/kernel/order.test.c @@ -154,8 +154,10 @@ static void test_skip_token(CuTest *tc) { static void test_replace_order(CuTest *tc) { order *orders = 0, *orig, *repl; - struct locale * lang = get_or_create_locale("en"); + struct locale * lang; + test_cleanup(); + lang = get_or_create_locale("en"); orig = create_order(K_MAKE, lang, 0); repl = create_order(K_ALLY, lang, 0); replace_order(&orders, orig, repl); @@ -165,6 +167,7 @@ static void test_replace_order(CuTest *tc) { CuAssertPtrNotNull(tc, orders); CuAssertPtrEquals(tc, 0, orders->next); CuAssertIntEquals(tc, getkeyword(repl), getkeyword(orders)); + test_cleanup(); } CuSuite *get_order_suite(void) From c04bda102b5ed5c3c57253c43a976dff2435bab4 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 14 Oct 2015 20:56:09 +0200 Subject: [PATCH 54/62] call free_order for each remaining reference --- src/kernel/order.test.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/kernel/order.test.c b/src/kernel/order.test.c index b53fd9d05..635e6e078 100644 --- a/src/kernel/order.test.c +++ b/src/kernel/order.test.c @@ -167,6 +167,8 @@ static void test_replace_order(CuTest *tc) { CuAssertPtrNotNull(tc, orders); CuAssertPtrEquals(tc, 0, orders->next); CuAssertIntEquals(tc, getkeyword(repl), getkeyword(orders)); + free_order(orders); + free_order(repl); test_cleanup(); } From b5455531e72249fa6b84b94abdbc7161a7c34020 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 14 Oct 2015 21:37:27 +0200 Subject: [PATCH 55/62] do not leak terrain.herbs --- src/kernel/jsonconf.c | 1 + src/kernel/terrain.c | 1 + 2 files changed, 2 insertions(+) diff --git a/src/kernel/jsonconf.c b/src/kernel/jsonconf.c index c8126715a..9e23c3360 100644 --- a/src/kernel/jsonconf.c +++ b/src/kernel/jsonconf.c @@ -270,6 +270,7 @@ static void json_terrain(cJSON *json, terrain_type *ter) { int size = cJSON_GetArraySize(child); if (size > 0) { int n; + free(ter->herbs); ter->herbs = malloc(sizeof(const item_type *) * (size + 1)); ter->herbs[size] = 0; for (n = 0, entry = child->child; entry; entry = entry->next) { diff --git a/src/kernel/terrain.c b/src/kernel/terrain.c index e72e94bfa..ac4a49fe9 100644 --- a/src/kernel/terrain.c +++ b/src/kernel/terrain.c @@ -63,6 +63,7 @@ void free_terrains(void) terrain_type * t = registered_terrains; registered_terrains = t->next; free(t->_name); + free(t->herbs); if (t->production) { for (n = 0; t->production[n].type; ++n) { free(t->production[n].base); From 3200dd2dc86a6f96c9ae4528c9fbe51733067f84 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 14 Oct 2015 21:51:43 +0200 Subject: [PATCH 56/62] leak: free locale_data --- src/kernel/order.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/kernel/order.c b/src/kernel/order.c index 245f6c6b5..00d2a838d 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -259,13 +259,12 @@ static void free_localedata(int lindex) { int i; for (i = 0; i != MAXKEYWORDS; ++i) { release_data(locale_array[lindex]->short_orders[i]); - locale_array[lindex]->short_orders[i] = 0; } for (i = 0; i != MAXSKILLS; ++i) { release_data(locale_array[lindex]->study_orders[i]); - locale_array[lindex]->study_orders[i] = 0; } - locale_array[lindex]->lang = 0; + free(locale_array[lindex]); + locale_array[lindex] = 0; } void close_orders(void) { From ef1a2dfc4f9b3676ce7c1d18fd9755d673341e8a Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 14 Oct 2015 22:06:40 +0200 Subject: [PATCH 57/62] fixed a crash --- src/kernel/order.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/kernel/order.c b/src/kernel/order.c index 00d2a838d..f79b2dd68 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -255,22 +255,27 @@ static order_data *create_data(keyword_t kwd, const char *sptr, int lindex) return data; } -static void free_localedata(int lindex) { +static void clear_localedata(int lindex) { int i; for (i = 0; i != MAXKEYWORDS; ++i) { release_data(locale_array[lindex]->short_orders[i]); + locale_array[lindex]->short_orders[i] = 0; } for (i = 0; i != MAXSKILLS; ++i) { release_data(locale_array[lindex]->study_orders[i]); + locale_array[lindex]->study_orders[i] = 0; } - free(locale_array[lindex]); - locale_array[lindex] = 0; + locale_array[lindex]->lang = 0; } void close_orders(void) { int i; for (i = 0; i != MAXLOCALES; ++i) { - if (locale_array[i]) free_localedata(i); + if (locale_array[i]){ + clear_localedata(i); + free(locale_array[i]); + locale_array[i] = 0; + } } } @@ -302,7 +307,7 @@ static order *create_order_i(keyword_t kwd, const char *sptr, bool persistent, locale_array[lindex] = (locale_data *)calloc(1, sizeof(locale_data)); } else if (locale_array[lindex]->lang != lang) { - free_localedata(lindex); + clear_localedata(lindex); } locale_array[lindex]->lang = lang; From 467ce2a719bcfb2778cad77a9eb417fc3b3c9141 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 14 Oct 2015 22:09:11 +0200 Subject: [PATCH 58/62] visual studio compilation fix --- src/kernel/terrain.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel/terrain.h b/src/kernel/terrain.h index 945d07794..931a74861 100644 --- a/src/kernel/terrain.h +++ b/src/kernel/terrain.h @@ -64,7 +64,7 @@ extern "C" { short max_road; /* this many stones make a full road */ short distribution; /* multiplier used for seeding */ struct terrain_production *production; - const struct item_type **herbs; /* zero-terminated array of herbs */ + struct item_type **herbs; /* zero-terminated array of herbs */ const char *(*name) (const struct region * r); struct terrain_type *next; } terrain_type; From d79745812acef454e59adacc604b0135dc9fbd8a Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 14 Oct 2015 22:19:15 +0200 Subject: [PATCH 59/62] unit needs to be in a region or test_cleanup will not free it --- src/travelthru.test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/travelthru.test.c b/src/travelthru.test.c index f92188751..74ab29b7e 100644 --- a/src/travelthru.test.c +++ b/src/travelthru.test.c @@ -35,7 +35,7 @@ static void setup_travelthru(travel_fixture *fix, int nunits) { } f = test_create_faction(0); while (nunits--) { - unit *u = test_create_unit(f, 0); + unit *u = test_create_unit(f, test_create_region(1, 0, 0)); travelthru_add(r, u); } fix->r = r; From d4655ee88aeafc4ec1c4f87b7ae39f1bf5c80a96 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 15 Oct 2015 08:29:20 +0200 Subject: [PATCH 60/62] leak: do not create new message_type objects in test_cleanup --- src/kernel/config.c | 4 ---- src/kernel/curse.test.c | 2 +- src/kernel/messages.c | 6 ++++++ src/tests.c | 4 ---- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/kernel/config.c b/src/kernel/config.c index e2ae97c55..19390799d 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -1597,10 +1597,6 @@ void kernel_init(void) { register_reports(); mt_clear(); - if (!mt_find("missing_message")) { - mt_register(mt_new_va("missing_message", "name:string", 0)); - mt_register(mt_new_va("missing_feedback", "unit:unit", "region:region", "command:order", "name:string", 0)); - } attrib_init(); translation_init(); } diff --git a/src/kernel/curse.test.c b/src/kernel/curse.test.c index bf9f1c85c..002ef18ec 100644 --- a/src/kernel/curse.test.c +++ b/src/kernel/curse.test.c @@ -157,6 +157,6 @@ CuSuite *get_curse_suite(void) SUITE_ADD_TEST(suite, test_good_dreams); SUITE_ADD_TEST(suite, test_bad_dreams); SUITE_ADD_TEST(suite, test_memstream); - DISABLE_TEST(suite, test_write_flag); + SUITE_ADD_TEST(suite, test_write_flag); return suite; } diff --git a/src/kernel/messages.c b/src/kernel/messages.c index 77b15ea23..779354498 100644 --- a/src/kernel/messages.c +++ b/src/kernel/messages.c @@ -91,6 +91,9 @@ struct message *msg_feedback(const struct unit *u, struct order *ord, if (!mtype) { log_error("trying to create message of unknown type \"%s\"\n", name); + if (!mt_find("missing_feedback")) { + mt_register(mt_new_va("missing_feedback", "unit:unit", "region:region", "command:order", "name:string", 0)); + } return msg_message("missing_feedback", "unit region command name", u, u->region, ord, name); } @@ -154,6 +157,9 @@ message *msg_message(const char *name, const char *sig, ...) if (!mtype) { log_warning("trying to create message of unknown type \"%s\"\n", name); if (strcmp(name, "missing_message") != 0) { + if (!mt_find("missing_message")) { + mt_register(mt_new_va("missing_message", "name:string", 0)); + } return msg_message("missing_message", "name", name); } return NULL; diff --git a/src/tests.c b/src/tests.c index 45f2036f6..347418ce5 100644 --- a/src/tests.c +++ b/src/tests.c @@ -97,10 +97,6 @@ void test_cleanup(void) for (i = 0; i != MAXKEYWORDS; ++i) { enable_keyword(i, true); } - if (!mt_find("missing_message")) { - mt_register(mt_new_va("missing_message", "name:string", 0)); - mt_register(mt_new_va("missing_feedback", "unit:unit", "region:region", "command:order", "name:string", 0)); - } if (errno) { int error = errno; errno = 0; From c9e7a76d9b5a63d38245b548f0fffaddfa9c4638 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 15 Oct 2015 08:38:43 +0200 Subject: [PATCH 61/62] minor leak: release memory held by curse_type structures --- src/eressea.c | 2 ++ src/kernel/curse.c | 12 ++++++++++-- src/kernel/curse.h | 2 ++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/eressea.c b/src/eressea.c index 703334993..d08a60df6 100755 --- a/src/eressea.c +++ b/src/eressea.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -48,6 +49,7 @@ void game_done(void) calendar_cleanup(); #endif free_functions(); + free_curses(); kernel_done(); } diff --git a/src/kernel/curse.c b/src/kernel/curse.c index 828552a3a..fe32ef1e0 100644 --- a/src/kernel/curse.c +++ b/src/kernel/curse.c @@ -293,11 +293,12 @@ attrib_type at_curse = { #include #include -static quicklist *cursetypes[256]; +#define MAXCTHASH 128 +static quicklist *cursetypes[MAXCTHASH]; void ct_register(const curse_type * ct) { - unsigned int hash = tolower(ct->cname[0]); + unsigned int hash = tolower(ct->cname[0]) & 0xFF; quicklist **ctlp = cursetypes + hash; ql_set_insert(ctlp, (void *)ct); @@ -818,3 +819,10 @@ double destr_curse(curse * c, int cast_level, double force) } return force; } + +void free_curses(void) { + int i; + for (i = 0; i != MAXCTHASH; ++i) { + ql_free(cursetypes[i]); + } +} \ No newline at end of file diff --git a/src/kernel/curse.h b/src/kernel/curse.h index 80ce3109d..143e73d27 100644 --- a/src/kernel/curse.h +++ b/src/kernel/curse.h @@ -214,6 +214,8 @@ extern "C" { int duration; /* Dauer der Verzauberung. Wird jede Runde vermindert */ } curse; + void free_curses(void); /* de-register all curse-types */ + extern struct attrib_type at_curse; void curse_write(const struct attrib *a, const void *owner, struct storage *store); From 47e925473e79c5f395dc4d577f9d8cf823ed0af0 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 15 Oct 2015 08:40:52 +0200 Subject: [PATCH 62/62] always use a macro, not magical constants --- src/kernel/curse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel/curse.c b/src/kernel/curse.c index fe32ef1e0..09fcdb1d1 100644 --- a/src/kernel/curse.c +++ b/src/kernel/curse.c @@ -334,7 +334,7 @@ void ct_checknames(void) { int i, qi; quicklist *ctl; - for (i = 0; i < 256; ++i) { + for (i = 0; i < MAXCTHASH; ++i) { ctl = cursetypes[i]; for (qi = 0; ctl; ql_advance(&ctl, &qi, 1)) { curse_type *type = (curse_type *)ql_get(ctl, qi);