cyclonedds/src/core/ddsc/src/dds_qos.c
Erik Boasson 0356af470d Fix undefined behaviour reported by ubsan
* calling ddsrt_memdup, ddsrt_strdup with a null pointer (they handle it
  gracefully but forbid it in the interface ...)

* replacement of all pre-C99 flexible arrays (i.e., declaring as
  array[1], then mallocing and using as if array[N]) by C99 flexible
  arrays.

* also add a missing null-pointer test in dds_dispose_ts, and fix the
  test cases that pass a null pointer and a non-writer handle to it to
  instead pass an invalid adress

Signed-off-by: Erik Boasson <eb@ilities.com>
2019-06-28 12:47:27 +02:00

567 lines
17 KiB
C

/*
* 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 <assert.h>
#include <string.h>
#include <stdbool.h>
#include "dds/dds.h"
#include "dds/ddsrt/heap.h"
#include "dds/ddsrt/string.h"
#include "dds/ddsi/q_plist.h"
static void dds_qos_data_copy_in (ddsi_octetseq_t *data, const void * __restrict value, size_t sz, bool overwrite)
{
if (overwrite && data->value)
ddsrt_free (data->value);
data->length = (uint32_t) sz;
data->value = value ? ddsrt_memdup (value, sz) : NULL;
}
static bool dds_qos_data_copy_out (const ddsi_octetseq_t *data, void **value, size_t *sz)
{
assert (data->length < UINT32_MAX);
if (sz == NULL && value != NULL)
return false;
if (sz)
*sz = data->length;
if (value)
{
if (data->length == 0)
*value = NULL;
else
{
assert (data->value);
*value = dds_alloc (data->length + 1);
memcpy (*value, data->value, data->length);
((char *) (*value))[data->length] = 0;
}
}
return true;
}
dds_qos_t *dds_create_qos (void)
{
dds_qos_t *qos = ddsrt_malloc (sizeof (dds_qos_t));
nn_xqos_init_empty (qos);
return qos;
}
dds_qos_t *dds_qos_create (void)
{
return dds_create_qos ();
}
void dds_reset_qos (dds_qos_t * __restrict qos)
{
if (qos)
{
nn_xqos_fini (qos);
nn_xqos_init_empty (qos);
}
}
void dds_qos_reset (dds_qos_t * __restrict qos)
{
dds_reset_qos (qos);
}
void dds_delete_qos (dds_qos_t * __restrict qos)
{
if (qos)
{
nn_xqos_fini (qos);
ddsrt_free (qos);
}
}
void dds_qos_delete (dds_qos_t * __restrict qos)
{
dds_delete_qos (qos);
}
dds_return_t dds_copy_qos (dds_qos_t * __restrict dst, const dds_qos_t * __restrict src)
{
if (src == NULL || dst == NULL)
return DDS_RETCODE_BAD_PARAMETER;
nn_xqos_copy (dst, src);
return DDS_RETCODE_OK;
}
dds_return_t dds_qos_copy (dds_qos_t * __restrict dst, const dds_qos_t * __restrict src)
{
return dds_copy_qos (dst, src);
}
void dds_merge_qos (dds_qos_t * __restrict dst, const dds_qos_t * __restrict src)
{
/* Copy qos from source to destination unless already set */
if (src != NULL && dst != NULL)
nn_xqos_mergein_missing (dst, src, ~(uint64_t)0);
}
void dds_qos_merge (dds_qos_t * __restrict dst, const dds_qos_t * __restrict src)
{
dds_merge_qos (dst, src);
}
bool dds_qos_equal (const dds_qos_t * __restrict a, const dds_qos_t * __restrict b)
{
/* FIXME: a bit of a hack - and I am not so sure I like accepting null pointers here anyway */
if (a == NULL && b == NULL)
return true;
else if (a == NULL || b == NULL)
return false;
else
return nn_xqos_delta (a, b, ~(uint64_t)0) == 0;
}
void dds_qset_userdata (dds_qos_t * __restrict qos, const void * __restrict value, size_t sz)
{
if (qos == NULL || (sz > 0 && value == NULL))
return;
dds_qos_data_copy_in (&qos->user_data, value, sz, qos->present & QP_USER_DATA);
qos->present |= QP_USER_DATA;
}
void dds_qset_topicdata (dds_qos_t * __restrict qos, const void * __restrict value, size_t sz)
{
if (qos == NULL || (sz > 0 && value == NULL))
return;
dds_qos_data_copy_in (&qos->topic_data, value, sz, qos->present & QP_TOPIC_DATA);
qos->present |= QP_TOPIC_DATA;
}
void dds_qset_groupdata (dds_qos_t * __restrict qos, const void * __restrict value, size_t sz)
{
if (qos == NULL || (sz > 0 && value == NULL))
return;
dds_qos_data_copy_in (&qos->group_data, value, sz, qos->present & QP_GROUP_DATA);
qos->present |= QP_GROUP_DATA;
}
void dds_qset_durability (dds_qos_t * __restrict qos, dds_durability_kind_t kind)
{
if (qos == NULL)
return;
qos->durability.kind = kind;
qos->present |= QP_DURABILITY;
}
void dds_qset_history (dds_qos_t * __restrict qos, dds_history_kind_t kind, int32_t depth)
{
if (qos == NULL)
return;
qos->history.kind = kind;
qos->history.depth = depth;
qos->present |= QP_HISTORY;
}
void dds_qset_resource_limits (dds_qos_t * __restrict qos, int32_t max_samples, int32_t max_instances, int32_t max_samples_per_instance)
{
if (qos == NULL)
return;
qos->resource_limits.max_samples = max_samples;
qos->resource_limits.max_instances = max_instances;
qos->resource_limits.max_samples_per_instance = max_samples_per_instance;
qos->present |= QP_RESOURCE_LIMITS;
}
void dds_qset_presentation (dds_qos_t * __restrict qos, dds_presentation_access_scope_kind_t access_scope, bool coherent_access, bool ordered_access)
{
if (qos == NULL)
return;
qos->presentation.access_scope = access_scope;
qos->presentation.coherent_access = coherent_access;
qos->presentation.ordered_access = ordered_access;
qos->present |= QP_PRESENTATION;
}
void dds_qset_lifespan (dds_qos_t * __restrict qos, dds_duration_t lifespan)
{
if (qos == NULL)
return;
qos->lifespan.duration = lifespan;
qos->present |= QP_LIFESPAN;
}
void dds_qset_deadline (dds_qos_t * __restrict qos, dds_duration_t deadline)
{
if (qos == NULL)
return;
qos->deadline.deadline = deadline;
qos->present |= QP_DEADLINE;
}
void dds_qset_latency_budget (dds_qos_t * __restrict qos, dds_duration_t duration)
{
if (qos == NULL)
return;
qos->latency_budget.duration = duration;
qos->present |= QP_LATENCY_BUDGET;
}
void dds_qset_ownership (dds_qos_t * __restrict qos, dds_ownership_kind_t kind)
{
if (qos == NULL)
return;
qos->ownership.kind = kind;
qos->present |= QP_OWNERSHIP;
}
void dds_qset_ownership_strength (dds_qos_t * __restrict qos, int32_t value)
{
if (qos == NULL)
return;
qos->ownership_strength.value = value;
qos->present |= QP_OWNERSHIP_STRENGTH;
}
void dds_qset_liveliness (dds_qos_t * __restrict qos, dds_liveliness_kind_t kind, dds_duration_t lease_duration)
{
if (qos == NULL)
return;
qos->liveliness.kind = kind;
qos->liveliness.lease_duration = lease_duration;
qos->present |= QP_LIVELINESS;
}
void dds_qset_time_based_filter (dds_qos_t * __restrict qos, dds_duration_t minimum_separation)
{
if (qos == NULL)
return;
qos->time_based_filter.minimum_separation = minimum_separation;
qos->present |= QP_TIME_BASED_FILTER;
}
void dds_qset_partition (dds_qos_t * __restrict qos, uint32_t n, const char ** __restrict ps)
{
if (qos == NULL || (n > 0 && ps == NULL))
return;
if (qos->present & QP_PARTITION)
{
for (uint32_t i = 0; i < qos->partition.n; i++)
ddsrt_free (qos->partition.strs[i]);
ddsrt_free (qos->partition.strs);
}
qos->partition.n = n;
if (qos->partition.n == 0)
qos->partition.strs = NULL;
else
{
qos->partition.strs = ddsrt_malloc (n * sizeof (*qos->partition.strs));
for (uint32_t i = 0; i < n; i++)
qos->partition.strs[i] = ddsrt_strdup (ps[i]);
}
qos->present |= QP_PARTITION;
}
void dds_qset_partition1 (dds_qos_t * __restrict qos, const char * __restrict name)
{
if (name == NULL)
dds_qset_partition (qos, 0, NULL);
else
dds_qset_partition (qos, 1, (const char **) &name);
}
void dds_qset_reliability (dds_qos_t * __restrict qos, dds_reliability_kind_t kind, dds_duration_t max_blocking_time)
{
if (qos == NULL)
return;
qos->reliability.kind = kind;
qos->reliability.max_blocking_time = max_blocking_time;
qos->present |= QP_RELIABILITY;
}
void dds_qset_transport_priority (dds_qos_t * __restrict qos, int32_t value)
{
if (qos == NULL)
return;
qos->transport_priority.value = value;
qos->present |= QP_TRANSPORT_PRIORITY;
}
void dds_qset_destination_order (dds_qos_t * __restrict qos, dds_destination_order_kind_t kind)
{
if (qos == NULL)
return;
qos->destination_order.kind = kind;
qos->present |= QP_DESTINATION_ORDER;
}
void dds_qset_writer_data_lifecycle (dds_qos_t * __restrict qos, bool autodispose)
{
if (qos == NULL)
return;
qos->writer_data_lifecycle.autodispose_unregistered_instances = autodispose;
qos->present |= QP_PRISMTECH_WRITER_DATA_LIFECYCLE;
}
void dds_qset_reader_data_lifecycle (dds_qos_t * __restrict qos, dds_duration_t autopurge_nowriter_samples_delay, dds_duration_t autopurge_disposed_samples_delay)
{
if (qos == NULL)
return;
qos->reader_data_lifecycle.autopurge_nowriter_samples_delay = autopurge_nowriter_samples_delay;
qos->reader_data_lifecycle.autopurge_disposed_samples_delay = autopurge_disposed_samples_delay;
qos->present |= QP_PRISMTECH_READER_DATA_LIFECYCLE;
}
void dds_qset_durability_service (dds_qos_t * __restrict qos, dds_duration_t service_cleanup_delay, dds_history_kind_t history_kind, int32_t history_depth, int32_t max_samples, int32_t max_instances, int32_t max_samples_per_instance)
{
if (qos == NULL)
return;
qos->durability_service.service_cleanup_delay = service_cleanup_delay;
qos->durability_service.history.kind = history_kind;
qos->durability_service.history.depth = history_depth;
qos->durability_service.resource_limits.max_samples = max_samples;
qos->durability_service.resource_limits.max_instances = max_instances;
qos->durability_service.resource_limits.max_samples_per_instance = max_samples_per_instance;
qos->present |= QP_DURABILITY_SERVICE;
}
void dds_qset_ignorelocal (dds_qos_t * __restrict qos, dds_ignorelocal_kind_t ignore)
{
if (qos == NULL)
return;
qos->ignorelocal.value = ignore;
qos->present |= QP_CYCLONE_IGNORELOCAL;
}
bool dds_qget_userdata (const dds_qos_t * __restrict qos, void **value, size_t *sz)
{
if (qos == NULL || !(qos->present & QP_USER_DATA))
return false;
return dds_qos_data_copy_out (&qos->user_data, value, sz);
}
bool dds_qget_topicdata (const dds_qos_t * __restrict qos, void **value, size_t *sz)
{
if (qos == NULL || !(qos->present & QP_TOPIC_DATA))
return false;
return dds_qos_data_copy_out (&qos->topic_data, value, sz);
}
bool dds_qget_groupdata (const dds_qos_t * __restrict qos, void **value, size_t *sz)
{
if (qos == NULL || !(qos->present & QP_GROUP_DATA))
return false;
return dds_qos_data_copy_out (&qos->group_data, value, sz);
}
bool dds_qget_durability (const dds_qos_t * __restrict qos, dds_durability_kind_t *kind)
{
if (qos == NULL || !(qos->present & QP_DURABILITY))
return false;
if (kind)
*kind = qos->durability.kind;
return true;
}
bool dds_qget_history (const dds_qos_t * __restrict qos, dds_history_kind_t *kind, int32_t *depth)
{
if (qos == NULL || !(qos->present & QP_HISTORY))
return false;
if (kind)
*kind = qos->history.kind;
if (depth)
*depth = qos->history.depth;
return true;
}
bool dds_qget_resource_limits (const dds_qos_t * __restrict qos, int32_t *max_samples, int32_t *max_instances, int32_t *max_samples_per_instance)
{
if (qos == NULL || !(qos->present & QP_RESOURCE_LIMITS))
return false;
if (max_samples)
*max_samples = qos->resource_limits.max_samples;
if (max_instances)
*max_instances = qos->resource_limits.max_instances;
if (max_samples_per_instance)
*max_samples_per_instance = qos->resource_limits.max_samples_per_instance;
return true;
}
bool dds_qget_presentation (const dds_qos_t * __restrict qos, dds_presentation_access_scope_kind_t *access_scope, bool *coherent_access, bool *ordered_access)
{
if (qos == NULL || !(qos->present & QP_PRESENTATION))
return false;
if (access_scope)
*access_scope = qos->presentation.access_scope;
if (coherent_access)
*coherent_access = qos->presentation.coherent_access;
if (ordered_access)
*ordered_access = qos->presentation.ordered_access;
return true;
}
bool dds_qget_lifespan (const dds_qos_t * __restrict qos, dds_duration_t *lifespan)
{
if (qos == NULL || !(qos->present & QP_LIFESPAN))
return false;
if (lifespan)
*lifespan = qos->lifespan.duration;
return true;
}
bool dds_qget_deadline (const dds_qos_t * __restrict qos, dds_duration_t *deadline)
{
if (qos == NULL || !(qos->present & QP_DEADLINE))
return false;
if (deadline)
*deadline = qos->deadline.deadline;
return true;
}
bool dds_qget_latency_budget (const dds_qos_t * __restrict qos, dds_duration_t *duration)
{
if (qos == NULL || !(qos->present & QP_LATENCY_BUDGET))
return false;
if (duration)
*duration = qos->latency_budget.duration;
return true;
}
bool dds_qget_ownership (const dds_qos_t * __restrict qos, dds_ownership_kind_t *kind)
{
if (qos == NULL || !(qos->present & QP_OWNERSHIP))
return false;
if (kind)
*kind = qos->ownership.kind;
return true;
}
bool dds_qget_ownership_strength (const dds_qos_t * __restrict qos, int32_t *value)
{
if (qos == NULL || !(qos->present & QP_OWNERSHIP_STRENGTH))
return false;
if (value)
*value = qos->ownership_strength.value;
return true;
}
bool dds_qget_liveliness (const dds_qos_t * __restrict qos, dds_liveliness_kind_t *kind, dds_duration_t *lease_duration)
{
if (qos == NULL || !(qos->present & QP_LIVELINESS))
return false;
if (kind)
*kind = qos->liveliness.kind;
if (lease_duration)
*lease_duration = qos->liveliness.lease_duration;
return true;
}
bool dds_qget_time_based_filter (const dds_qos_t * __restrict qos, dds_duration_t *minimum_separation)
{
if (qos == NULL || !(qos->present & QP_TIME_BASED_FILTER))
return false;
if (minimum_separation)
*minimum_separation = qos->time_based_filter.minimum_separation;
return true;
}
bool dds_qget_partition (const dds_qos_t * __restrict qos, uint32_t *n, char ***ps)
{
if (qos == NULL || !(qos->present & QP_PARTITION))
return false;
if (n == NULL && ps != NULL)
return false;
if (n)
*n = qos->partition.n;
if (ps)
{
if (qos->partition.n == 0)
*ps = NULL;
else
{
*ps = dds_alloc (sizeof (char*) * qos->partition.n);
for (uint32_t i = 0; i < qos->partition.n; i++)
(*ps)[i] = dds_string_dup (qos->partition.strs[i]);
}
}
return true;
}
bool dds_qget_reliability (const dds_qos_t * __restrict qos, dds_reliability_kind_t *kind, dds_duration_t *max_blocking_time)
{
if (qos == NULL || !(qos->present & QP_RELIABILITY))
return false;
if (kind)
*kind = qos->reliability.kind;
if (max_blocking_time)
*max_blocking_time = qos->reliability.max_blocking_time;
return true;
}
bool dds_qget_transport_priority (const dds_qos_t * __restrict qos, int32_t *value)
{
if (qos == NULL || !(qos->present & QP_TRANSPORT_PRIORITY))
return false;
if (value)
*value = qos->transport_priority.value;
return true;
}
bool dds_qget_destination_order (const dds_qos_t * __restrict qos, dds_destination_order_kind_t *kind)
{
if (qos == NULL || !(qos->present & QP_DESTINATION_ORDER))
return false;
if (kind)
*kind = qos->destination_order.kind;
return true;
}
bool dds_qget_writer_data_lifecycle (const dds_qos_t * __restrict qos, bool *autodispose)
{
if (qos == NULL || !(qos->present & QP_PRISMTECH_WRITER_DATA_LIFECYCLE))
return false;
if (autodispose)
*autodispose = qos->writer_data_lifecycle.autodispose_unregistered_instances;
return true;
}
bool dds_qget_reader_data_lifecycle (const dds_qos_t * __restrict qos, dds_duration_t *autopurge_nowriter_samples_delay, dds_duration_t *autopurge_disposed_samples_delay)
{
if (qos == NULL || !(qos->present & QP_PRISMTECH_READER_DATA_LIFECYCLE))
return false;
if (autopurge_nowriter_samples_delay)
*autopurge_nowriter_samples_delay = qos->reader_data_lifecycle.autopurge_nowriter_samples_delay;
if (autopurge_disposed_samples_delay)
*autopurge_disposed_samples_delay = qos->reader_data_lifecycle.autopurge_disposed_samples_delay;
return true;
}
bool dds_qget_durability_service (const dds_qos_t * __restrict qos, dds_duration_t *service_cleanup_delay, dds_history_kind_t *history_kind, int32_t *history_depth, int32_t *max_samples, int32_t *max_instances, int32_t *max_samples_per_instance)
{
if (qos == NULL || !(qos->present & QP_DURABILITY_SERVICE))
return false;
if (service_cleanup_delay)
*service_cleanup_delay = qos->durability_service.service_cleanup_delay;
if (history_kind)
*history_kind = qos->durability_service.history.kind;
if (history_depth)
*history_depth = qos->durability_service.history.depth;
if (max_samples)
*max_samples = qos->durability_service.resource_limits.max_samples;
if (max_instances)
*max_instances = qos->durability_service.resource_limits.max_instances;
if (max_samples_per_instance)
*max_samples_per_instance = qos->durability_service.resource_limits.max_samples_per_instance;
return true;
}
bool dds_qget_ignorelocal (const dds_qos_t * __restrict qos, dds_ignorelocal_kind_t *ignore)
{
if (qos == NULL || !(qos->present & QP_CYCLONE_IGNORELOCAL))
return false;
if (ignore)
*ignore = qos->ignorelocal.value;
return true;
}