Fixes for table-driven plist ser/deser
* GUID, keyhash compare (currently no reliance on this comparison, so not causing trouble in Cyclone for applications) * comparing "propagate" boolean in plist (newly added for security, not yet used) * fix memory leak in plist_unalias (currently only used in duplicating them, in which case the memory leak doesn't occur) * add unit tests for plist handling Signed-off-by: Erik Boasson <eb@ilities.com>
This commit is contained in:
parent
8f46889f74
commit
bf8bc87a87
6 changed files with 571 additions and 31 deletions
|
@ -70,6 +70,7 @@ PREPEND(hdrs_private_ddsi "${CMAKE_CURRENT_LIST_DIR}/include/dds/ddsi"
|
||||||
ddsi_raweth.h
|
ddsi_raweth.h
|
||||||
ddsi_ipaddr.h
|
ddsi_ipaddr.h
|
||||||
ddsi_mcgroup.h
|
ddsi_mcgroup.h
|
||||||
|
ddsi_plist_generic.h
|
||||||
ddsi_serdata.h
|
ddsi_serdata.h
|
||||||
ddsi_sertopic.h
|
ddsi_sertopic.h
|
||||||
ddsi_serdata_default.h
|
ddsi_serdata_default.h
|
||||||
|
@ -129,3 +130,8 @@ install(
|
||||||
DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/include/dds"
|
DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/include/dds"
|
||||||
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
|
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
|
||||||
COMPONENT dev)
|
COMPONENT dev)
|
||||||
|
|
||||||
|
# TODO: improve test inclusion.
|
||||||
|
if((BUILD_TESTING) AND ((NOT DEFINED MSVC_VERSION) OR (MSVC_VERSION GREATER "1800")))
|
||||||
|
add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/tests")
|
||||||
|
endif()
|
||||||
|
|
56
src/core/ddsi/include/dds/ddsi/ddsi_plist_generic.h
Normal file
56
src/core/ddsi/include/dds/ddsi/ddsi_plist_generic.h
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* Copyright(c) 2019 ADLINK Technology Limited and others
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Public License v. 2.0 which is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
|
||||||
|
* v. 1.0 which is available at
|
||||||
|
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
|
||||||
|
*/
|
||||||
|
#ifndef DDSI_PLIST_GENERIC_H
|
||||||
|
#define DDSI_PLIST_GENERIC_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "dds/export.h"
|
||||||
|
|
||||||
|
#include "dds/ddsrt/attributes.h"
|
||||||
|
|
||||||
|
#if defined (__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Instructions for the generic serializer (&c) that handles most parameters.
|
||||||
|
The "packed" attribute means single-byte instructions on GCC and Clang. */
|
||||||
|
enum pserop {
|
||||||
|
XSTOP,
|
||||||
|
XO, /* octet sequence */
|
||||||
|
XS, /* string */
|
||||||
|
XE1, XE2, XE3, /* enum 0..1, 0..2, 0..3 */
|
||||||
|
Xi, Xix2, Xix3, Xix4, /* int32_t, 1 .. 4 in a row */
|
||||||
|
Xu, Xux2, Xux3, Xux4, Xux5, /* uint32_t, 1 .. 5 in a row */
|
||||||
|
XD, XDx2, /* duration, 1 .. 2 in a row */
|
||||||
|
Xo, Xox2, /* octet, 1 .. 2 in a row */
|
||||||
|
Xb, Xbx2, /* boolean, 1 .. 2 in a row */
|
||||||
|
XbCOND, /* boolean: compare to ignore remainder if false (for use_... flags) */
|
||||||
|
XbPROP, /* boolean: omit in serialized form; skip serialization if false; always true on deserialize */
|
||||||
|
XG, /* GUID */
|
||||||
|
XK, /* keyhash */
|
||||||
|
XQ /* arbitary non-nested sequence */
|
||||||
|
} ddsrt_attribute_packed;
|
||||||
|
|
||||||
|
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_ser_generic (void **dst, size_t *dstsize, const void *src, const enum pserop * __restrict desc);
|
||||||
|
DDS_EXPORT dds_return_t plist_unalias_generic (void * __restrict dst, const enum pserop * __restrict desc);
|
||||||
|
DDS_EXPORT bool plist_equal_generic (const void *srcx, const void *srcy, const enum pserop * __restrict desc);
|
||||||
|
DDS_EXPORT size_t plist_memsize_generic (const enum pserop * __restrict desc);
|
||||||
|
|
||||||
|
#if defined (__cplusplus)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -38,6 +38,8 @@
|
||||||
#include "dds/ddsrt/avl.h"
|
#include "dds/ddsrt/avl.h"
|
||||||
#include "dds/ddsi/q_misc.h" /* for vendor_is_... */
|
#include "dds/ddsi/q_misc.h" /* for vendor_is_... */
|
||||||
|
|
||||||
|
#include "dds/ddsi/ddsi_plist_generic.h"
|
||||||
|
|
||||||
/* I am tempted to change LENGTH_UNLIMITED to 0 in the API (with -1
|
/* I am tempted to change LENGTH_UNLIMITED to 0 in the API (with -1
|
||||||
supported for backwards compatibility) ... on the wire however
|
supported for backwards compatibility) ... on the wire however
|
||||||
it must be -1 */
|
it must be -1 */
|
||||||
|
@ -88,25 +90,6 @@ struct flagset {
|
||||||
uint64_t wanted;
|
uint64_t wanted;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Instructions for the generic serializer (&c) that handles most parameters.
|
|
||||||
The "packed" attribute means single-byte instructions on GCC and Clang. */
|
|
||||||
enum pserop {
|
|
||||||
XSTOP,
|
|
||||||
XO, /* octet sequence */
|
|
||||||
XS, /* string */
|
|
||||||
XE1, XE2, XE3, /* enum 0..1, 0..2, 0..3 */
|
|
||||||
Xi, Xix2, Xix3, Xix4, /* int32_t, 1 .. 4 in a row */
|
|
||||||
Xu, Xux2, Xux3, Xux4, Xux5, /* uint32_t, 1 .. 5 in a row */
|
|
||||||
XD, XDx2, /* duration, 1 .. 2 in a row */
|
|
||||||
Xo, Xox2, /* octet, 1 .. 2 in a row */
|
|
||||||
Xb, Xbx2, /* boolean, 1 .. 2 in a row */
|
|
||||||
XbCOND, /* boolean: compare to ignore remainder if false (for use_... flags) */
|
|
||||||
XbPROP, /* boolean: omit in serialized form; skip serialization if false; always true on deserialize */
|
|
||||||
XG, /* GUID */
|
|
||||||
XK, /* keyhash */
|
|
||||||
XQ /* arbitary non-nested sequence */
|
|
||||||
} ddsrt_attribute_packed;
|
|
||||||
|
|
||||||
struct piddesc {
|
struct piddesc {
|
||||||
nn_parameterid_t pid; /* parameter id or PID_PAD if strictly local */
|
nn_parameterid_t pid; /* parameter id or PID_PAD if strictly local */
|
||||||
uint16_t flags; /* see PDF_xxx flags */
|
uint16_t flags; /* see PDF_xxx flags */
|
||||||
|
@ -359,6 +342,11 @@ static size_t ser_generic_srcsize (const enum pserop * __restrict desc)
|
||||||
#undef SIMPLE
|
#undef SIMPLE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t plist_memsize_generic (const enum pserop * __restrict desc)
|
||||||
|
{
|
||||||
|
return ser_generic_srcsize (desc);
|
||||||
|
}
|
||||||
|
|
||||||
static void fini_generic_embeddable (void * __restrict dst, size_t * __restrict dstoff, const enum pserop *desc, const enum pserop * const desc_end, bool aliased)
|
static void fini_generic_embeddable (void * __restrict dst, size_t * __restrict dstoff, const enum pserop *desc, const enum pserop * const desc_end, bool aliased)
|
||||||
{
|
{
|
||||||
#define COMPLEX(basecase_, type_, cleanup_unaliased_, cleanup_always_) do { \
|
#define COMPLEX(basecase_, type_, cleanup_unaliased_, cleanup_always_) do { \
|
||||||
|
@ -546,7 +534,10 @@ static dds_return_t deser_generic (void * __restrict dst, size_t * __restrict ds
|
||||||
{
|
{
|
||||||
size_t elem_off = i * elem_size;
|
size_t elem_off = i * elem_size;
|
||||||
if (deser_generic (x->value, &elem_off, flagset, flag, dd, srcoff, desc + 1) < 0)
|
if (deser_generic (x->value, &elem_off, flagset, flag, dd, srcoff, desc + 1) < 0)
|
||||||
|
{
|
||||||
|
ddsrt_free (x->value);
|
||||||
goto fail;
|
goto fail;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*dstoff += sizeof (*x);
|
*dstoff += sizeof (*x);
|
||||||
while (*++desc != XSTOP) { }
|
while (*++desc != XSTOP) { }
|
||||||
|
@ -563,6 +554,22 @@ fail:
|
||||||
return DDS_RETCODE_BAD_PARAMETER;
|
return DDS_RETCODE_BAD_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dds_return_t plist_deser_generic (void * __restrict dst, const void * __restrict src, size_t srcsize, bool bswap, const enum pserop * __restrict desc)
|
||||||
|
{
|
||||||
|
struct dd dd = {
|
||||||
|
.buf = src,
|
||||||
|
.bufsz = srcsize,
|
||||||
|
.bswap = bswap,
|
||||||
|
.protocol_version = {0,0},
|
||||||
|
.vendorid = NN_VENDORID_ECLIPSE,
|
||||||
|
.factory = NULL
|
||||||
|
};
|
||||||
|
uint64_t present = 0, aliased = 0;
|
||||||
|
struct flagset fs = { .present = &present, .aliased = &aliased, .wanted = 1 };
|
||||||
|
size_t dstoff = 0, srcoff = 0;
|
||||||
|
return deser_generic (dst, &dstoff, &fs, 1, &dd, &srcoff, desc);
|
||||||
|
}
|
||||||
|
|
||||||
static void ser_generic_size_embeddable (size_t *dstoff, const void *src, size_t srcoff, const enum pserop * __restrict desc)
|
static void ser_generic_size_embeddable (size_t *dstoff, const void *src, size_t srcoff, const enum pserop * __restrict desc)
|
||||||
{
|
{
|
||||||
#define COMPLEX(basecase_, type_, dstoff_update_) do { \
|
#define COMPLEX(basecase_, type_, dstoff_update_) do { \
|
||||||
|
@ -766,7 +773,20 @@ static dds_return_t ser_generic (struct nn_xmsg *xmsg, nn_parameterid_t pid, con
|
||||||
return ser_generic_embeddable (data, &dstoff, src, srcoff, desc);
|
return ser_generic_embeddable (data, &dstoff, src, srcoff, desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static dds_return_t unalias_generic (void * __restrict dst, size_t * __restrict dstoff, const enum pserop * __restrict desc)
|
dds_return_t plist_ser_generic (void **dst, size_t *dstsize, const void *src, const enum pserop * __restrict desc)
|
||||||
|
{
|
||||||
|
const size_t srcoff = 0;
|
||||||
|
size_t dstoff = 0;
|
||||||
|
dds_return_t ret;
|
||||||
|
*dstsize = ser_generic_size (src, srcoff, desc);
|
||||||
|
if ((*dst = ddsrt_malloc (*dstsize == 0 ? 1 : *dstsize)) == NULL)
|
||||||
|
return DDS_RETCODE_OUT_OF_RESOURCES;
|
||||||
|
ret = ser_generic_embeddable (*dst, &dstoff, src, srcoff, desc);
|
||||||
|
assert (dstoff == *dstsize);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static dds_return_t unalias_generic (void * __restrict dst, size_t * __restrict dstoff, bool gen_seq_aliased, const enum pserop * __restrict desc)
|
||||||
{
|
{
|
||||||
#define COMPLEX(basecase_, type_, ...) do { \
|
#define COMPLEX(basecase_, type_, ...) do { \
|
||||||
type_ *x = deser_generic_dst (dst, dstoff, alignof (type_)); \
|
type_ *x = deser_generic_dst (dst, dstoff, alignof (type_)); \
|
||||||
|
@ -795,10 +815,21 @@ static dds_return_t unalias_generic (void * __restrict dst, size_t * __restrict
|
||||||
case XK: SIMPLE (XK, nn_keyhash_t); break;
|
case XK: SIMPLE (XK, nn_keyhash_t); break;
|
||||||
case XQ: COMPLEX (XQ, ddsi_octetseq_t, if (x->length) {
|
case XQ: COMPLEX (XQ, ddsi_octetseq_t, if (x->length) {
|
||||||
const size_t elem_size = ser_generic_srcsize (desc + 1);
|
const size_t elem_size = ser_generic_srcsize (desc + 1);
|
||||||
x->value = ddsrt_memdup (x->value, x->length * elem_size);
|
if (gen_seq_aliased)
|
||||||
|
{
|
||||||
|
/* The memory for the elements of a generic sequence are owned by the plist, the only aliased bits
|
||||||
|
are the strings (XS) and octet sequences (XO) embedded in the elements. So in principle, an
|
||||||
|
unalias operation on a generic sequence should only operate on the elements of the sequence,
|
||||||
|
not on the sequence buffer itself.
|
||||||
|
|
||||||
|
However, the "mergein_missing" operation (and consequently the copy & dup operations) memcpy the
|
||||||
|
source, then pretend it is aliased. In this case, the sequence buffer is aliased, rather than
|
||||||
|
private, and hence a new copy needs to be allocated. */
|
||||||
|
x->value = ddsrt_memdup (x->value, x->length * elem_size);
|
||||||
|
}
|
||||||
for (uint32_t i = 0; i < x->length; i++) {
|
for (uint32_t i = 0; i < x->length; i++) {
|
||||||
size_t elem_off = i * elem_size;
|
size_t elem_off = i * elem_size;
|
||||||
unalias_generic (x->value, &elem_off, desc + 1);
|
unalias_generic (x->value, &elem_off, gen_seq_aliased, desc + 1);
|
||||||
}
|
}
|
||||||
}); while (*++desc != XSTOP) { } break;
|
}); while (*++desc != XSTOP) { } break;
|
||||||
}
|
}
|
||||||
|
@ -808,6 +839,12 @@ static dds_return_t unalias_generic (void * __restrict dst, size_t * __restrict
|
||||||
#undef COMPLEX
|
#undef COMPLEX
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dds_return_t plist_unalias_generic (void * __restrict dst, const enum pserop * __restrict desc)
|
||||||
|
{
|
||||||
|
size_t dstoff = 0;
|
||||||
|
return unalias_generic (dst, &dstoff, false, desc);
|
||||||
|
}
|
||||||
|
|
||||||
static bool unalias_generic_required (const enum pserop * __restrict desc)
|
static bool unalias_generic_required (const enum pserop * __restrict desc)
|
||||||
{
|
{
|
||||||
while (*desc != XSTOP)
|
while (*desc != XSTOP)
|
||||||
|
@ -835,6 +872,12 @@ static dds_return_t fini_generic (void * __restrict dst, size_t * __restrict dst
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void plist_fini_generic (void * __restrict dst, const enum pserop *desc, bool aliased)
|
||||||
|
{
|
||||||
|
size_t dstoff = 0;
|
||||||
|
fini_generic_embeddable (dst, &dstoff, desc, NULL, aliased);
|
||||||
|
}
|
||||||
|
|
||||||
static dds_return_t valid_generic (const void *src, size_t srcoff, const enum pserop * __restrict desc)
|
static dds_return_t valid_generic (const void *src, size_t srcoff, const enum pserop * __restrict desc)
|
||||||
{
|
{
|
||||||
#define COMPLEX(basecase_, type_, cond_stmts_) do { \
|
#define COMPLEX(basecase_, type_, cond_stmts_) do { \
|
||||||
|
@ -921,9 +964,9 @@ static bool equal_generic (const void *srcx, const void *srcy, size_t srcoff, co
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case XbPROP: TRIVIAL (Xb, unsigned char); break;
|
case XbPROP: TRIVIAL (XbPROP, unsigned char); break;
|
||||||
case XG: SIMPLE (XG, ddsi_guid_t, memcmp (x, y, sizeof (*x))); break;
|
case XG: SIMPLE (XG, ddsi_guid_t, memcmp (x, y, sizeof (*x)) == 0); break;
|
||||||
case XK: SIMPLE (XK, nn_keyhash_t, memcmp (x, y, sizeof (*x))); break;
|
case XK: SIMPLE (XK, nn_keyhash_t, memcmp (x, y, sizeof (*x)) == 0); break;
|
||||||
case XQ: COMPLEX (XQ, ddsi_octetseq_t, {
|
case XQ: COMPLEX (XQ, ddsi_octetseq_t, {
|
||||||
if (x->length != y->length)
|
if (x->length != y->length)
|
||||||
return false;
|
return false;
|
||||||
|
@ -943,6 +986,11 @@ static bool equal_generic (const void *srcx, const void *srcy, size_t srcoff, co
|
||||||
#undef COMPLEX
|
#undef COMPLEX
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool plist_equal_generic (const void *srcx, const void *srcy, const enum pserop * __restrict desc)
|
||||||
|
{
|
||||||
|
return equal_generic (srcx, srcy, 0, desc);
|
||||||
|
}
|
||||||
|
|
||||||
#define membersize(type, member) sizeof (((type *) 0)->member)
|
#define membersize(type, member) sizeof (((type *) 0)->member)
|
||||||
#define ENTRY(PFX_, NAME_, member_, flag_, validate_, ...) \
|
#define ENTRY(PFX_, NAME_, member_, flag_, validate_, ...) \
|
||||||
{ PID_##NAME_, flag_, PFX_##_##NAME_, #NAME_, offsetof (struct nn_plist, member_), \
|
{ PID_##NAME_, flag_, PFX_##_##NAME_, #NAME_, offsetof (struct nn_plist, member_), \
|
||||||
|
@ -1409,7 +1457,7 @@ static void plist_or_xqos_unalias (void * __restrict dst, size_t shift)
|
||||||
if ((*fs->present & entry->present_flag) && (*fs->aliased & entry->present_flag))
|
if ((*fs->present & entry->present_flag) && (*fs->aliased & entry->present_flag))
|
||||||
{
|
{
|
||||||
if (!(entry->flags & PDF_FUNCTION))
|
if (!(entry->flags & PDF_FUNCTION))
|
||||||
unalias_generic (dst, &dstoff, entry->op.desc);
|
unalias_generic (dst, &dstoff, false, entry->op.desc);
|
||||||
else if (entry->op.f.unalias)
|
else if (entry->op.f.unalias)
|
||||||
entry->op.f.unalias (dst, &dstoff);
|
entry->op.f.unalias (dst, &dstoff);
|
||||||
*fs->aliased &= ~entry->present_flag;
|
*fs->aliased &= ~entry->present_flag;
|
||||||
|
@ -1467,15 +1515,15 @@ static void plist_or_xqos_mergein_missing (void * __restrict dst, const void * _
|
||||||
if (!(*fs_dst->present & entry->present_flag) && (*fs_src->present & mask & entry->present_flag))
|
if (!(*fs_dst->present & entry->present_flag) && (*fs_src->present & mask & entry->present_flag))
|
||||||
{
|
{
|
||||||
/* bitwise copy, mark as aliased & unalias; have to unalias fields one-by-one rather than
|
/* bitwise copy, mark as aliased & unalias; have to unalias fields one-by-one rather than
|
||||||
do this for all fields and call "unalias" on the entire object because fields that are
|
do this for all fields and call "unalias" on the entire object because fields that are
|
||||||
already present may be aliased, and it would be somewhat impolite to change that.
|
already present may be aliased, and it would be somewhat impolite to change that.
|
||||||
|
|
||||||
Note: dst & src have the same type, so offset in src is the same;
|
Note: dst & src have the same type, so offset in src is the same;
|
||||||
Note: unalias may have to look at */
|
Note: unalias may have to look at */
|
||||||
memcpy ((char *) dst + dstoff, (const char *) src + dstoff, entry->size);
|
memcpy ((char *) dst + dstoff, (const char *) src + dstoff, entry->size);
|
||||||
*fs_dst->present |= entry->present_flag;
|
*fs_dst->present |= entry->present_flag;
|
||||||
if (!(entry->flags & PDF_FUNCTION))
|
if (!(entry->flags & PDF_FUNCTION))
|
||||||
unalias_generic (dst, &dstoff, entry->op.desc);
|
unalias_generic (dst, &dstoff, true, entry->op.desc);
|
||||||
else if (entry->op.f.unalias)
|
else if (entry->op.f.unalias)
|
||||||
entry->op.f.unalias (dst, &dstoff);
|
entry->op.f.unalias (dst, &dstoff);
|
||||||
}
|
}
|
||||||
|
|
22
src/core/ddsi/tests/CMakeLists.txt
Normal file
22
src/core/ddsi/tests/CMakeLists.txt
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#
|
||||||
|
# Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
|
||||||
|
#
|
||||||
|
# This program and the accompanying materials are made available under the
|
||||||
|
# terms of the Eclipse Public License v. 2.0 which is available at
|
||||||
|
# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
|
||||||
|
# v. 1.0 which is available at
|
||||||
|
# http://www.eclipse.org/org/documents/edl-v10.php.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
|
||||||
|
#
|
||||||
|
include(CUnit)
|
||||||
|
|
||||||
|
set(ddsi_test_sources
|
||||||
|
"plist_generic.c"
|
||||||
|
"plist.c")
|
||||||
|
|
||||||
|
add_cunit_executable(cunit_ddsi ${ddsi_test_sources})
|
||||||
|
target_include_directories(
|
||||||
|
cunit_ddsi PRIVATE
|
||||||
|
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../../ddsi/include/>")
|
||||||
|
target_link_libraries(cunit_ddsi PRIVATE ddsc)
|
170
src/core/ddsi/tests/plist.c
Normal file
170
src/core/ddsi/tests/plist.c
Normal file
|
@ -0,0 +1,170 @@
|
||||||
|
/*
|
||||||
|
* Copyright(c) 2019 ADLINK Technology Limited and others
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Public License v. 2.0 which is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
|
||||||
|
* v. 1.0 which is available at
|
||||||
|
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CUnit/Theory.h"
|
||||||
|
#include "dds/ddsrt/heap.h"
|
||||||
|
#include "dds/ddsrt/string.h"
|
||||||
|
#include "dds/ddsrt/endian.h"
|
||||||
|
#include "dds/ddsi/q_xqos.h"
|
||||||
|
#include "dds/ddsi/q_plist.h"
|
||||||
|
|
||||||
|
CU_Test (ddsi_plist, unalias_copy_merge)
|
||||||
|
{
|
||||||
|
/* one int, one string and one string sequence covers most cases */
|
||||||
|
nn_plist_t p0, p0memcpy;
|
||||||
|
char *p0strs[3];
|
||||||
|
nn_plist_init_empty (&p0);
|
||||||
|
p0.present = PP_PRISMTECH_PROCESS_ID | PP_ENTITY_NAME;
|
||||||
|
p0.aliased = PP_ENTITY_NAME;
|
||||||
|
p0.process_id = 0x12345678;
|
||||||
|
p0.entity_name = "nemo";
|
||||||
|
p0.qos.present = QP_PARTITION;
|
||||||
|
p0.qos.aliased = QP_PARTITION;
|
||||||
|
p0.qos.partition.n = 3;
|
||||||
|
p0.qos.partition.strs = ddsrt_malloc (p0.qos.partition.n * sizeof (*p0.qos.partition.strs));
|
||||||
|
p0strs[0] = p0.qos.partition.strs[0] = "aap";
|
||||||
|
p0strs[1] = p0.qos.partition.strs[1] = "noot";
|
||||||
|
p0strs[2] = p0.qos.partition.strs[2] = "mies";
|
||||||
|
memcpy (&p0memcpy, &p0, sizeof (p0));
|
||||||
|
|
||||||
|
/* manually alias one, so we can free it*/
|
||||||
|
nn_plist_t p0alias;
|
||||||
|
memcpy (&p0alias, &p0, sizeof (p0));
|
||||||
|
p0alias.qos.partition.strs = ddsrt_memdup (p0alias.qos.partition.strs, p0.qos.partition.n * sizeof (*p0.qos.partition.strs));
|
||||||
|
nn_plist_fini (&p0alias);
|
||||||
|
CU_ASSERT (memcmp (&p0, &p0memcpy, sizeof (p0)) == 0);
|
||||||
|
CU_ASSERT_STRING_EQUAL (p0.entity_name, "nemo");
|
||||||
|
CU_ASSERT_STRING_EQUAL (p0.qos.partition.strs[0], p0strs[0]);
|
||||||
|
CU_ASSERT_STRING_EQUAL (p0.qos.partition.strs[1], p0strs[1]);
|
||||||
|
CU_ASSERT_STRING_EQUAL (p0.qos.partition.strs[2], p0strs[2]);
|
||||||
|
|
||||||
|
/* copy an aliased one; the original must be unchanged, the copy unaliased */
|
||||||
|
nn_plist_t p1;
|
||||||
|
nn_plist_init_empty (&p1);
|
||||||
|
nn_plist_copy (&p1, &p0);
|
||||||
|
CU_ASSERT (memcmp (&p0, &p0memcpy, sizeof (p0)) == 0);
|
||||||
|
CU_ASSERT (p1.present == p0.present);
|
||||||
|
CU_ASSERT (p1.aliased == 0);
|
||||||
|
CU_ASSERT (p1.qos.present == p0.qos.present);
|
||||||
|
CU_ASSERT (p1.qos.aliased == 0);
|
||||||
|
CU_ASSERT (p1.process_id == p0.process_id);
|
||||||
|
CU_ASSERT (p1.entity_name != p0.entity_name);
|
||||||
|
CU_ASSERT_STRING_EQUAL (p1.entity_name, p0.entity_name);
|
||||||
|
CU_ASSERT (p1.qos.partition.n == p0.qos.partition.n);
|
||||||
|
CU_ASSERT (p1.qos.partition.strs != p0.qos.partition.strs);
|
||||||
|
CU_ASSERT (p1.qos.partition.strs[0] != p0.qos.partition.strs[0]);
|
||||||
|
CU_ASSERT (p1.qos.partition.strs[1] != p0.qos.partition.strs[1]);
|
||||||
|
CU_ASSERT (p1.qos.partition.strs[2] != p0.qos.partition.strs[2]);
|
||||||
|
CU_ASSERT_STRING_EQUAL (p1.qos.partition.strs[0], p0.qos.partition.strs[0]);
|
||||||
|
CU_ASSERT_STRING_EQUAL (p1.qos.partition.strs[1], p0.qos.partition.strs[1]);
|
||||||
|
CU_ASSERT_STRING_EQUAL (p1.qos.partition.strs[2], p0.qos.partition.strs[2]);
|
||||||
|
|
||||||
|
/* merge-in missing ones from an aliased copy: original must remain unchanged;
|
||||||
|
existing ones should stay without touching "aliased" only new ones are
|
||||||
|
added as unaliased ones */
|
||||||
|
nn_plist_t p2, p2memcpy;
|
||||||
|
nn_plist_init_empty (&p2);
|
||||||
|
p2.present = PP_ENTITY_NAME;
|
||||||
|
p2.aliased = PP_ENTITY_NAME;
|
||||||
|
p2.entity_name = "omen";
|
||||||
|
memcpy (&p2memcpy, &p2, sizeof (p2));
|
||||||
|
nn_plist_mergein_missing (&p2, &p0, p0.present, p0.qos.present);
|
||||||
|
CU_ASSERT (memcmp (&p0, &p0memcpy, sizeof (p0)) == 0);
|
||||||
|
CU_ASSERT (p2.present == p0.present);
|
||||||
|
CU_ASSERT (p2.aliased == p2memcpy.aliased);
|
||||||
|
CU_ASSERT (p2.qos.present == p0.qos.present);
|
||||||
|
CU_ASSERT (p2.qos.aliased == p2memcpy.qos.aliased);
|
||||||
|
CU_ASSERT (p2.process_id == p0.process_id);
|
||||||
|
CU_ASSERT (p2.entity_name == p2memcpy.entity_name);
|
||||||
|
CU_ASSERT_STRING_EQUAL (p2.entity_name, "omen");
|
||||||
|
CU_ASSERT (p2.qos.partition.n == p0.qos.partition.n);
|
||||||
|
CU_ASSERT (p2.qos.partition.strs != p0.qos.partition.strs);
|
||||||
|
CU_ASSERT (p2.qos.partition.strs[0] != p0.qos.partition.strs[0]);
|
||||||
|
CU_ASSERT (p2.qos.partition.strs[1] != p0.qos.partition.strs[1]);
|
||||||
|
CU_ASSERT (p2.qos.partition.strs[2] != p0.qos.partition.strs[2]);
|
||||||
|
CU_ASSERT_STRING_EQUAL (p2.qos.partition.strs[0], p0.qos.partition.strs[0]);
|
||||||
|
CU_ASSERT_STRING_EQUAL (p2.qos.partition.strs[1], p0.qos.partition.strs[1]);
|
||||||
|
CU_ASSERT_STRING_EQUAL (p2.qos.partition.strs[2], p0.qos.partition.strs[2]);
|
||||||
|
|
||||||
|
/* unalias of p0, partition.strs mustn't change, because it, unlike its elements, wasn't aliased */
|
||||||
|
nn_plist_unalias (&p0);
|
||||||
|
CU_ASSERT (p0.present == p0memcpy.present);
|
||||||
|
CU_ASSERT (p0.aliased == 0);
|
||||||
|
CU_ASSERT (p0.qos.present == p0memcpy.qos.present);
|
||||||
|
CU_ASSERT (p0.qos.aliased == 0);
|
||||||
|
CU_ASSERT (p0.process_id == p0memcpy.process_id);
|
||||||
|
CU_ASSERT (p0.entity_name != p0memcpy.entity_name);
|
||||||
|
CU_ASSERT_STRING_EQUAL (p0.entity_name, p0memcpy.entity_name);
|
||||||
|
CU_ASSERT (p0.qos.partition.n == p0memcpy.qos.partition.n);
|
||||||
|
CU_ASSERT (p0.qos.partition.strs == p0memcpy.qos.partition.strs);
|
||||||
|
CU_ASSERT (p0.qos.partition.strs[0] != p0strs[0]);
|
||||||
|
CU_ASSERT (p0.qos.partition.strs[1] != p0strs[1]);
|
||||||
|
CU_ASSERT (p0.qos.partition.strs[2] != p0strs[2]);
|
||||||
|
CU_ASSERT_STRING_EQUAL (p0.qos.partition.strs[0], p0strs[0]);
|
||||||
|
CU_ASSERT_STRING_EQUAL (p0.qos.partition.strs[1], p0strs[1]);
|
||||||
|
CU_ASSERT_STRING_EQUAL (p0.qos.partition.strs[2], p0strs[2]);
|
||||||
|
memcpy (&p0memcpy, &p0, sizeof (p0));
|
||||||
|
|
||||||
|
/* copy an aliased one; the original must be unchanged, the copy unaliased */
|
||||||
|
nn_plist_t p3;
|
||||||
|
nn_plist_init_empty (&p3);
|
||||||
|
nn_plist_copy (&p3, &p0);
|
||||||
|
CU_ASSERT (memcmp (&p0, &p0memcpy, sizeof (p0)) == 0);
|
||||||
|
CU_ASSERT (p3.present == p0.present);
|
||||||
|
CU_ASSERT (p3.aliased == 0);
|
||||||
|
CU_ASSERT (p3.qos.present == p0.qos.present);
|
||||||
|
CU_ASSERT (p3.qos.aliased == 0);
|
||||||
|
CU_ASSERT (p3.process_id == p0.process_id);
|
||||||
|
CU_ASSERT (p3.entity_name != p0.entity_name);
|
||||||
|
CU_ASSERT_STRING_EQUAL (p3.entity_name, p0.entity_name);
|
||||||
|
CU_ASSERT (p3.qos.partition.n == p0.qos.partition.n);
|
||||||
|
CU_ASSERT (p3.qos.partition.strs != p0.qos.partition.strs);
|
||||||
|
CU_ASSERT (p3.qos.partition.strs[0] != p0.qos.partition.strs[0]);
|
||||||
|
CU_ASSERT (p3.qos.partition.strs[1] != p0.qos.partition.strs[1]);
|
||||||
|
CU_ASSERT (p3.qos.partition.strs[2] != p0.qos.partition.strs[2]);
|
||||||
|
CU_ASSERT_STRING_EQUAL (p3.qos.partition.strs[0], p0.qos.partition.strs[0]);
|
||||||
|
CU_ASSERT_STRING_EQUAL (p3.qos.partition.strs[1], p0.qos.partition.strs[1]);
|
||||||
|
CU_ASSERT_STRING_EQUAL (p3.qos.partition.strs[2], p0.qos.partition.strs[2]);
|
||||||
|
|
||||||
|
/* merge-in missing ones from an aliased copy: original must remain unchanged;
|
||||||
|
existing ones should stay without touching "aliased" only new ones are
|
||||||
|
added as unaliased ones */
|
||||||
|
nn_plist_t p4, p4memcpy;
|
||||||
|
nn_plist_init_empty (&p4);
|
||||||
|
p4.present = PP_ENTITY_NAME;
|
||||||
|
p4.aliased = PP_ENTITY_NAME;
|
||||||
|
p4.entity_name = "omen";
|
||||||
|
memcpy (&p4memcpy, &p4, sizeof (p4));
|
||||||
|
nn_plist_mergein_missing (&p4, &p0, p0.present, p0.qos.present);
|
||||||
|
CU_ASSERT (memcmp (&p0, &p0memcpy, sizeof (p0)) == 0);
|
||||||
|
CU_ASSERT (p4.present == p0.present);
|
||||||
|
CU_ASSERT (p4.aliased == p4memcpy.aliased);
|
||||||
|
CU_ASSERT (p4.qos.present == p0.qos.present);
|
||||||
|
CU_ASSERT (p4.qos.aliased == p4memcpy.qos.aliased);
|
||||||
|
CU_ASSERT (p4.process_id == p0.process_id);
|
||||||
|
CU_ASSERT (p4.entity_name == p4memcpy.entity_name);
|
||||||
|
CU_ASSERT_STRING_EQUAL (p4.entity_name, "omen");
|
||||||
|
CU_ASSERT (p4.qos.partition.n == p0.qos.partition.n);
|
||||||
|
CU_ASSERT (p4.qos.partition.strs != p0.qos.partition.strs);
|
||||||
|
CU_ASSERT (p4.qos.partition.strs[0] != p0.qos.partition.strs[0]);
|
||||||
|
CU_ASSERT (p4.qos.partition.strs[1] != p0.qos.partition.strs[1]);
|
||||||
|
CU_ASSERT (p4.qos.partition.strs[2] != p0.qos.partition.strs[2]);
|
||||||
|
CU_ASSERT_STRING_EQUAL (p4.qos.partition.strs[0], p0.qos.partition.strs[0]);
|
||||||
|
CU_ASSERT_STRING_EQUAL (p4.qos.partition.strs[1], p0.qos.partition.strs[1]);
|
||||||
|
CU_ASSERT_STRING_EQUAL (p4.qos.partition.strs[2], p0.qos.partition.strs[2]);
|
||||||
|
|
||||||
|
nn_plist_fini (&p0);
|
||||||
|
nn_plist_fini (&p1);
|
||||||
|
nn_plist_fini (&p2);
|
||||||
|
nn_plist_fini (&p3);
|
||||||
|
nn_plist_fini (&p4);
|
||||||
|
}
|
238
src/core/ddsi/tests/plist_generic.c
Normal file
238
src/core/ddsi/tests/plist_generic.c
Normal file
|
@ -0,0 +1,238 @@
|
||||||
|
/*
|
||||||
|
* Copyright(c) 2019 ADLINK Technology Limited and others
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Public License v. 2.0 which is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
|
||||||
|
* v. 1.0 which is available at
|
||||||
|
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CUnit/Theory.h"
|
||||||
|
#include "dds/ddsrt/heap.h"
|
||||||
|
#include "dds/ddsrt/endian.h"
|
||||||
|
#include "dds/ddsi/q_xqos.h"
|
||||||
|
#include "dds/ddsi/ddsi_plist_generic.h"
|
||||||
|
|
||||||
|
struct desc {
|
||||||
|
const enum pserop desc[10];
|
||||||
|
const void *data;
|
||||||
|
size_t exp_sersize;
|
||||||
|
const unsigned char *exp_ser;
|
||||||
|
|
||||||
|
/* XbPROP means expectation after deser may be different from input, if exp_data
|
||||||
|
is NULL, use "data", else use "exp_data" */
|
||||||
|
const void *exp_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct desc_invalid {
|
||||||
|
const enum pserop desc[20];
|
||||||
|
size_t sersize;
|
||||||
|
const unsigned char *ser;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if DDSRT_ENDIAN == DDSRT_BIG_ENDIAN
|
||||||
|
#define SER32(v) \
|
||||||
|
(unsigned char)((uint32_t)(v) >> 24), \
|
||||||
|
(unsigned char)(((uint32_t)(v) >> 16) & 0xff), \
|
||||||
|
(unsigned char)(((uint32_t)(v) >> 8) & 0xff), \
|
||||||
|
(unsigned char)((uint32_t)(v) & 0xff)
|
||||||
|
#define SER32BE(v) SER32(v)
|
||||||
|
#else
|
||||||
|
#define SER32(v) \
|
||||||
|
(unsigned char)((uint32_t)(v) & 0xff), \
|
||||||
|
(unsigned char)(((uint32_t)(v) >> 8) & 0xff), \
|
||||||
|
(unsigned char)(((uint32_t)(v) >> 16) & 0xff), \
|
||||||
|
(unsigned char)((uint32_t)(v) >> 24)
|
||||||
|
#define SER32BE(v) \
|
||||||
|
(unsigned char)((uint32_t)(v) >> 24), \
|
||||||
|
(unsigned char)(((uint32_t)(v) >> 16) & 0xff), \
|
||||||
|
(unsigned char)(((uint32_t)(v) >> 8) & 0xff), \
|
||||||
|
(unsigned char)((uint32_t)(v) & 0xff)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef unsigned char raw[];
|
||||||
|
typedef uint32_t raw32[];
|
||||||
|
typedef ddsi_octetseq_t oseq;
|
||||||
|
|
||||||
|
struct desc descs[] = {
|
||||||
|
{ {XSTOP}, (raw){0}, 0, (raw){0} },
|
||||||
|
{ {XO,XSTOP}, &(oseq){0, NULL }, 4, (raw){SER32(0)} },
|
||||||
|
{ {XO,XSTOP}, &(oseq){1, (raw){3} }, 5, (raw){SER32(1), 3} },
|
||||||
|
{ {XS,XSTOP}, &(char *[]){""}, 5, (raw){SER32(1), 0} },
|
||||||
|
{ {XS,XSTOP}, &(char *[]){"meow"}, 9, (raw){SER32(5), 'm','e','o','w',0} },
|
||||||
|
{ {XE1,XSTOP}, (raw32){1}, 4, (raw){SER32(1)} },
|
||||||
|
{ {XE2,XSTOP}, (raw32){2}, 4, (raw){SER32(2)} },
|
||||||
|
{ {XE3,XSTOP}, (raw32){3}, 4, (raw){SER32(3)} },
|
||||||
|
{ {Xi,XSTOP}, (raw32){1}, 4, (raw){SER32(1)} },
|
||||||
|
{ {Xix2,XSTOP}, (raw32){2,3}, 8, (raw){SER32(2), SER32(3)} },
|
||||||
|
{ {Xix3,XSTOP}, (raw32){4,5,6}, 12, (raw){SER32(4), SER32(5), SER32(6)} },
|
||||||
|
{ {Xix4,XSTOP}, (raw32){7,8,9,10}, 16, (raw){SER32(7), SER32(8), SER32(9), SER32(10)} },
|
||||||
|
{ {Xu,XSTOP}, (raw32){1}, 4, (raw){SER32(1)} },
|
||||||
|
{ {Xux2,XSTOP}, (raw32){2,3}, 8, (raw){SER32(2), SER32(3)} },
|
||||||
|
{ {Xux3,XSTOP}, (raw32){4,5,6}, 12, (raw){SER32(4), SER32(5), SER32(6)} },
|
||||||
|
{ {Xux4,XSTOP}, (raw32){7,8,9,10}, 16, (raw){SER32(7), SER32(8), SER32(9), SER32(10)} },
|
||||||
|
{ {Xux5,XSTOP}, (raw32){7,8,9,10,11}, 20, (raw){SER32(7), SER32(8), SER32(9), SER32(10), SER32(11)} },
|
||||||
|
{ {XD,XSTOP}, (uint64_t[]){314159265358979324},
|
||||||
|
/* note: fractional part depends on rounding rule used for converting nanoseconds to NTP time
|
||||||
|
Cyclone currently rounds up, so we have to do that too */
|
||||||
|
8, (raw){SER32(314159265), SER32(1541804457)} },
|
||||||
|
{ {XD,XSTOP}, (uint64_t[]){DDS_NEVER},
|
||||||
|
8, (raw){SER32(INT32_MAX), SER32(UINT32_MAX)} },
|
||||||
|
{ {XDx2,XSTOP}, (uint64_t[]){314159265358979324, 271828182845904524},
|
||||||
|
16, (raw){SER32(314159265), SER32(1541804457), SER32(271828182), SER32(3633132267)} },
|
||||||
|
{ {Xo,XSTOP}, (raw){31}, 1, (raw){31} },
|
||||||
|
{ {Xox2,XSTOP}, (raw){31,13}, 2, (raw){31,13} },
|
||||||
|
{ {Xb,XSTOP}, (raw){1}, 1, (raw){1} },
|
||||||
|
{ {Xbx2,XSTOP}, (raw){1,0}, 2, (raw){1,0} },
|
||||||
|
{ {XG,XSTOP}, (raw32){3,4,5,0x1c1}, 16, (raw){SER32BE(3), SER32BE(4), SER32BE(5), SER32BE(0x1c1) } },
|
||||||
|
{ {XK,XSTOP}, (raw){1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16},
|
||||||
|
16, (raw){1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} },
|
||||||
|
{ {XQ,Xo,XSTOP,XSTOP}, &(oseq){3, (raw){1,2,3}},
|
||||||
|
7, (raw){SER32(3), 1,2,3} },
|
||||||
|
{ {XQ,XS,XSTOP,XSTOP}, &(ddsi_stringseq_t){2, (char*[]){"tree","flower"}},
|
||||||
|
27, (raw){SER32(2), SER32(5),'t','r','e','e',0, 0,0,0, SER32(7), 'f','l','o','w','e','r',0} },
|
||||||
|
{ {Xb,XQ,XbPROP,XS,Xo,XSTOP,XSTOP},
|
||||||
|
&(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}}}},
|
||||||
|
43, (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
|
||||||
|
},
|
||||||
|
&(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}}}},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
CU_Test (ddsi_plist_generic, ser_and_deser)
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
uint64_t u;
|
||||||
|
void *p;
|
||||||
|
char buf[256];
|
||||||
|
} mem;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < sizeof (descs) / sizeof (descs[0]); i++)
|
||||||
|
{
|
||||||
|
size_t memsize;
|
||||||
|
void *ser;
|
||||||
|
size_t sersize;
|
||||||
|
dds_return_t ret;
|
||||||
|
ret = plist_ser_generic (&ser, &sersize, descs[i].data, descs[i].desc);
|
||||||
|
if (ret != DDS_RETCODE_OK)
|
||||||
|
CU_ASSERT_FATAL (ret == DDS_RETCODE_OK);
|
||||||
|
if (sersize != descs[i].exp_sersize)
|
||||||
|
CU_ASSERT (sersize == descs[i].exp_sersize);
|
||||||
|
/* if sizes don't match, still check prefix */
|
||||||
|
size_t cmpsize = (sersize < descs[i].exp_sersize) ? sersize : descs[i].exp_sersize;
|
||||||
|
if (memcmp (ser, descs[i].exp_ser, cmpsize) != 0)
|
||||||
|
{
|
||||||
|
printf ("memcmp i = %zu\n", i);
|
||||||
|
for (size_t k = 0; k < cmpsize; k++)
|
||||||
|
printf (" %3zu %02x %02x\n", k, ((unsigned char *)ser)[k], descs[i].exp_ser[k]);
|
||||||
|
CU_ASSERT (!(bool)"memcmp");
|
||||||
|
}
|
||||||
|
/* check */
|
||||||
|
memsize = plist_memsize_generic (descs[i].desc);
|
||||||
|
if (memsize > sizeof (mem))
|
||||||
|
CU_ASSERT_FATAL (memsize <= sizeof (mem));
|
||||||
|
/* memset to zero for used part so padding is identical to compiler inserted padding,
|
||||||
|
but to something unlikely for the remainder */
|
||||||
|
memset (mem.buf, 0, memsize);
|
||||||
|
memset (mem.buf + memsize, 0xee, sizeof (mem) - memsize);
|
||||||
|
ret = plist_deser_generic (&mem, ser, sersize, false, descs[i].desc);
|
||||||
|
if (ret != DDS_RETCODE_OK)
|
||||||
|
CU_ASSERT_FATAL (ret == DDS_RETCODE_OK);
|
||||||
|
/* the compare function should be happy with it */
|
||||||
|
if (!plist_equal_generic (descs[i].exp_data ? descs[i].exp_data : descs[i].data, &mem, descs[i].desc))
|
||||||
|
CU_ASSERT (!(bool)"plist_equal_generic");
|
||||||
|
/* content should be identical except when an XO, XS or XQ is present (because the first two
|
||||||
|
alias the serialised form and XQ to freshly allocated memory), so we do a limited check */
|
||||||
|
bool can_memcmp = true;
|
||||||
|
for (const enum pserop *op = descs[i].desc; *op != XSTOP && can_memcmp; op++)
|
||||||
|
if (*op == XS || *op == XO || *op == XQ)
|
||||||
|
can_memcmp = false;
|
||||||
|
if (can_memcmp && memcmp (descs[i].exp_data ? descs[i].exp_data : descs[i].data, &mem, memsize) != 0)
|
||||||
|
CU_ASSERT (!(bool)"memcmp");
|
||||||
|
/* rely on mem checkers to find memory leaks, incorrect free, etc. */
|
||||||
|
plist_fini_generic (&mem, descs[i].desc, true);
|
||||||
|
ddsrt_free (ser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CU_Test (ddsi_plist_generic, unalias)
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
uint64_t u;
|
||||||
|
void *p;
|
||||||
|
char buf[256];
|
||||||
|
} mem;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < sizeof (descs) / sizeof (descs[0]); i++)
|
||||||
|
{
|
||||||
|
void *ser;
|
||||||
|
size_t sersize;
|
||||||
|
dds_return_t ret;
|
||||||
|
(void) plist_ser_generic (&ser, &sersize, descs[i].data, descs[i].desc);
|
||||||
|
(void) plist_deser_generic (&mem, ser, sersize, false, descs[i].desc);
|
||||||
|
/* after unaliasing, the data should be valid even when the serialised form has been overwritten or freed */
|
||||||
|
ret = plist_unalias_generic (&mem, descs[i].desc);
|
||||||
|
CU_ASSERT_FATAL (ret == DDS_RETCODE_OK);
|
||||||
|
memset (ser, 0xee, sersize);
|
||||||
|
ddsrt_free (ser);
|
||||||
|
if (!plist_equal_generic (descs[i].exp_data ? descs[i].exp_data : descs[i].data, &mem, descs[i].desc))
|
||||||
|
CU_ASSERT (!(bool)"plist_equal_generic");
|
||||||
|
plist_fini_generic (&mem, descs[i].desc, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct desc_invalid descs_invalid[] = {
|
||||||
|
{ {Xb,XSTOP}, 1, (raw){2} }, // 2 is not a valid boolean
|
||||||
|
{ {XS,XSTOP}, 8, (raw){SER32(5), 'm','e','o','w',0} }, // short input
|
||||||
|
{ {XS,XSTOP}, 8, (raw){SER32(4), 'm','e','o','w',0} }, // not terminated
|
||||||
|
{ {XG,XSTOP}, 15, (raw){SER32BE(3), SER32BE(4), SER32BE(5), SER32BE(0x100) } }, // short input
|
||||||
|
{ {XK,XSTOP}, 15, (raw){1,2,3,4,5,6,7,8,9,10,11,12,13,14,15} }, // short input
|
||||||
|
{ {XQ,Xo,XSTOP,XSTOP}, 7, (raw){SER32(4), 1,2,3} }, // short input
|
||||||
|
{ {XQ,XS,XSTOP,XSTOP}, // padding missing, short input
|
||||||
|
24, (raw){SER32(2), SER32(5),'t','r','e','e',0, SER32(7), 'f','l','o','w','e','r',0} },
|
||||||
|
{ {Xb,XQ,XbPROP,XS,Xo,XSTOP,XSTOP},
|
||||||
|
43, (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(7), 'p','r','u','n','e',0, 5 // string not terminated
|
||||||
|
} },
|
||||||
|
{ {Xb, XQ,XbPROP,XS,Xo,XSTOP, XQ,XbPROP,XS,Xo,XSTOP, XSTOP},
|
||||||
|
43, (raw){1, 0,0,0,
|
||||||
|
/* first sequence is valid */
|
||||||
|
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,
|
||||||
|
/* second sequence is invalid */
|
||||||
|
0, /* pad */
|
||||||
|
SER32(3),
|
||||||
|
SER32(7), 'o','r','a','n','g','e',0, 2,
|
||||||
|
SER32(4), 'f','i','g',0, 4, 0,0,0,
|
||||||
|
SER32(7), 'p','r','u','n','e',0, 5 // string not terminated
|
||||||
|
} }
|
||||||
|
};
|
||||||
|
|
||||||
|
CU_Test (ddsi_plist_generic, invalid_input)
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
uint64_t u;
|
||||||
|
void *p;
|
||||||
|
char buf[256];
|
||||||
|
} mem;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < sizeof (descs_invalid) / sizeof (descs_invalid[0]); i++)
|
||||||
|
{
|
||||||
|
dds_return_t ret;
|
||||||
|
ret = plist_deser_generic (&mem, descs_invalid[i].ser, descs_invalid[i].sersize, false, descs_invalid[i].desc);
|
||||||
|
if (ret == DDS_RETCODE_OK)
|
||||||
|
CU_ASSERT_FATAL (ret != DDS_RETCODE_OK);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue