* 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
This commit is contained in:
Cedric BAIL 2008-10-24 14:06:40 +00:00
parent 7d0d0aaf7f
commit d0fe4b4f3f
3 changed files with 181 additions and 30 deletions

View File

@ -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 */

View File

@ -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;
}
}

View File

@ -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);