fix memory leak in umlaut.c with reference counting (sad).

This commit is contained in:
Enno Rehling 2016-09-06 19:57:07 +01:00
parent b62fa64d8c
commit a5ce809f41
11 changed files with 45 additions and 38 deletions

View File

@ -12,7 +12,7 @@ void init_direction(const struct locale *lang, direction_t dir, const char *str)
void **tokens = get_translations(lang, UT_DIRECTIONS); void **tokens = get_translations(lang, UT_DIRECTIONS);
variant token; variant token;
token.i = dir; token.i = dir;
addtoken(tokens, str, token); addtoken((struct tnode **)tokens, str, token);
} }
void init_directions(struct locale *lang) { void init_directions(struct locale *lang) {
@ -47,7 +47,7 @@ void init_directions(struct locale *lang) {
if (str) { if (str) {
variant token; variant token;
token.i = dirs[i].direction; token.i = dirs[i].direction;
addtoken(tokens, str, token); addtoken((struct tnode **)tokens, str, token);
} }
} }
} }

View File

@ -311,7 +311,7 @@ const building_type *findbuildingtype(const char *name,
const char *n = LOC(lang, btype->_name); const char *n = LOC(lang, btype->_name);
type.v = (void *)btype; type.v = (void *)btype;
addtoken(&bn->names, n, type); addtoken((struct tnode **)&bn->names, n, type);
} }
bnames = bn; bnames = bn;
} }

View File

@ -78,7 +78,7 @@ const char *str, parser fun)
cmd->fun = fun; cmd->fun = fun;
cmd->nodes = tnext; cmd->nodes = tnext;
var.v = cmd; var.v = cmd;
addtoken(keys, str, var); addtoken((struct tnode **)keys, str, var);
} }
static int do_command_i(const void *keys, struct unit *u, struct order *ord) static int do_command_i(const void *keys, struct unit *u, struct order *ord)

View File

@ -471,7 +471,7 @@ void init_terrains_translation(const struct locale *lang) {
var.v = (void *)terrain; var.v = (void *)terrain;
name = locale_string(lang, terrain->_name, false); name = locale_string(lang, terrain->_name, false);
if (name) { if (name) {
addtoken(tokens, name, var); addtoken((struct tnode **)tokens, name, var);
} }
else { else {
log_debug("no translation for terrain %s in locale %s", terrain->_name, locale_name(lang)); log_debug("no translation for terrain %s in locale %s", terrain->_name, locale_name(lang));
@ -490,7 +490,7 @@ void init_options_translation(const struct locale * lang) {
if (options[i]) { if (options[i]) {
const char *name = locale_string(lang, options[i], false); const char *name = locale_string(lang, options[i], false);
if (name) { if (name) {
addtoken(tokens, name, var); addtoken((struct tnode **)tokens, name, var);
} }
else { else {
log_debug("no translation for OPTION %s in locale %s", options[i], locale_name(lang)); log_debug("no translation for OPTION %s in locale %s", options[i], locale_name(lang));
@ -525,7 +525,7 @@ void init_locale(struct locale *lang)
var.i = i; var.i = i;
name = LOC(lang, mkname("school", tok)); name = LOC(lang, mkname("school", tok));
if (name) { if (name) {
addtoken(tokens, name, var); addtoken((struct tnode **)tokens, name, var);
} }
else { else {
log_warning("no translation for magic school %s in locale %s", tok, locale_name(lang)); log_warning("no translation for magic school %s in locale %s", tok, locale_name(lang));
@ -544,9 +544,9 @@ void init_locale(struct locale *lang)
const char *name; const char *name;
var.v = (void *)rc; var.v = (void *)rc;
name = locale_string(lang, rc_name_s(rc, NAME_PLURAL), false); name = locale_string(lang, rc_name_s(rc, NAME_PLURAL), false);
if (name) addtoken(tokens, name, var); if (name) addtoken((struct tnode **)tokens, name, var);
name = locale_string(lang, rc_name_s(rc, NAME_SINGULAR), false); name = locale_string(lang, rc_name_s(rc, NAME_SINGULAR), false);
if (name) addtoken(tokens, name, var); if (name) addtoken((struct tnode **)tokens, name, var);
} }
init_parameters(lang); init_parameters(lang);

View File

@ -78,7 +78,7 @@ const ship_type *findshiptype(const char *name, const struct locale *lang)
variant var2; variant var2;
const char *n = LOC(lang, stype->_name); const char *n = LOC(lang, stype->_name);
var2.v = (void *)stype; var2.v = (void *)stype;
addtoken(&sn->names, n, var2); addtoken((struct tnode **)&sn->names, n, var2);
} }
snames = sn; snames = sn;
} }

View File

@ -1438,8 +1438,8 @@ static void init_prefixnames(void)
LOC(lang, mkname("prefix", race_prefixes[key])); LOC(lang, mkname("prefix", race_prefixes[key]));
if (findtoken(in->names, pname, &var) == E_TOK_NOMATCH || var.i != key) { if (findtoken(in->names, pname, &var) == E_TOK_NOMATCH || var.i != key) {
var.i = key; var.i = key;
addtoken(&in->names, pname, var); addtoken((struct tnode **)&in->names, pname, var);
addtoken(&in->names, LOC(lang, mkname("prefix", addtoken((struct tnode **)&in->names, LOC(lang, mkname("prefix",
race_prefixes[key])), var); race_prefixes[key])), var);
} }
} }

View File

@ -2954,7 +2954,7 @@ static void select_spellbook(void **tokens, spellbook *sb, const struct locale *
else { else {
variant token; variant token;
token.v = sp; token.v = sp;
addtoken(tokens, n, token); addtoken((struct tnode **)tokens, n, token);
} }
} }
} }

View File

@ -32,7 +32,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
typedef struct tref { typedef struct tref {
struct tref *nexthash; struct tref *nexthash;
ucs4_t ucs; ucs4_t ucs;
void *node; struct tnode *node;
} tref; } tref;
#define LEAF 1 /* leaf node for a word. always matches */ #define LEAF 1 /* leaf node for a word. always matches */
@ -42,6 +42,7 @@ typedef struct tnode {
struct tref *next[NODEHASHSIZE]; struct tref *next[NODEHASHSIZE];
unsigned char flags; unsigned char flags;
variant id; variant id;
int refcount;
} tnode; } tnode;
char * transliterate(char * out, size_t size, const char * in) char * transliterate(char * out, size_t size, const char * in)
@ -114,7 +115,13 @@ char * transliterate(char * out, size_t size, const char * in)
return *src ? 0 : out; return *src ? 0 : out;
} }
void addtoken(void ** root, const char *str, variant id) tnode * mknode(void) {
tnode * node = calloc(1, sizeof(tnode));
node->refcount = 1;
return node;
}
void addtoken(tnode ** root, const char *str, variant id)
{ {
tnode * tk; tnode * tk;
static const struct replace { static const struct replace {
@ -128,7 +135,7 @@ void addtoken(void ** root, const char *str, variant id)
assert(root && str); assert(root && str);
if (!*root) { if (!*root) {
tk = *root = calloc(1, sizeof(tnode)); tk = *root = mknode();
} }
else { else {
tk = *root; tk = *root;
@ -161,7 +168,7 @@ void addtoken(void ** root, const char *str, variant id)
next = next->nexthash; next = next->nexthash;
if (!next) { if (!next) {
tref *ref; tref *ref;
tnode *node = (tnode *)calloc(1, sizeof(tnode)); // TODO: what is the reason for this empty node to exist? tnode *node = mknode(); // TODO: what is the reason for this empty node to exist?
if (ucs < 'a' || ucs > 'z') { if (ucs < 'a' || ucs > 'z') {
lcs = towlower((wint_t)ucs); lcs = towlower((wint_t)ucs);
@ -187,6 +194,7 @@ void addtoken(void ** root, const char *str, variant id)
assert_alloc(ref); assert_alloc(ref);
ref->ucs = lcs; ref->ucs = lcs;
ref->node = node; ref->node = node;
++node->refcount;
ref->nexthash = tk->next[index]; ref->nexthash = tk->next[index];
tk->next[index] = ref; tk->next[index] = ref;
} }
@ -212,23 +220,25 @@ void addtoken(void ** root, const char *str, variant id)
} }
} }
void freetokens(void * root) void freetokens(tnode * root)
{ {
tnode * node = (tnode *)root; tnode * node = root;
int i; int i;
for (i = 0; node && i != NODEHASHSIZE; ++i) { for (i = 0; node && i != NODEHASHSIZE; ++i) {
if (node->next[i]) { if (node->next[i]) {
tref ** refs = &node->next[i]; tref * ref = node->next[i];
freetokens(node->next[i]->node); while (ref) {
while (*refs) { tref * next = ref->nexthash;
tref * ref = *refs; freetokens(ref->node);
*refs = ref->nexthash;
// free(ref->node);
free(ref); free(ref);
ref = next;
} }
node->next[i] = 0;
} }
} }
free(node); if (--node->refcount == 0) {
free(node);
}
} }
int findtoken(const void * root, const char *key, variant * result) int findtoken(const void * root, const char *key, variant * result)

View File

@ -29,10 +29,11 @@ extern "C" {
#define E_TOK_NOMATCH (-1) #define E_TOK_NOMATCH (-1)
#define E_TOK_SUCCESS 0 #define E_TOK_SUCCESS 0
#define NODEHASHSIZE 8 #define NODEHASHSIZE 8
struct tnode;
int findtoken(const void *tk, const char *str, variant * result); int findtoken(const void *tk, const char *str, variant * result);
void addtoken(void **root, const char *str, variant id); void addtoken(struct tnode **root, const char *str, variant id);
void freetokens(void *root); void freetokens(struct tnode *root);
char * transliterate(char * out, size_t size, const char * in); char * transliterate(char * out, size_t size, const char * in);

View File

@ -4,7 +4,6 @@
#include <string.h> #include <string.h>
#include "umlaut.h" #include "umlaut.h"
#ifdef LEAK_FREE
static void test_transliterate(CuTest * tc) static void test_transliterate(CuTest * tc)
{ {
char buffer[32]; char buffer[32];
@ -29,7 +28,7 @@ static void test_transliterate(CuTest * tc)
static void test_transliterations(CuTest *tc) { static void test_transliterations(CuTest *tc) {
const char * umlauts = "\xc3\xa4\xc3\xb6\xc3\xbc\xc3\x9f"; /* auml ouml uuml szlig nul */ const char * umlauts = "\xc3\xa4\xc3\xb6\xc3\xbc\xc3\x9f"; /* auml ouml uuml szlig nul */
void * tokens = 0; struct tnode * tokens = 0;
variant id; variant id;
int result; int result;
@ -49,7 +48,7 @@ static void test_transliterations(CuTest *tc) {
static void test_directions(CuTest * tc) static void test_directions(CuTest * tc)
{ {
void * tokens = 0; struct tnode * tokens = 0;
variant id; variant id;
int result; int result;
@ -65,7 +64,7 @@ static void test_directions(CuTest * tc)
static void test_umlaut(CuTest * tc) static void test_umlaut(CuTest * tc)
{ {
void * tokens = 0; struct tnode *tokens = 0;
variant id; variant id;
int result; int result;
@ -97,14 +96,13 @@ static void test_umlaut(CuTest * tc)
freetokens(tokens); freetokens(tokens);
} }
#endif
static void test_leak(CuTest *tc) { static void test_leak(CuTest *tc) {
void *tokens = NULL; struct tnode *tokens = NULL;
variant token; variant token;
token.i = 42; token.i = 42;
addtoken(&tokens, "No", token); addtoken(&tokens, "NO", token);
addtoken(&tokens, "nw", token); addtoken(&tokens, "nw", token);
CuAssertIntEquals(tc, E_TOK_SUCCESS, findtoken(tokens, "n", &token)); CuAssertIntEquals(tc, E_TOK_SUCCESS, findtoken(tokens, "n", &token));
freetokens(tokens); freetokens(tokens);
@ -113,12 +111,10 @@ static void test_leak(CuTest *tc) {
CuSuite *get_umlaut_suite(void) CuSuite *get_umlaut_suite(void)
{ {
CuSuite *suite = CuSuiteNew(); CuSuite *suite = CuSuiteNew();
#ifdef LEAK_FREE
SUITE_ADD_TEST(suite, test_umlaut); SUITE_ADD_TEST(suite, test_umlaut);
SUITE_ADD_TEST(suite, test_directions); SUITE_ADD_TEST(suite, test_directions);
SUITE_ADD_TEST(suite, test_transliterate); SUITE_ADD_TEST(suite, test_transliterate);
SUITE_ADD_TEST(suite, test_transliterations); SUITE_ADD_TEST(suite, test_transliterations);
#endif
SUITE_ADD_TEST(suite, test_leak); SUITE_ADD_TEST(suite, test_leak);
return suite; return suite;
} }

View File

@ -36,7 +36,7 @@ void register_special_direction(struct locale *lang, const char *name)
char *str = _strdup(name); char *str = _strdup(name);
var.v = str; var.v = str;
addtoken(tokens, token, var); addtoken((struct tnode **)tokens, token, var);
if (lang == locales) { if (lang == locales) {
dir_lookup *dl = malloc(sizeof(dir_lookup)); dir_lookup *dl = malloc(sizeof(dir_lookup));