]> git.ipfire.org Git - thirdparty/lldpd.git/blobdiff - src/marshal.c
debian: no need to BD on lsb-release anymore
[thirdparty/lldpd.git] / src / marshal.c
index 993d6543aabd2ed0dc07c674185482cda7082780..0cde547c401266289fdee6f0a56bf645fe6ca8c8 100644 (file)
 
 #include "lldpd-structs.h"
 
+/* Stolen from CCAN */
+#if HAVE_ALIGNOF
+# define ALIGNOF(t) (__alignof__(t))
+#else
+# define ALIGNOF(t) ((sizeof(t) > 1)?((char *)(&((struct { char c; t _h; } *)0)->_h) - (char *)0):1)
+#endif
+
 /* A serialized object */
 struct marshal_serialized {
        void         *orig;     /* Original reference. Also enforce alignment. */
@@ -56,11 +63,12 @@ struct marshal_info marshal_info_ignore = {
 struct ref {
        TAILQ_ENTRY(ref) next;
        void *pointer;
+       uintptr_t dummy;        /* To renumerate pointers */
 };
 TAILQ_HEAD(ref_l, ref);
 
 /* Serialize the given object. */
-size_t
+ssize_t
 marshal_serialize_(struct marshal_info *mi, void *unserialized, void **input,
     int skip, void *_refs, int osize)
 {
@@ -70,12 +78,15 @@ marshal_serialize_(struct marshal_info *mi, void *unserialized, void **input,
        size_t len;
        struct marshal_subinfo *current;
        struct marshal_serialized *new = NULL, *serialized = NULL;
+       uintptr_t dummy = 1;
+
+       log_debug("marshal", "start serialization of %s", mi->name);
 
        /* Check if we have already serialized this one. */
        if (!refs) {
                refs = calloc(1, sizeof(struct ref_l));
                if (!refs) {
-                       LLOG_WARNX("unable to allocate memory for list of references");
+                       log_warnx("marshal", "unable to allocate memory for list of references");
                        return -1;
                }
                TAILQ_INIT(refs);
@@ -83,11 +94,14 @@ 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. */
        size = mi->size;
        if (!strcmp(mi->name, "null string"))
+               /* We know we can't be called with NULL */
                size = strlen((char *)unserialized) + 1;
        else if (!strcmp(mi->name, "fixed string"))
                size = osize;
@@ -96,21 +110,23 @@ marshal_serialize_(struct marshal_info *mi, void *unserialized, void **input,
        len = sizeof(struct marshal_serialized) + (skip?0:size);
        serialized = calloc(1, len);
        if (!serialized) {
-               LLOG_WARNX("unable to allocate memory to serialize structure %s",
+               log_warnx("marshal", "unable to allocate memory to serialize structure %s",
                    mi->name);
                len = -1;
                goto marshal_error;
        }
-       serialized->orig = unserialized;
+       /* We don't use the original pointer but a dummy one. */
+       serialized->orig = (unsigned char*)dummy;
 
        /* Append the new reference */
        if (!(cref = calloc(1, sizeof(struct ref)))) {
-               LLOG_WARNX("unable to allocate memory for list of references");
+               log_warnx("marshal", "unable to allocate memory for list of references");
                free(serialized);
                len = -1;
                goto marshal_error;
        }
        cref->pointer = unserialized;
+       cref->dummy = dummy;
        TAILQ_INSERT_TAIL(refs, cref, next);
 
        /* First, serialize the main structure */
@@ -120,8 +136,9 @@ marshal_serialize_(struct marshal_info *mi, void *unserialized, void **input,
        /* Then, serialize inner structures */
        for (current = mi->pointers; current->mi; current++) {
                size_t sublen;
+               size_t padlen;
                void  *source;
-               void  *target;
+               void  *target = NULL;
                if (current->kind == ignore) continue;
                if (current->kind == pointer) {
                        memcpy(&source,
@@ -132,29 +149,44 @@ marshal_serialize_(struct marshal_info *mi, void *unserialized, void **input,
                        source = (void *)((unsigned char *)unserialized + current->offset);
                if (current->offset2)
                        memcpy(&osize, (unsigned char*)unserialized + current->offset2, sizeof(int));
+               target = NULL;
                sublen = marshal_serialize_(current->mi,
                    source, &target,
                    current->kind == substruct, refs, osize);
                if (sublen == -1) {
-                       LLOG_WARNX("unable to serialize substructure %s for %s",
+                       log_warnx("marshal", "unable to serialize substructure %s for %s",
                            current->mi->name, mi->name);
                        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*)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);
+               /* Append the result, force alignment to be able to unserialize it */
+               padlen = ALIGNOF(struct marshal_serialized);
+               padlen = (padlen - (len % padlen)) % padlen;
+               new = realloc(serialized, len + padlen + sublen);
                if (!new) {
-                       LLOG_WARNX("unable to allocate more memory to serialize structure %s",
+                       log_warnx("marshal", "unable to allocate more memory to serialize structure %s",
                            mi->name);
                        free(serialized);
                        free(target);
                        len = -1;
                        goto marshal_error;
                }
-               memcpy((unsigned char *)new + len, target, sublen);
+               memset((unsigned char *)new + len, 0, padlen);
+               memcpy((unsigned char *)new + len + padlen, target, sublen);
                free(target);
-               len += sublen;
+               len += sublen + padlen;
                serialized = (struct marshal_serialized *)new;
        }
 
@@ -229,8 +261,10 @@ marshal_unserialize_(struct marshal_info *mi, void *buffer, size_t len, void **o
        struct marshal_subinfo *current;
        struct gc *apointer;
 
+       log_debug("marshal", "start unserialization of %s", mi->name);
+
        if (len < sizeof(struct marshal_serialized) || len < total_len) {
-               LLOG_WARNX("data to deserialize is too small (%zu) for structure %s",
+               log_warnx("marshal", "data to deserialize is too small (%zu) for structure %s",
                    len, mi->name);
                return 0;
        }
@@ -239,7 +273,7 @@ marshal_unserialize_(struct marshal_info *mi, void *buffer, size_t len, void **o
        if (!pointers) {
                pointers = calloc(1, sizeof(struct gc_l));
                if (!pointers) {
-                       LLOG_WARNX("unable to allocate memory for garbage collection");
+                       log_warnx("marshal", "unable to allocate memory for garbage collection");
                        return 0;
                }
                TAILQ_INIT(pointers);
@@ -255,7 +289,7 @@ marshal_unserialize_(struct marshal_info *mi, void *buffer, size_t len, void **o
                                                           the string is null terminated. */
                }
                if (size > len - sizeof(struct marshal_serialized)) {
-                       LLOG_WARNX("data to deserialize contains a string too long");
+                       log_warnx("marshal", "data to deserialize contains a string too long");
                        total_len = 0;
                        goto unmarshal_error;
                }
@@ -265,7 +299,7 @@ marshal_unserialize_(struct marshal_info *mi, void *buffer, size_t len, void **o
        /* First, the main structure */
        if (!skip) {
                if ((*output = marshal_alloc(pointers, size + extra, serialized->orig)) == NULL) {
-                       LLOG_WARNX("unable to allocate memory to unserialize structure %s",
+                       log_warnx("marshal", "unable to allocate memory to unserialize structure %s",
                            mi->name);
                        total_len = 0;
                        goto unmarshal_error;
@@ -276,6 +310,7 @@ marshal_unserialize_(struct marshal_info *mi, void *buffer, size_t len, void **o
        /* Then, each substructure */
        for (current = mi->pointers; current->mi; current++) {
                size_t  sublen;
+               size_t  padlen;
                new = (unsigned char *)*output + current->offset;
                if (current->kind == ignore) {
                        memset((unsigned char *)*output + current->offset,
@@ -299,11 +334,13 @@ marshal_unserialize_(struct marshal_info *mi, void *buffer, size_t len, void **o
                /* Deserialize */
                if (current->offset2)
                        memcpy(&osize, (unsigned char *)*output + current->offset2, sizeof(int));
-               sublen = marshal_unserialize_(current->mi,
-                   (unsigned char *)buffer + total_len, len - total_len, &new, pointers,
-                   current->kind == substruct, osize);
-               if (sublen == 0) {
-                       LLOG_WARNX("unable to serialize substructure %s for %s",
+               padlen = ALIGNOF(struct marshal_serialized);
+               padlen = (padlen - (total_len % padlen)) % padlen;
+               if (len < total_len + padlen || ((sublen = marshal_unserialize_(current->mi,
+                               (unsigned char *)buffer + total_len + padlen,
+                               len - total_len - padlen, &new, pointers,
+                               current->kind == substruct, osize)) == 0)) {
+                       log_warnx("marshal", "unable to serialize substructure %s for %s",
                            current->mi->name, mi->name);
                        total_len = 0;
                        goto unmarshal_error;
@@ -312,7 +349,7 @@ marshal_unserialize_(struct marshal_info *mi, void *buffer, size_t len, void **o
                if (current->kind == pointer)
                        memcpy((unsigned char *)*output + current->offset,
                            &new, sizeof(void *));
-               total_len += sublen;
+               total_len += sublen + padlen;
        }
 
 unmarshal_error: