From d0fe4b4f3f4012af9c6df704bcd545c6a61e952d Mon Sep 17 00:00:00 2001 From: Cedric BAIL Date: Fri, 24 Oct 2008 14:06:40 +0000 Subject: [PATCH] * Bug fix : - Array layout would be broken or worse not possible to reload at all if you put NULL pointer in it. - Array of string now work. - Fix a double free issue with array on double load. * Add the test to detect this case. SVN revision: 37051 --- legacy/eet/src/lib/Eet.h | 3 +- legacy/eet/src/lib/eet_data.c | 184 ++++++++++++++++++++++++++----- legacy/eet/src/tests/eet_suite.c | 24 +++- 3 files changed, 181 insertions(+), 30 deletions(-) diff --git a/legacy/eet/src/lib/Eet.h b/legacy/eet/src/lib/Eet.h index 7fc9dbb49a..606c7fe733 100644 --- a/legacy/eet/src/lib/Eet.h +++ b/legacy/eet/src/lib/Eet.h @@ -57,7 +57,8 @@ extern "C" { #define EET_T_ULONG_LONG 10 /**< Data type: unsigned long long */ #define EET_T_STRING 11 /**< Data type: char * */ #define EET_T_INLINED_STRING 12 /**< Data type: char * (but compressed inside the resulting eet) */ -#define EET_T_LAST 13 /**< Last data type */ +#define EET_T_NULL 13 /**< Data type: (void *) (only use it if you know why) */ +#define EET_T_LAST 14 /**< Last data type */ #define EET_G_UNKNOWN 100 /**< Unknown group data encoding type */ #define EET_G_ARRAY 101 /**< Fixed size array group type */ diff --git a/legacy/eet/src/lib/eet_data.c b/legacy/eet/src/lib/eet_data.c index 2d60ede8cc..be83422934 100644 --- a/legacy/eet/src/lib/eet_data.c +++ b/legacy/eet/src/lib/eet_data.c @@ -193,6 +193,8 @@ static inline int eet_data_get_string(const Eet_Dictionary *ed, const void *sr static void *eet_data_put_string(Eet_Dictionary *ed, const void *src, int *size_ret); static int eet_data_get_istring(const Eet_Dictionary *ed, const void *src, const void *src_end, void *dest); static void *eet_data_put_istring(Eet_Dictionary *ed, const void *src, int *size_ret); +static int eet_data_get_null(const Eet_Dictionary *ed, const void *src, const void *src_end, void *dest); +static void *eet_data_put_null(Eet_Dictionary *ed, const void *src, int *size_ret); static int eet_data_get_type(const Eet_Dictionary *ed, int type, const void *src, const void *src_end, void *dest); static void *eet_data_put_type(Eet_Dictionary *ed, int type, const void *src, int *size_ret); @@ -241,7 +243,8 @@ static const Eet_Data_Basic_Type_Codec eet_basic_codec[] = {sizeof(int), "uint", eet_data_get_int, eet_data_put_int }, {sizeof(long long), "ulong_long", eet_data_get_long_long, eet_data_put_long_long}, {sizeof(char *), "string", eet_data_get_string, eet_data_put_string }, - {sizeof(char *), "inlined", eet_data_get_istring, eet_data_put_istring } + {sizeof(char *), "inlined", eet_data_get_istring, eet_data_put_istring }, + {sizeof(void *), "NULL", eet_data_get_null, eet_data_put_null } }; static const Eet_Data_Group_Type_Codec eet_group_codec[] = @@ -485,6 +488,25 @@ eet_data_put_istring(Eet_Dictionary *ed __UNUSED__, const void *src, int *size_r return eet_data_put_string(NULL, src, size_ret); } +/* ALWAYS NULL TYPE */ +static int +eet_data_get_null(const Eet_Dictionary *ed __UNUSED__, const void *src __UNUSED__, const void *src_end __UNUSED__, void *dst) +{ + char **d; + + d = (char**) dst; + + *d = NULL; + return 0; +} + +static void * +eet_data_put_null(Eet_Dictionary *ed __UNUSED__, const void *src __UNUSED__, int *size_ret) +{ + *size_ret = 0; + return NULL; +} + /** * Fast lookups of simple doubles/floats. * @@ -689,16 +711,26 @@ eet_data_chunk_get(const Eet_Dictionary *ed, Eet_Data_Chunk *chnk, const char *s; int ret1, ret2; - if (!src) return; - if (size <= 8) return; + if (!src) { + fprintf(stderr, "stiouf -3\n"); + return; + } + if (size <= 8) { + fprintf(stderr, "stiouf -2 %i\n", size); + return; + } - if (!chnk) return; + if (!chnk) { + fprintf(stderr, "stiouf -1\n"); + return; + } s = src; if (s[2] == 'K') { if ((s[0] != 'C') || (s[1] != 'H') || (s[2] != 'K')) { + fprintf(stderr, "stiouf 0\n"); return; } chnk->type = (unsigned char)(s[3]); @@ -720,21 +752,25 @@ eet_data_chunk_get(const Eet_Dictionary *ed, Eet_Data_Chunk *chnk, { if ((s[0] != 'C') || (s[1] != 'H') || (s[2] != 'n') || (s[3] != 'K')) { + fprintf(stderr, "stiouf 1\n"); return; } } ret1 = eet_data_get_type(ed, EET_T_INT, (s + 4), (s + size), &(chnk->size)); if (ret1 <= 0) { + fprintf(stderr, "stiouf 2\n"); return; } if ((chnk->size < 0) || ((chnk->size + 8) > size)) { + fprintf(stderr, "stiouf 3\n"); return; } ret2 = eet_data_get_type(ed, EET_T_STRING, (s + 8), (s + size), &(chnk->name)); if (ret2 <= 0) { + fprintf(stderr, "stiouf 4\n"); return; } @@ -830,7 +866,7 @@ eet_data_chunk_put(Eet_Dictionary *ed, Eet_Data_Chunk *chnk, Eet_Data_Stream *ds int string_ret = 0; unsigned char buf[4] = "CHK"; - if (!chnk->data) return; + if (!chnk->data && chnk->type != EET_T_NULL) return; /* chunk head */ /* eet_data_stream_write(ds, "CHnK", 4);*/ @@ -1297,6 +1333,31 @@ _eet_freelist_free(Eet_Data_Descriptor *edd) _eet_free_reset(&freelist); } +static Eet_Free freeleak = { 0, { 0 }, { 0 }, { NULL } }; + +#define _eet_freeleak_add(Data) _eet_free_add(&freeleak, Data); +#define _eet_freeleak_reset() _eet_free_reset(&freeleak); +#define _eet_freeleak_ref() _eet_free_ref(&freeleak); +#define _eet_freeleak_unref() _eet_free_unref(&freeleak); + +static void +_eet_freeleak_free(Eet_Data_Descriptor *edd) +{ + int j; + int i; + + if (freeleak.ref > 0) return; + for (j = 0; j < 256; ++j) + for (i = 0; i < freeleak.num[j]; ++i) + { + if (edd) + edd->func.mem_free(freeleak.list[j][i]); + else + free(freeleak.list[j][i]); + } + _eet_free_reset(&freeleak); +} + static Eet_Free freelist_list = { 0, { 0 }, { 0 }, { NULL } }; #define _eet_freelist_list_add(Data) _eet_free_add(&freelist_list, Data); @@ -1604,6 +1665,7 @@ _eet_data_dump_free(Node *node) case EET_T_USHORT: case EET_T_UINT: case EET_T_ULONG_LONG: + case EET_T_NULL: break; case EET_T_INLINED_STRING: case EET_T_STRING: @@ -1732,6 +1794,8 @@ _eet_data_dump_encode(Eet_Dictionary *ed, eet_data_stream_free(ds); return cdata; + case EET_T_NULL: + break; case EET_T_CHAR: data = eet_data_put_type(ed, node->type, &(node->data.c), &size); if (data) @@ -2041,6 +2105,11 @@ _eet_data_dump_parse(Eet_Dictionary *ed, n->type = EET_T_INLINED_STRING; n->data.str = strdup(tok4); } + else if (!strcmp(tok3, "null")) + { + n->type = EET_T_NULL; + n->data.str = NULL; + } else { printf("ERROR: value type '%s' invalid.\n", tok4); @@ -2140,6 +2209,7 @@ _eet_data_descriptor_decode(const Eet_Dictionary *ed, } } _eet_freelist_ref(); + _eet_freeleak_ref(); _eet_freelist_str_ref(); _eet_freelist_list_ref(); if (data) _eet_freelist_add(data); @@ -2331,6 +2401,9 @@ _eet_data_descriptor_decode(const Eet_Dictionary *ed, } } break; + case EET_T_NULL: + dumpfunc(dumpdata, "null"); + break; default: dumpfunc(dumpdata, "???: ???"); break; break; @@ -2499,6 +2572,7 @@ _eet_data_descriptor_decode(const Eet_Dictionary *ed, } _eet_freelist_unref(); + _eet_freeleak_unref(); _eet_freelist_str_unref(); _eet_freelist_list_unref(); if (dumpfunc) @@ -2507,10 +2581,12 @@ _eet_data_descriptor_decode(const Eet_Dictionary *ed, _eet_freelist_direct_str_free(edd); _eet_freelist_list_free(edd); _eet_freelist_free(edd); + _eet_freeleak_reset(); } else { _eet_freelist_reset(); + _eet_freeleak_free(edd); _eet_freelist_str_reset(); _eet_freelist_list_reset(); _eet_freelist_direct_str_reset(); @@ -2531,12 +2607,14 @@ _eet_data_descriptor_decode(const Eet_Dictionary *ed, error: _eet_freelist_unref(); + _eet_freeleak_unref(); _eet_freelist_str_unref(); _eet_freelist_list_unref(); _eet_freelist_str_free(edd); _eet_freelist_direct_str_free(edd); _eet_freelist_list_free(edd); _eet_freelist_free(edd); + _eet_freeleak_reset(); if (dumpfunc) { if (dump) @@ -2667,12 +2745,14 @@ eet_data_get_array(const Eet_Dictionary *ed, Eet_Data_Descriptor *edd __UNUSED__ int level, void (*dumpfunc) (void *data, const char *str), void *dumpdata, char **p, int *size) { + const char *name; void *ptr; int count; int ret; + int subsize; int i; - EET_ASSERT(!IS_SIMPLE_TYPE(type), return 0); + EET_ASSERT(!((type > EET_T_UNKNOW) && (type < EET_T_STRING)), return 0); ptr = data; /* read the number of elements */ @@ -2682,13 +2762,21 @@ eet_data_get_array(const Eet_Dictionary *ed, Eet_Data_Descriptor *edd __UNUSED__ ((char *)echnk->data) + echnk->size, &count); if (ret <= 0) return ret; + + if (type >= EET_T_STRING) + subsize = eet_basic_codec[ede->type].size; + else + subsize = ede->subtype->size; + + name = echnk->name; + if (group_type == EET_G_VAR_ARRAY) { /* store the number of elements * on the counter offset */ *(int *)(((char *)data) + ede->count - ede->offset) = count; /* allocate space for the array of elements */ - *(void **)ptr = calloc(count, ede->subtype->size); + *(void **)ptr = calloc(count, subsize); if (!*(void **)ptr) return 0; @@ -2706,24 +2794,47 @@ eet_data_get_array(const Eet_Dictionary *ed, Eet_Data_Descriptor *edd __UNUSED__ memset(echnk, 0, sizeof(Eet_Data_Chunk)); eet_data_chunk_get(ed, echnk, *p, *size); - if (!echnk->name) return 0; + if (!echnk->name || strcmp(echnk->name, name) != 0) return 0; /* get the data */ /* get the destination pointer */ if (group_type == EET_G_ARRAY) - dst = (char *)ptr + (ede->subtype->size * i); + dst = (char *)ptr + (subsize * i); else - dst = *(char **)ptr + (ede->subtype->size * i); - data_ret = _eet_data_descriptor_decode(ed, - ede->subtype, - echnk->data, - echnk->size, - level + 2, - dumpfunc, - dumpdata); - if (!data_ret) return 0; - memcpy(dst, data_ret, ede->subtype->size); - free(data_ret); + dst = *(char **)ptr + (subsize * i); + + if (type >= EET_T_STRING) + { + int ret; + + ret = eet_data_get_unknown(ed, + edd, + ede, + echnk, + ede->type, + EET_G_UNKNOWN, + &data_ret, + level, + dumpfunc, + dumpdata, + p, + size); + if (!ret) return 0; + memcpy(dst, &data_ret, subsize); + } + else + { + data_ret = _eet_data_descriptor_decode(ed, + ede->subtype, + echnk->data, + echnk->size, + level + 2, + dumpfunc, + dumpdata); + if (!data_ret) return 0; + memcpy(dst, data_ret, subsize); + _eet_freeleak_add(data_ret); + } } return 1; } @@ -2795,19 +2906,20 @@ eet_data_encode(Eet_Dictionary *ed, Eet_Data_Stream *ds, void *data, const char echnk = eet_data_chunk_new(data, size, name, type, group_type); eet_data_chunk_put(ed, echnk, ds); eet_data_chunk_free(echnk); - free(data); + if (data) free(data); } static void eet_data_put_array(Eet_Dictionary *ed, Eet_Data_Descriptor *edd __UNUSED__, Eet_Data_Element *ede, Eet_Data_Stream *ds, void *data_in) { void *data; + int offset = 0; + int subsize; + int count; int size; int j; - int offset = 0; - int count; - EET_ASSERT(!IS_SIMPLE_TYPE(ede->type), return ); + EET_ASSERT(!((ede->type > EET_T_UNKNOW) && (ede->type < EET_T_STRING)), return ); if (ede->group_type == EET_G_ARRAY) count = ede->counter_offset; @@ -2819,18 +2931,36 @@ eet_data_put_array(Eet_Dictionary *ed, Eet_Data_Descriptor *edd __UNUSED__, Eet_ data = eet_data_put_type(ed, EET_T_INT, &count, &size); if (data) eet_data_encode(ed, ds, data, ede->name, size, ede->type, ede->group_type); + if (ede->type >= EET_T_STRING) + subsize = eet_basic_codec[ede->type].size; + else + subsize = ede->subtype->size; + for (j = 0; j < count; j++) { void *d; + int pos = ds->pos; if (ede->group_type == EET_G_ARRAY) d = (void *)(((char *)data_in) + offset); else d = *(((char **)data_in)) + offset; - data = _eet_data_descriptor_encode(ed, ede->subtype, d, &size); - offset += ede->subtype->size; - if (data) eet_data_encode(ed, ds, data, ede->name, size, ede->type, ede->group_type); + if (ede->type >= EET_T_STRING) + eet_data_put_unknown(ed, NULL, ede, ds, d); + else + { + data = _eet_data_descriptor_encode(ed, ede->subtype, d, &size); + if (data) eet_data_encode(ed, ds, data, ede->name, size, ede->type, ede->group_type); + } + + if (pos == ds->pos) + { + /* Add a NULL element just to have the correct array layout. */ + eet_data_encode(ed, ds, NULL, ede->name, 0, EET_T_NULL, ede->group_type); + } + + offset += subsize; } } diff --git a/legacy/eet/src/tests/eet_suite.c b/legacy/eet/src/tests/eet_suite.c index b8d3e32c5d..9a75103ff0 100644 --- a/legacy/eet/src/tests/eet_suite.c +++ b/legacy/eet/src/tests/eet_suite.c @@ -293,6 +293,7 @@ struct _Eet_Test_Ex_Type unsigned short us; unsigned int ui; unsigned long long ul; + char *charray[10]; }; static int i42 = 42; @@ -340,6 +341,9 @@ _eet_build_ex_descriptor(Eet_Data_Descriptor *edd) eet_data_descriptor_element_add(edd, "sarray2", EET_T_INT, EET_G_ARRAY, (char *)(&(etbt.sarray2)) - (char *)(&(etbt)), /* 0, */sizeof(etbt.sarray2)/sizeof(etbt.sarray2[0]), NULL, NULL); + eet_data_descriptor_element_add(edd, "charray", EET_T_STRING, EET_G_ARRAY, + (char *)(&(etbt.charray)) - (char *)(&(etbt)), + /* 0, */sizeof(etbt.charray)/sizeof(etbt.charray[0]), NULL, NULL); EET_DATA_DESCRIPTOR_ADD_LIST(edd, Eet_Test_Ex_Type, "list", list, edd); EET_DATA_DESCRIPTOR_ADD_HASH(edd, Eet_Test_Ex_Type, "hash", hash, edd); eet_data_descriptor_element_add(edd, "ilist", EET_T_INT, EET_G_LIST, @@ -384,6 +388,8 @@ _eet_test_ex_set(Eet_Test_Ex_Type *res, int offset) res->ihash = NULL; res->slist = NULL; res->shash = NULL; + for (i = 0; i < sizeof(res->charray)/sizeof(res->charray[0]); ++i) + res->charray[i] = NULL; res->varray2 = malloc(sizeof (Eet_Test_Basic_Type) * 10); res->varray1 = malloc(sizeof (int) * 5); @@ -503,6 +509,9 @@ START_TEST(eet_test_data_type_encoding_decoding) etbt.slist = eina_list_prepend(NULL, "test"); etbt.shash = eina_hash_string_superfast_new(NULL); eina_hash_add(etbt.shash, EET_TEST_KEY1, "test"); + memset(&etbt.charray, 0, sizeof(etbt.charray)); + etbt.charray[0] = "test"; + etbt.charray[5] = "plouf"; eet_test_setup_eddc(&eddc); eddc.name = "Eet_Test_Ex_Type"; @@ -527,6 +536,8 @@ START_TEST(eet_test_data_type_encoding_decoding) fail_if(strcmp(eina_list_data_get(result->slist), "test") != 0); fail_if(eina_hash_find(result->shash, EET_TEST_KEY1) == NULL); fail_if(strcmp(eina_hash_find(result->shash, EET_TEST_KEY1), "test") != 0); + fail_if(strcmp(result->charray[0], "test") != 0); + fail_if(strcmp(result->charray[5], "plouf") != 0); test = 0; eina_hash_foreach(result->hash, func, &test); @@ -584,6 +595,8 @@ START_TEST(eet_test_data_type_dump_undump) etbt.slist = eina_list_prepend(NULL, "test"); etbt.shash = eina_hash_string_superfast_new(NULL); eina_hash_add(etbt.shash, EET_TEST_KEY1, "test"); + memset(&etbt.charray, 0, sizeof(etbt.charray)); + etbt.charray[0] = "test"; eet_test_setup_eddc(&eddc); eddc.name = "Eet_Test_Ex_Type"; @@ -622,6 +635,7 @@ START_TEST(eet_test_data_type_dump_undump) fail_if(strcmp(eina_list_data_get(result->slist), "test") != 0); fail_if(eina_hash_find(result->shash, EET_TEST_KEY1) == NULL); fail_if(strcmp(eina_hash_find(result->shash, EET_TEST_KEY1), "test") != 0); + fail_if(strcmp(result->charray[0], "test") != 0); test = 0; eina_hash_foreach(result->hash, func, &test); @@ -723,6 +737,8 @@ START_TEST(eet_file_data_test) etbt.slist = eina_list_prepend(NULL, "test"); etbt.shash = eina_hash_string_superfast_new(NULL); eina_hash_add(etbt.shash, EET_TEST_KEY1, "test"); + memset(&etbt.charray, 0, sizeof(etbt.charray)); + etbt.charray[0] = "test"; eet_test_setup_eddc(&eddc); eddc.name = "Eet_Test_Ex_Type"; @@ -771,7 +787,7 @@ START_TEST(eet_file_data_test) ef = eet_open(file, EET_FILE_MODE_READ_WRITE); fail_if(!ef); - fail_if(!eet_data_write(ef, edd, EET_TEST_FILE_KEY2, &etbt, 1)); + fail_if(!eet_data_write(ef, edd, EET_TEST_FILE_KEY2, &etbt, 0)); result = eet_data_read(ef, edd, EET_TEST_FILE_KEY1); fail_if(!result); @@ -792,6 +808,7 @@ START_TEST(eet_file_data_test) fail_if(strcmp(eina_list_data_get(result->slist), "test") != 0); fail_if(eina_hash_find(result->shash, EET_TEST_KEY1) == NULL); fail_if(strcmp(eina_hash_find(result->shash, EET_TEST_KEY1), "test") != 0); + fail_if(strcmp(result->charray[0], "test") != 0); test = 0; eina_hash_foreach(result->hash, func, &test); @@ -860,6 +877,8 @@ START_TEST(eet_file_data_dump_test) etbt.slist = eina_list_prepend(NULL, "test"); etbt.hash = eina_hash_string_superfast_new(NULL); eina_hash_add(etbt.shash, EET_TEST_KEY1, "test"); + memset(&etbt.charray, 0, sizeof(etbt.charray)); + etbt.charray[0] = "test"; eet_test_setup_eddc(&eddc); eddc.name = "Eet_Test_Ex_Type"; @@ -876,7 +895,7 @@ START_TEST(eet_file_data_dump_test) ef = eet_open(file, EET_FILE_MODE_WRITE); fail_if(!ef); - fail_if(!eet_data_write(ef, edd, EET_TEST_FILE_KEY1, &etbt, 1)); + fail_if(!eet_data_write(ef, edd, EET_TEST_FILE_KEY1, &etbt, 0)); eet_close(ef); @@ -909,6 +928,7 @@ START_TEST(eet_file_data_dump_test) fail_if(strcmp(eina_list_data_get(result->slist), "test") != 0); fail_if(eina_hash_find(result->shash, EET_TEST_KEY1) == NULL); fail_if(strcmp(eina_hash_find(result->shash, EET_TEST_KEY1), "test") != 0); + fail_if(strcmp(result->charray[0], "test") != 0); test = 0; eina_hash_foreach(result->hash, func, &test);