#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. */
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)
{
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);
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;
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 */
/* 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,
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;
}
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;
}
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);
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;
}
/* 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;
/* 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,
/* 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;
if (current->kind == pointer)
memcpy((unsigned char *)*output + current->offset,
&new, sizeof(void *));
- total_len += sublen;
+ total_len += sublen + padlen;
}
unmarshal_error: