From: Vincent Bernat Date: Sun, 30 Dec 2012 18:12:52 +0000 (+0100) Subject: marshal: ensure that two identic structures are serialized in the same way X-Git-Tag: 0.7.0~21 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=47862f89afec5218fc7841ef270ed7f30473c22b;p=thirdparty%2Flldpd.git marshal: ensure that two identic structures are serialized in the same way 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). --- diff --git a/src/marshal.c b/src/marshal.c index 85087a5d..238be970 100644 --- a/src/marshal.c +++ b/src/marshal.c @@ -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); diff --git a/tests/check_marshal.c b/tests/check_marshal.c index 3dd4f649..5dd40fc9 100644 --- a/tests/check_marshal.c +++ b/tests/check_marshal.c @@ -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;