Support optional tail in plist deserialisation

Signed-off-by: Erik Boasson <eb@ilities.com>
This commit is contained in:
Erik Boasson 2019-09-26 13:37:30 +02:00
parent bf8bc87a87
commit 2289428991
3 changed files with 146 additions and 8 deletions

View file

@ -13,6 +13,7 @@
#define DDSI_PLIST_GENERIC_H #define DDSI_PLIST_GENERIC_H
#include <stddef.h> #include <stddef.h>
#include <assert.h>
#include <stdbool.h> #include <stdbool.h>
#include "dds/export.h" #include "dds/export.h"
@ -39,9 +40,19 @@ enum pserop {
XbPROP, /* boolean: omit in serialized form; skip serialization if false; always true on deserialize */ XbPROP, /* boolean: omit in serialized form; skip serialization if false; always true on deserialize */
XG, /* GUID */ XG, /* GUID */
XK, /* keyhash */ XK, /* keyhash */
XQ /* arbitary non-nested sequence */ XQ, /* arbitary non-nested sequence */
Xopt, /* remainder is optional on deser, 0-init if not present */
} ddsrt_attribute_packed; } ddsrt_attribute_packed;
inline bool pserop_seralign_is_1 (enum pserop op) {
/* NB: XbPROP is never serialized, so its alignment is irrelevant. If ever there
is a need to allow calling this function when op = XbPROP, it needs to be changed
to taking the address of the pserop, and in that case inspect the following
operator */
assert (op != XbPROP && op != Xopt && op != XSTOP);
return (op >= Xo && op <= XK);
}
DDS_EXPORT void plist_fini_generic (void * __restrict dst, const enum pserop *desc, bool aliased); DDS_EXPORT void plist_fini_generic (void * __restrict dst, const enum pserop *desc, bool aliased);
DDS_EXPORT dds_return_t plist_deser_generic (void * __restrict dst, const void * __restrict src, size_t srcsize, bool bswap, const enum pserop * __restrict desc); DDS_EXPORT dds_return_t plist_deser_generic (void * __restrict dst, const void * __restrict src, size_t srcsize, bool bswap, const enum pserop * __restrict desc);
DDS_EXPORT dds_return_t plist_ser_generic (void **dst, size_t *dstsize, const void *src, const enum pserop * __restrict desc); DDS_EXPORT dds_return_t plist_ser_generic (void **dst, size_t *dstsize, const void *src, const enum pserop * __restrict desc);

View file

@ -98,10 +98,10 @@ struct piddesc {
size_t plist_offset; /* offset from start of nn_plist_t */ size_t plist_offset; /* offset from start of nn_plist_t */
size_t size; /* in-memory size for copying */ size_t size; /* in-memory size for copying */
union { union {
/* descriptor for generic code: 11 is enough for the current set of /* descriptor for generic code: 12 is enough for the current set of
parameters, compiler will warn if one ever tries to use more than parameters, compiler will warn if one ever tries to use more than
will fit; on non-GCC/Clang and 32-bits machines */ will fit */
const enum pserop desc[11]; const enum pserop desc[12];
struct { struct {
dds_return_t (*deser) (void * __restrict dst, size_t * __restrict dstoff, struct flagset *flagset, uint64_t flag, const struct dd * __restrict dd, size_t * __restrict srcoff); dds_return_t (*deser) (void * __restrict dst, size_t * __restrict dstoff, struct flagset *flagset, uint64_t flag, const struct dd * __restrict dd, size_t * __restrict srcoff);
dds_return_t (*ser) (struct nn_xmsg *xmsg, nn_parameterid_t pid, const void *src, size_t srcoff); dds_return_t (*ser) (struct nn_xmsg *xmsg, nn_parameterid_t pid, const void *src, size_t srcoff);
@ -114,6 +114,8 @@ struct piddesc {
dds_return_t (*deser_validate_xform) (void * __restrict dst, const struct dd * __restrict dd); dds_return_t (*deser_validate_xform) (void * __restrict dst, const struct dd * __restrict dd);
}; };
extern inline bool pserop_seralign_is_1 (enum pserop op);
static void log_octetseq (uint32_t cat, const struct ddsrt_log_cfg *logcfg, uint32_t n, const unsigned char *xs); static void log_octetseq (uint32_t cat, const struct ddsrt_log_cfg *logcfg, uint32_t n, const unsigned char *xs);
static dds_return_t validate_history_qospolicy (const dds_history_qospolicy_t *q); static dds_return_t validate_history_qospolicy (const dds_history_qospolicy_t *q);
static dds_return_t validate_resource_limits_qospolicy (const dds_resource_limits_qospolicy_t *q); static dds_return_t validate_resource_limits_qospolicy (const dds_resource_limits_qospolicy_t *q);
@ -336,6 +338,7 @@ static size_t ser_generic_srcsize (const enum pserop * __restrict desc)
case XK: SIMPLE (XK, nn_keyhash_t); break; case XK: SIMPLE (XK, nn_keyhash_t); break;
case XbPROP: SIMPLE (XbPROP, unsigned char); break; case XbPROP: SIMPLE (XbPROP, unsigned char); break;
case XQ: SIMPLE (XQ, ddsi_octetseq_t); while (*++desc != XSTOP) { } break; case XQ: SIMPLE (XQ, ddsi_octetseq_t); while (*++desc != XSTOP) { } break;
case Xopt: break;
} }
desc++; desc++;
} }
@ -388,6 +391,7 @@ static void fini_generic_embeddable (void * __restrict dst, size_t * __restrict
}, ddsrt_free (x->value)); }, ddsrt_free (x->value));
while (desc + 1 != desc_end && *++desc != XSTOP) { } while (desc + 1 != desc_end && *++desc != XSTOP) { }
break; break;
case Xopt: break;
} }
desc++; desc++;
} }
@ -395,6 +399,26 @@ static void fini_generic_embeddable (void * __restrict dst, size_t * __restrict
#undef COMPLEX #undef COMPLEX
} }
static size_t pserop_memalign (enum pserop op)
{
switch (op)
{
case XO: case XQ: return alignof (ddsi_octetseq_t);
case XS: return alignof (char *);
case XG: return alignof (ddsi_guid_t);
case XK: return alignof (nn_keyhash_t);
case Xb: case Xbx2: return 1;
case Xo: case Xox2: return 1;
case XbCOND: case XbPROP: return 1;
case XE1: case XE2: case XE3: return sizeof (uint32_t);
case Xi: case Xix2: case Xix3: case Xix4: return sizeof (int32_t);
case Xu: case Xux2: case Xux3: case Xux4: case Xux5: return sizeof (uint32_t);
case XD: case XDx2: return alignof (dds_duration_t);
case XSTOP: case Xopt: assert (0);
}
return 0;
}
static dds_return_t deser_generic (void * __restrict dst, size_t * __restrict dstoff, struct flagset *flagset, uint64_t flag, const struct dd * __restrict dd, size_t * __restrict srcoff, const enum pserop * __restrict desc) static dds_return_t deser_generic (void * __restrict dst, size_t * __restrict dstoff, struct flagset *flagset, uint64_t flag, const struct dd * __restrict dd, size_t * __restrict srcoff, const enum pserop * __restrict desc)
{ {
enum pserop const * const desc_in = desc; enum pserop const * const desc_in = desc;
@ -409,8 +433,7 @@ static dds_return_t deser_generic (void * __restrict dst, size_t * __restrict ds
switch (*desc) switch (*desc)
{ {
case XSTOP: case XSTOP:
*flagset->present |= flag; goto success;
return 0;
case XO: { /* octet sequence */ case XO: { /* octet sequence */
ddsi_octetseq_t * const x = deser_generic_dst (dst, dstoff, alignof (ddsi_octetseq_t)); ddsi_octetseq_t * const x = deser_generic_dst (dst, dstoff, alignof (ddsi_octetseq_t));
if (deser_uint32 (&x->length, dd, srcoff) < 0 || dd->bufsz - *srcoff < x->length) if (deser_uint32 (&x->length, dd, srcoff) < 0 || dd->bufsz - *srcoff < x->length)
@ -543,9 +566,29 @@ static dds_return_t deser_generic (void * __restrict dst, size_t * __restrict ds
while (*++desc != XSTOP) { } while (*++desc != XSTOP) { }
break; break;
} }
case Xopt: { /* remainder is optional; alignment is very nearly always 4 */
bool end_of_input;
if (pserop_seralign_is_1 (desc[1]))
end_of_input = (*srcoff + 1 > dd->bufsz);
else
{
*srcoff = (*srcoff + 3) & ~(size_t)3;
end_of_input = (*srcoff + 4 > dd->bufsz);
}
if (end_of_input)
{
void * const x = deser_generic_dst (dst, dstoff, pserop_memalign (desc[1]));
size_t rem_size = ser_generic_srcsize (desc + 1);
memset (x, 0, rem_size);
goto success;
}
}
} }
desc++; desc++;
} }
success:
*flagset->present |= flag;
return 0;
fail: fail:
fini_generic_embeddable (dst, &dstoff_in, desc_in, desc, *flagset->aliased & flag); fini_generic_embeddable (dst, &dstoff_in, desc_in, desc, *flagset->aliased & flag);
@ -604,6 +647,7 @@ static void ser_generic_size_embeddable (size_t *dstoff, const void *src, size_t
for (uint32_t i = 0; i < x->length; i++) for (uint32_t i = 0; i < x->length; i++)
ser_generic_size_embeddable (dstoff, x->value, i * elem_size, desc + 1); ser_generic_size_embeddable (dstoff, x->value, i * elem_size, desc + 1);
}); while (*++desc != XSTOP) { } break; }); while (*++desc != XSTOP) { } break;
case Xopt: break;
} }
desc++; desc++;
} }
@ -761,6 +805,8 @@ static dds_return_t ser_generic_embeddable (char * const data, size_t *dstoff, c
while (*++desc != XSTOP) { } while (*++desc != XSTOP) { }
break; break;
} }
case Xopt:
break;
} }
desc++; desc++;
} }
@ -832,6 +878,7 @@ static dds_return_t unalias_generic (void * __restrict dst, size_t * __restrict
unalias_generic (x->value, &elem_off, gen_seq_aliased, desc + 1); unalias_generic (x->value, &elem_off, gen_seq_aliased, desc + 1);
} }
}); while (*++desc != XSTOP) { } break; }); while (*++desc != XSTOP) { } break;
case Xopt: break;
} }
desc++; desc++;
} }
@ -917,6 +964,7 @@ static dds_return_t valid_generic (const void *src, size_t srcoff, const enum ps
} }
} }
}); while (*++desc != XSTOP) { } break; }); while (*++desc != XSTOP) { } break;
case Xopt: break;
} }
desc++; desc++;
} }
@ -978,6 +1026,7 @@ static bool equal_generic (const void *srcx, const void *srcy, size_t srcoff, co
} }
} }
}); while (*++desc != XSTOP) { } break; }); while (*++desc != XSTOP) { } break;
case Xopt: break;
} }
desc++; desc++;
} }
@ -1091,7 +1140,9 @@ static const struct piddesc piddesc_omg[] = {
QP (DEADLINE, deadline, XD), QP (DEADLINE, deadline, XD),
QP (LATENCY_BUDGET, latency_budget, XD), QP (LATENCY_BUDGET, latency_budget, XD),
QP (LIVELINESS, liveliness, XE2, XD), QP (LIVELINESS, liveliness, XE2, XD),
QP (PROPERTY_LIST, property, XQ, XbPROP, XS, XS, XSTOP, XQ, XbPROP, XS, XO, XSTOP), /* Property list used to be of type [(String,String]), security changed into ([String,String],Maybe [(String,[Word8])]),
the "Xopt" here is to allow both forms on input, with an assumed empty second sequence if the old form was received */
QP (PROPERTY_LIST, property, XQ, XbPROP, XS, XS, XSTOP, Xopt, XQ, XbPROP, XS, XO, XSTOP),
/* Reliability encoding does not follow the rules (best-effort/reliable map to 1/2 instead of 0/1 */ /* Reliability encoding does not follow the rules (best-effort/reliable map to 1/2 instead of 0/1 */
{ PID_RELIABILITY, PDF_QOS | PDF_FUNCTION, QP_RELIABILITY, "RELIABILITY", { PID_RELIABILITY, PDF_QOS | PDF_FUNCTION, QP_RELIABILITY, "RELIABILITY",
offsetof (struct nn_plist, qos.reliability), membersize (struct nn_plist, qos.reliability), offsetof (struct nn_plist, qos.reliability), membersize (struct nn_plist, qos.reliability),

View file

@ -17,7 +17,7 @@
#include "dds/ddsi/ddsi_plist_generic.h" #include "dds/ddsi/ddsi_plist_generic.h"
struct desc { struct desc {
const enum pserop desc[10]; const enum pserop desc[20];
const void *data; const void *data;
size_t exp_sersize; size_t exp_sersize;
const unsigned char *exp_ser; const unsigned char *exp_ser;
@ -104,6 +104,29 @@ struct desc descs[] = {
}, },
&(struct{char b; oseq seq;}){1, {3, (unsigned char *)(struct{char b;char *s;uint8_t o;}[]){ &(struct{char b; oseq seq;}){1, {3, (unsigned char *)(struct{char b;char *s;uint8_t o;}[]){
{1,"orange",2}, {1,"fig",4}, {1,"prune",5}}}}, {1,"orange",2}, {1,"fig",4}, {1,"prune",5}}}},
},
{ {Xb,XQ,XbPROP,XS,Xo,XSTOP, Xopt,XQ,XbPROP,XS,Xo,XSTOP, XSTOP},
&(struct{char b; oseq seq, seq2;}){1,
{5, (unsigned char *)(struct{char b;char *s;uint8_t o;}[]){
{0,"apple",1}, {1,"orange",2}, {0,"cherry",3}, {1,"fig",4}, {1,"prune",5}}},
{2, (unsigned char *)(struct{char b;char *s;uint8_t o;}[]){
{1,"oak",8}, {0,"beech",9}}}
},
57, (raw){1, 0,0,0,
SER32(3),
SER32(7), 'o','r','a','n','g','e',0, 2,
SER32(4), 'f','i','g',0, 4, 0,0,0,
SER32(6), 'p','r','u','n','e',0, 5,
0,
SER32(1),
SER32(4), 'o','a','k',0, 8
},
&(struct{char b; oseq seq, seq2;}){1,
{3, (unsigned char *)(struct{char b;char *s;uint8_t o;}[]){
{1,"orange",2}, {1,"fig",4}, {1,"prune",5}}},
{1, (unsigned char *)(struct{char b;char *s;uint8_t o;}[]){
{1,"oak",8}}}
}
} }
}; };
@ -236,3 +259,56 @@ CU_Test (ddsi_plist_generic, invalid_input)
CU_ASSERT_FATAL (ret != DDS_RETCODE_OK); CU_ASSERT_FATAL (ret != DDS_RETCODE_OK);
} }
} }
CU_Test (ddsi_plist_generic, optional)
{
union {
uint64_t u;
void *p;
char buf[256];
} mem;
enum pserop ser_desc[] = {Xb,XQ,XbPROP,XS,Xo,XSTOP,XSTOP};
enum pserop deser_desc[] = {Xb,XQ,XbPROP,XS,Xo,XSTOP, Xopt,XQ,XbPROP,XS,Xo,XSTOP, XSTOP};
const void *data = &(struct{char b; oseq seq;}){
1, {5, (unsigned char *)(struct{char b;char *s;uint8_t o;}[]){
{0,"apple",1}, {1,"orange",2}, {0,"cherry",3}, {1,"fig",4}, {1,"prune",5}}}};
size_t exp_sersize = 43;
const unsigned char *exp_ser = (raw){
1, 0,0,0, SER32(3),
SER32(7), 'o','r','a','n','g','e',0, 2,
SER32(4), 'f','i','g',0, 4, 0,0,0,
SER32(6), 'p','r','u','n','e',0, 5
};
const void *exp_data = &(struct{char b; oseq seq; oseq seq2;}){
1, {3, (unsigned char *)(struct{char b;char *s;uint8_t o;}[]){
{1,"orange",2}, {1,"fig",4}, {1,"prune",5}}},
{0, NULL}};
size_t memsize;
void *ser;
size_t sersize;
dds_return_t ret;
ret = plist_ser_generic (&ser, &sersize, data, ser_desc);
CU_ASSERT_FATAL (ret == DDS_RETCODE_OK);
CU_ASSERT (sersize == exp_sersize);
/* if sizes don't match, still check prefix */
size_t cmpsize = (sersize < exp_sersize) ? sersize : exp_sersize;
if (memcmp (ser, exp_ser, cmpsize) != 0)
{
printf ("ddsi_plist_generic_optional: memcmp\n");
for (size_t k = 0; k < cmpsize; k++)
printf (" %3zu %02x %02x\n", k, ((unsigned char *)ser)[k], exp_ser[k]);
CU_ASSERT (!(bool)"memcmp");
}
/* check */
memsize = plist_memsize_generic (deser_desc);
CU_ASSERT_FATAL (memsize <= sizeof (mem));
memset (&mem, 0xee, sizeof (mem));
ret = plist_deser_generic (&mem, ser, sersize, false, deser_desc);
CU_ASSERT_FATAL (ret == DDS_RETCODE_OK);
/* the compare function should be happy with it */
CU_ASSERT (plist_equal_generic (exp_data, &mem, deser_desc));
plist_fini_generic (&mem, deser_desc, true);
ddsrt_free (ser);
}