]> git.ipfire.org Git - thirdparty/lldpd.git/commitdiff
marshal: ensure that two identic structures are serialized in the same way
authorVincent Bernat <bernat@luffy.cx>
Sun, 30 Dec 2012 18:12:52 +0000 (19:12 +0100)
committerVincent Bernat <bernat@luffy.cx>
Sun, 30 Dec 2012 18:12:52 +0000 (19:12 +0100)
Because we serialized pointers unchanged and use them to track
substructures, two identic structures located at different places in
the memory were serialized as two different buffers. It is easy to use
"dummy" pointers instead of real ones and then be able to compare two
structures by serializing them and compare the resulting buffers.

However, those two structures should be calloced to make this
works. When allocating from the stack, use of designated initializers
don't mean anything about padded memory (no guarantee that it will be
set to 0).

src/marshal.c
tests/check_marshal.c

index 85087a5d9b884737b665b61b9cf3c34d2aa40e47..238be97057abac9d4f66d540520fe1c80e046b13 100644 (file)
@@ -57,6 +57,7 @@ struct marshal_info marshal_info_ignore = {
 struct ref {
        TAILQ_ENTRY(ref) next;
        void *pointer;
+       int dummy;              /* To renumerate pointers */
 };
 TAILQ_HEAD(ref_l, ref);
 
@@ -71,6 +72,7 @@ marshal_serialize_(struct marshal_info *mi, void *unserialized, void **input,
        size_t len;
        struct marshal_subinfo *current;
        struct marshal_serialized *new = NULL, *serialized = NULL;
+       int dummy = 1;
 
        log_debug("marshal", "start serialization of %s", mi->name);
 
@@ -86,6 +88,8 @@ marshal_serialize_(struct marshal_info *mi, void *unserialized, void **input,
        TAILQ_FOREACH(cref, refs, next) {
                if (unserialized == cref->pointer)
                        return 0;
+               /* dummy should be higher than any existing dummy */
+               if (cref->dummy >= dummy) dummy = cref->dummy + 1;
        }
 
        /* Handle special cases. */
@@ -104,7 +108,8 @@ marshal_serialize_(struct marshal_info *mi, void *unserialized, void **input,
                len = -1;
                goto marshal_error;
        }
-       serialized->orig = unserialized;
+       /* We don't use the original pointer but a dummy one. */
+       serialized->orig = (unsigned char*)NULL + dummy;
 
        /* Append the new reference */
        if (!(cref = calloc(1, sizeof(struct ref)))) {
@@ -114,6 +119,7 @@ marshal_serialize_(struct marshal_info *mi, void *unserialized, void **input,
                goto marshal_error;
        }
        cref->pointer = unserialized;
+       cref->dummy = dummy;
        TAILQ_INSERT_TAIL(refs, cref, next);
 
        /* First, serialize the main structure */
@@ -144,6 +150,17 @@ marshal_serialize_(struct marshal_info *mi, void *unserialized, void **input,
                        free(serialized);
                        return -1;
                }
+               /* We want to put the renumerated pointer instead of the real one. */
+               if (current->kind == pointer && !skip) {
+                       TAILQ_FOREACH(cref, refs, next) {
+                               if (source == cref->pointer) {
+                                       void *fakepointer = (unsigned char*)NULL + cref->dummy;
+                                       memcpy((unsigned char *)serialized->object + current->offset,
+                                           &fakepointer, sizeof(void *));
+                                       break;
+                               }
+                       }
+               }
                if (sublen == 0) continue; /* This was already serialized */
                /* Append the result */
                new = realloc(serialized, len + sublen);
index 3dd4f649bd88476a3b9f4e2ebe9c505f23baa4ce..5dd40fc9e248405a2162fc9e82169b635437a7fe 100644 (file)
@@ -730,6 +730,36 @@ START_TEST(test_ignore) {
 }
 END_TEST
 
+START_TEST(test_equality) {
+       struct struct_simple source_simple1 = {
+               .a1 = 451,
+               .a2 = 451424,
+               .a3 = 'o',
+               .a4 = 74,
+               .a5 = { 'a', 'b', 'c', 'd', 'e', 'f', 'g'},
+       };
+       struct struct_simpleentry entry1 = {
+               .g1 = 47,
+               .g2 = &source_simple1,
+       };
+
+       struct struct_simple source_simple2;
+       struct struct_simpleentry entry2;
+
+       void *buffer1, *buffer2;
+       memcpy(&source_simple2, &source_simple1, sizeof(source_simple1));
+       memcpy(&entry2, &entry1, sizeof(entry1));
+       entry2.g2 = &source_simple2;
+       ssize_t len1 = marshal_serialize(struct_simpleentry, &entry1, &buffer1);
+       ssize_t len2 = marshal_serialize(struct_simpleentry, &entry2, &buffer2);
+       fail_unless(len1 > 0, "Unable to serialize");
+       fail_unless(len2 > 0, "Unable to serialize");
+       ck_assert_int_eq(len1, len2);
+       fail_unless(!memcmp(buffer1, buffer2, len1), "Same content should give the same serialization");
+       free(buffer1); free(buffer2);
+}
+END_TEST
+
 Suite *
 marshal_suite(void)
 {
@@ -749,6 +779,7 @@ marshal_suite(void)
        tcase_add_test(tc_marshal, test_string);
        tcase_add_test(tc_marshal, test_fixed_string);
        tcase_add_test(tc_marshal, test_ignore);
+       tcase_add_test(tc_marshal, test_equality);
        suite_add_tcase(s, tc_marshal);
 
        return s;