* Bug fix :
authorcedric <cedric@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Fri, 24 Oct 2008 14:06:40 +0000 (14:06 +0000)
committercedric <cedric@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Fri, 24 Oct 2008 14:06:40 +0000 (14:06 +0000)
  - 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.

git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/eet@37051 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

src/lib/Eet.h
src/lib/eet_data.c
src/tests/eet_suite.c

index 7fc9dbb..606c7fe 100644 (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 */
index 2d60ede..be83422 100644 (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 size;
-   int j;
    int offset = 0;
+   int subsize;
    int count;
+   int size;
+   int j;
 
-   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;
      }
 }
 
index b8d3e32..9a75103 100644 (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);