LCOV - code coverage report
Current view: top level - core - marsh.h (source / functions) Coverage Total Hit
Test: lcov.out Lines: 100.0 % 21 21
Test Date: 2025-02-26 17:59:59 Functions: 100.0 % 5 5

            Line data    Source code
       1              : /* SPDX-License-Identifier: GPL-2.0-only */
       2              : /*
       3              :  * Copyright (c) 2023 Meta Platforms, Inc. and affiliates.
       4              :  */
       5              : 
       6              : #pragma once
       7              : 
       8              : #include <stdbool.h>
       9              : #include <stddef.h>
      10              : 
      11              : #include "core/helper.h"
      12              : 
      13              : /**
      14              :  * Marshalled data.
      15              :  *
      16              :  * @var bf_marsh::data_len
      17              :  *  Length of marshalled data. It doesn't include the length of the header.
      18              :  * @var bf_marsh::data
      19              :  *  Marshalled data.
      20              :  */
      21              : struct bf_marsh
      22              : {
      23              :     size_t data_len;
      24              :     char data[];
      25              : } bf_packed;
      26              : 
      27              : #define _cleanup_bf_marsh_ __attribute__((__cleanup__(bf_marsh_free)))
      28              : 
      29              : /**
      30              :  * Returns true if a marsh object is empty (only contains a header).
      31              :  *
      32              :  * @param marsh Marsh object to check for empty. Can't be NULL.
      33              :  * @return True if the @c marsh object is empty, false otherwise.
      34              :  */
      35            1 : static inline bool bf_marsh_is_empty(const struct bf_marsh *marsh)
      36              : {
      37            1 :     bf_assert(marsh);
      38              : 
      39            1 :     return marsh->data_len == 0;
      40              : }
      41              : 
      42              : /**
      43              :  * Get the total size of marshalled data.
      44              :  *
      45              :  * @param marsh Marshalled data.
      46              :  * @return Total size of marshalled data, including the header.
      47              :  */
      48          235 : static inline size_t bf_marsh_size(const struct bf_marsh *marsh)
      49              : {
      50          235 :     bf_assert(marsh);
      51              : 
      52          235 :     return sizeof(struct bf_marsh) + marsh->data_len;
      53              : }
      54              : 
      55              : /**
      56              :  * Get pointer to the end of a @ref bf_marsh structure.
      57              :  *
      58              :  * "End" here, means the first byte after the content of the marshalled data.
      59              :  *
      60              :  * @param marsh Marshalled data.
      61              :  * @return Pointer to the end of the marshalled data.
      62              :  */
      63          501 : static inline void *bf_marsh_end(const struct bf_marsh *marsh)
      64              : {
      65          501 :     bf_assert(marsh);
      66              : 
      67          501 :     return (void *)(marsh->data + marsh->data_len);
      68              : }
      69              : 
      70              : /**
      71              :  * Check if `child` is a valid child for `marsh`.
      72              :  *
      73              :  * A valid marsh is defined by the following criteria:
      74              :  * - It starts within its parent's data.
      75              :  * - Its full length (including the header) is within its parent's data.
      76              :  * A marsh can only be validated relative to its parent. By recursively
      77              :  * validating all the children of a marsh, we can validate the whole marsh.
      78              :  *
      79              :  * @warning This function doesn't check if the marshalled data is valid. It
      80              :  * only checks if the marshalled data is within the parent's data and can be
      81              :  * accessed safely.
      82              :  *
      83              :  * @param marsh Parent marsh, must be valid.
      84              :  * @param child Child marsh to validate. Can be NULL.
      85              :  * @return true if `child` is a valid child of `marsh`, false otherwise.
      86              :  */
      87          135 : static inline bool bf_marsh_child_is_valid(const struct bf_marsh *marsh,
      88              :                                            const struct bf_marsh *child)
      89              : {
      90          135 :     bf_assert(marsh);
      91              : 
      92          134 :     if (!child)
      93              :         return false;
      94              : 
      95              :     // Child must start within the parent marsh.
      96          265 :     if ((void *)child < (void *)marsh->data ||
      97          132 :         (void *)child > bf_marsh_end(marsh))
      98            2 :         return false;
      99              : 
     100              :     /* Child's data_len field must be within the parent bf_marsh. This check
     101              :      * is required to safely access child->data_len. */
     102          131 :     if ((void *)child + sizeof(struct bf_marsh) > bf_marsh_end(marsh))
     103              :         return false;
     104              : 
     105              :     // Child's data must be within the parent bf_marsh.
     106          117 :     if (bf_marsh_end(child) > bf_marsh_end(marsh))
     107              :         return false;
     108              : 
     109              :     return true;
     110              : }
     111              : 
     112              : /**
     113              :  * Get `marsh`'s child located after `child`.
     114              :  *
     115              :  * @param marsh Parent marsh, must be valid.
     116              :  * @param child Child of `marsh`, must be a valid child of `marsh` or NULL. If
     117              :  *        `child` is NULL, the first child of `marsh` is returned.
     118              :  * @return Next child of `marsh` after `child`, or NULL if `child` is the
     119              :  *         last valid child of `marsh`.
     120              :  */
     121          130 : static inline struct bf_marsh *bf_marsh_next_child(const struct bf_marsh *marsh,
     122              :                                                    const struct bf_marsh *child)
     123              : {
     124          130 :     bf_assert(marsh);
     125              : 
     126              :     struct bf_marsh *next_child =
     127          129 :         child ? (struct bf_marsh *)(child->data + child->data_len) :
     128              :                 (struct bf_marsh *)marsh->data;
     129              : 
     130          129 :     return bf_marsh_child_is_valid(marsh, next_child) ? next_child : NULL;
     131              : }
     132              : 
     133              : /**
     134              :  * Allocate and initialise a @ref bf_marsh structure.
     135              :  *
     136              :  * @param marsh Marsh to be allocated. On success, contains a pointer to the
     137              :  *        marsh structure, and is owned by the caller. If the function fails, it's
     138              :  *        left unchanged.
     139              :  * @param data Data to be marshalled.
     140              :  * @param data_len Length of @p data.
     141              :  * @return 0 on success, negative errno value on error.
     142              :  */
     143              : int bf_marsh_new(struct bf_marsh **marsh, const void *data, size_t data_len);
     144              : 
     145              : /**
     146              :  * Free a marsh, including its data.
     147              :  *
     148              :  * If @p marsh points to NULL, then nothing is done.
     149              :  *
     150              :  * @param marsh Marsh to free. Must not be NULL.
     151              :  */
     152              : void bf_marsh_free(struct bf_marsh **marsh);
     153              : 
     154              : /**
     155              :  * Add a child to a marsh, from another marsh.
     156              :  *
     157              :  * @p obj will be added to the data in @p marsh.
     158              :  *
     159              :  * @param marsh Parent marsh. Must be non NULL.
     160              :  * @param obj Marsh to be added as a child. Must be non NULL.
     161              :  * @return 0 on success, negative errno value on error.
     162              :  */
     163              : int bf_marsh_add_child_obj(struct bf_marsh **marsh, const struct bf_marsh *obj);
     164              : 
     165              : /**
     166              :  * Add a child to a marsh, from raw data.
     167              :  *
     168              :  * If @p data is NULL, nothing is done and @p marsh remain unchanged. In this
     169              :  * case, @p data_len must be 0.
     170              :  *
     171              :  * @param marsh Parent marsh. Must be non NULL.
     172              :  * @param data Data to add to the marsh.
     173              :  * @param data_len Length of the data to add to @p marsh.
     174              :  * @return 0 on success, negative errno value on error.
     175              :  */
     176              : int bf_marsh_add_child_raw(struct bf_marsh **marsh, const void *data,
     177              :                            size_t data_len);
        

Generated by: LCOV version 2.0-1