blob: 6f50b05cef138a0d2227fa6695d40d010278ec9e [file] [log] [blame]
Patrick Williams691668f2023-11-01 08:19:10 -05001/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
Andrew Jefferyc63f63a2023-02-24 22:29:33 +10302#ifndef PLDM_MSGBUF_H
3#define PLDM_MSGBUF_H
4
Andrew Jeffery860a43d2024-08-23 01:21:58 +00005#include "compiler.h"
6
Andrew Jeffery66c77232024-04-24 11:42:02 +09307/*
8 * Historically, many of the structs exposed in libpldm's public headers are
9 * defined with __attribute__((packed)). This is unfortunate: it gives the
10 * impression that a wire-format buffer can be cast to the message type to make
11 * the message's fields easily accessible. As it turns out, that's not
12 * that's valid for several reasons:
13 *
14 * 1. Casting the wire-format buffer to a struct of the message type doesn't
15 * abstract the endianness of message field values
16 *
17 * 2. Some messages contain packed tagged union fields which cannot be properly
18 * described in a C struct.
19 *
20 * The msgbuf APIs exist to assist with (un)packing the wire-format in a way
21 * that is type-safe, spatially memory-safe, endian-safe, performant, and
22 * free of undefined-behaviour. Message structs that are added to the public
23 * library API should no-longer be marked __attribute__((packed)), and the
24 * implementation of their encode and decode functions must exploit the msgbuf
25 * API.
26 *
27 * However, we would like to allow implementation of codec functions in terms of
28 * msgbuf APIs even if they're decoding a message into a (historically) packed
29 * struct. Some of the complexity that follows is a consequence of the packed/
30 * unpacked conflict.
31 */
32
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103033#ifdef __cplusplus
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093034/*
35 * Fix up C11's _Static_assert() vs C++'s static_assert().
36 *
37 * Can we please have nice things for once.
38 */
39// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
40#define _Static_assert(...) static_assert(__VA_ARGS__)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103041extern "C" {
42#endif
43
Andrew Jefferyb0c1d202023-11-07 22:08:44 +103044#include <libpldm/base.h>
45#include <libpldm/pldm_types.h>
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103046
Andrew Jeffery66c77232024-04-24 11:42:02 +093047#include "compiler.h"
48
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103049#include <assert.h>
50#include <endian.h>
Andrew Jefferyc8df31c2024-05-21 16:47:43 +093051#include <errno.h>
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103052#include <limits.h>
53#include <stdbool.h>
Andrew Jeffery66c77232024-04-24 11:42:02 +093054#include <stdint.h>
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103055#include <string.h>
56#include <sys/types.h>
Thu Nguyen15237782024-07-02 09:30:41 +000057#include <uchar.h>
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103058
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +093059/*
60 * We can't use static_assert() outside of some other C construct. Deal
61 * with high-level global assertions by burying them in an unused struct
62 * declaration, that has a sole member for compliance with the requirement that
63 * types must have a size.
64*/
65static struct {
66 static_assert(
67 INTMAX_MAX != SIZE_MAX,
68 "Extraction and insertion value comparisons may be broken");
69 static_assert(INTMAX_MIN + INTMAX_MAX <= 0,
70 "Extraction and insertion arithmetic may be broken");
Andrew Jefferyc8df31c2024-05-21 16:47:43 +093071 static_assert(PLDM_SUCCESS == 0, "Error handling is broken");
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +093072 int compliance;
Andrew Jeffery860a43d2024-08-23 01:21:58 +000073} build_assertions LIBPLDM_CC_UNUSED;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +093074
Andrew Jefferyc8df31c2024-05-21 16:47:43 +093075enum pldm_msgbuf_error_mode {
76 PLDM_MSGBUF_PLDM_CC = 0x5a,
77 PLDM_MSGBUF_C_ERRNO = 0xa5,
78};
79
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103080struct pldm_msgbuf {
Thu Nguyen062c8762023-04-22 20:45:04 +070081 uint8_t *cursor;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +093082 intmax_t remaining;
Andrew Jefferyc8df31c2024-05-21 16:47:43 +093083 enum pldm_msgbuf_error_mode mode;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103084};
85
Andrew Jefferyd861a682024-06-03 21:43:09 +093086/**
87 * @brief Either negate an errno value or return a value mapped to a PLDM
88 * completion code.
89 *
90 * Note that `pldm_msgbuf_status()` is purely internal to the msgbuf API
91 * for ergonomics. It's preferred that we don't try to unify this with
92 * `pldm_xlate_errno()` from src/api.h despite the similarities.
93 *
94 * @param[in] ctx - The msgbuf context providing the personality info
95 * @param[in] err - The positive errno value to translate
96 *
97 * @return Either the negated value of @p err if the context's error mode is
98 * `PLDM_MSGBUF_C_ERRNO`, or the equivalent PLDM completion code if the
99 * error mode is `PLDM_MSGBUF_PLDM_CC`.
100 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300101LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300102LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_status(struct pldm_msgbuf *ctx,
103 unsigned int err)
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930104{
105 int rc;
106
107 assert(err != 0);
108 assert(err <= INT_MAX);
109
110 if (ctx->mode == PLDM_MSGBUF_C_ERRNO) {
111 if (err > INT_MAX) {
112 return -EINVAL;
113 }
114
115 static_assert(INT_MIN + INT_MAX < 0,
116 "Arithmetic assumption failure");
117 return -((int)err);
118 }
119
120 if (err > INT_MAX) {
121 return PLDM_ERROR;
122 }
123
124 assert(ctx->mode == PLDM_MSGBUF_PLDM_CC);
125 switch (err) {
126 case EINVAL:
127 rc = PLDM_ERROR_INVALID_DATA;
128 break;
129 case EBADMSG:
130 case EOVERFLOW:
131 rc = PLDM_ERROR_INVALID_LENGTH;
132 break;
133 default:
134 assert(false);
135 rc = PLDM_ERROR;
136 break;
137 }
138
139 assert(rc > 0);
140 return rc;
141}
142
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030143/**
144 * @brief Initialize pldm buf struct for buf extractor
145 *
146 * @param[out] ctx - pldm_msgbuf context for extractor
147 * @param[in] minsize - The minimum required length of buffer `buf`
148 * @param[in] buf - buffer to be extracted
149 * @param[in] len - size of buffer
150 *
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930151 * @return 0 on success, otherwise an error code appropriate for the current
152 * personality.
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030153 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300154LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300155LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930156// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
157pldm__msgbuf_init(struct pldm_msgbuf *ctx, size_t minsize, const void *buf,
158 size_t len)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030159{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930160 assert(ctx->mode == PLDM_MSGBUF_PLDM_CC ||
161 ctx->mode == PLDM_MSGBUF_C_ERRNO);
162
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930163 if ((minsize > len)) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930164 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030165 }
166
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930167#if INTMAX_MAX < SIZE_MAX
168 if (len > INTMAX_MAX) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930169 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930170 }
171#endif
172
Andrew Jeffery07febdb2024-05-17 14:17:14 +0930173 if ((uintptr_t)buf + len < len) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930174 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030175 }
176
177 ctx->cursor = (uint8_t *)buf;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930178 ctx->remaining = (intmax_t)len;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030179
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930180 return 0;
181}
182
183/**
184 * @brief Initialise a msgbuf instance to return errors as PLDM completion codes
185 *
186 * @see pldm__msgbuf_init
187 *
188 * @param[out] ctx - pldm_msgbuf context for extractor
189 * @param[in] minsize - The minimum required length of buffer `buf`
190 * @param[in] buf - buffer to be extracted
191 * @param[in] len - size of buffer
192 *
193 * @return PLDM_SUCCESS if the provided buffer region is sensible,
194 * otherwise PLDM_ERROR_INVALID_DATA if pointer parameters are invalid,
195 * or PLDM_ERROR_INVALID_LENGTH if length constraints are violated.
196 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300197LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300198LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_init_cc(struct pldm_msgbuf *ctx,
199 size_t minsize,
200 const void *buf, size_t len)
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930201{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930202 ctx->mode = PLDM_MSGBUF_PLDM_CC;
203 return pldm__msgbuf_init(ctx, minsize, buf, len);
204}
205
206/**
207 * @brief Initialise a msgbuf instance to return errors as negative errno values
208 *
209 * @see pldm__msgbuf_init
210 *
211 * @param[out] ctx - pldm_msgbuf context for extractor
212 * @param[in] minsize - The minimum required length of buffer `buf`
213 * @param[in] buf - buffer to be extracted
214 * @param[in] len - size of buffer
215 *
216 * @return 0 if the provided buffer region is sensible, otherwise -EINVAL if
217 * pointer parameters are invalid, or -EOVERFLOW if length constraints
218 * are violated.
219 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300220LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300221LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_init_errno(struct pldm_msgbuf *ctx,
222 size_t minsize,
223 const void *buf, size_t len)
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930224{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930225 ctx->mode = PLDM_MSGBUF_C_ERRNO;
226 return pldm__msgbuf_init(ctx, minsize, buf, len);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030227}
228
229/**
230 * @brief Validate buffer overflow state
231 *
232 * @param[in] ctx - pldm_msgbuf context for extractor
233 *
234 * @return PLDM_SUCCESS if there are zero or more bytes of data that remain
235 * unread from the buffer. Otherwise, PLDM_ERROR_INVALID_LENGTH indicates that a
236 * prior accesses would have occurred beyond the bounds of the buffer, and
237 * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid
238 * pointer.
239 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300240LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300241LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_validate(struct pldm_msgbuf *ctx)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030242{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930243 if (ctx->remaining < 0) {
244 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030245 }
246
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930247 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030248}
249
250/**
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930251 * @brief Test whether a message buffer has been exactly consumed
252 *
253 * @param[in] ctx - pldm_msgbuf context for extractor
254 *
255 * @return PLDM_SUCCESS iff there are zero bytes of data that remain unread from
256 * the buffer and no overflow has occurred. Otherwise, PLDM_ERROR_INVALID_LENGTH
257 * indicates that an incorrect sequence of accesses have occurred, and
258 * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid
259 * pointer.
260 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300261LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300262LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_consumed(struct pldm_msgbuf *ctx)
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930263{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930264 if (ctx->remaining != 0) {
265 return pldm_msgbuf_status(ctx, EBADMSG);
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930266 }
267
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930268 return 0;
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930269}
270
271/**
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030272 * @brief Destroy the pldm buf
273 *
274 * @param[in] ctx - pldm_msgbuf context for extractor
275 *
276 * @return PLDM_SUCCESS if all buffer accesses were in-bounds,
277 * PLDM_ERROR_INVALID_DATA if the ctx parameter is invalid, or
278 * PLDM_ERROR_INVALID_LENGTH if prior accesses would have occurred beyond the
279 * bounds of the buffer.
280 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300281LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300282LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_destroy(struct pldm_msgbuf *ctx)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030283{
284 int valid;
285
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030286 valid = pldm_msgbuf_validate(ctx);
287
288 ctx->cursor = NULL;
289 ctx->remaining = 0;
290
291 return valid;
292}
293
294/**
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930295 * @brief Destroy the pldm_msgbuf instance, and check that the underlying buffer
296 * has been completely consumed without overflow
297 *
298 * @param[in] ctx - pldm_msgbuf context
299 *
300 * @return PLDM_SUCCESS if all buffer access were in-bounds and completely
301 * consume the underlying buffer. Otherwise, PLDM_ERROR_INVALID_DATA if the ctx
302 * parameter is invalid, or PLDM_ERROR_INVALID_LENGTH if prior accesses would
303 * have occurred byond the bounds of the buffer
304 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300305LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300306LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery76712f62024-05-22 15:19:00 +0930307pldm_msgbuf_destroy_consumed(struct pldm_msgbuf *ctx)
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930308{
309 int consumed;
310
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930311 consumed = pldm_msgbuf_consumed(ctx);
312
313 ctx->cursor = NULL;
314 ctx->remaining = 0;
315
316 return consumed;
317}
318
Andrew Jeffery66c77232024-04-24 11:42:02 +0930319/*
320 * Exploit the pre-processor to perform type checking by macro substitution.
321 *
322 * A C type is defined by its alignment as well as its object
323 * size, and compilers have a hammer to enforce it in the form of
324 * `-Waddress-of-packed-member`. Due to the unpacked/packed struct conflict in
325 * the libpldm public API this presents a problem: Naively attempting to use the
326 * msgbuf APIs on a member of a packed struct would yield an error.
327 *
328 * The msgbuf APIs are implemented such that data is moved through unaligned
329 * pointers in a safe way, but to mitigate `-Waddress-of-packed-member` we must
330 * make the object pointers take a trip through `void *` at its API boundary.
331 * That presents a bit too much of an opportunity to non-surgically remove your
332 * own foot, so here we set about doing something to mitigate that as well.
333 *
334 * pldm_msgbuf_extract_typecheck() exists to enforce pointer type correctness
335 * only for the purpose of object sizes, disregarding alignment. We have a few
336 * constraints that cause some headaches:
337 *
338 * 1. We have to perform the type-check before a call through a C function,
339 * as the function must take the object pointer argument as `void *`.
340 * Essentially, this constrains us to doing something with macros.
341 *
342 * 2. While libpldm is a C library, its test suite is written in C++ to take
343 * advantage of gtest.
344 *
345 * 3. Ideally we'd do something with C's `static_assert()`, however
346 * `static_assert()` is defined as void, and as we're constrained to macros,
347 * using `static_assert()` would require a statement-expression
348 *
349 * 4. Currently the project is built with `-std=c17`. CPP statement-expressions
350 * are a GNU extension. We prefer to avoid switching to `-std=gnu17` just for
351 * the purpose of enabling statement-expressions in this one instance.
352 *
353 * 5. We can achieve a conditional build error using `pldm_require_obj_type()`,
354 * however it's implemented in terms of `_Generic()`, which is not available
355 * in C++.
356 *
357 * Combined this means we need separate solutions for C and C++.
358 *
359 * For C, as we don't have statement-expressions, we need to exploit some other
360 * language feature to inject a `pldm_require_obj_type()` prior to the msgbuf
361 * API function call. We also have to take care of the fact that the call-sites
362 * may be in the context of a variable assignment for error-handling purposes.
363 * The key observation is that we can use the comma operator as a sequence point
364 * to order the type check before the API call, discarding the "result" value of
365 * the type check and yielding the return value of the API call.
366 *
367 * C++ could be less of a headache than the C as we can leverage template
368 * functions. An advantage of template functions is that while their definition
369 * is driven by instantion, the definition does not appear at the source
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +0530370 * location of the instantiation, which gives it a great leg-up over the problems
Andrew Jeffery66c77232024-04-24 11:42:02 +0930371 * we have in the C path. However, the use of the msgbuf APIs in the test suite
372 * still makes things somewhat tricky, as the call-sites in the test suite are
373 * wrapped up in EXPECT_*() gtest macros. Ideally we'd implement functions that
374 * takes both the object type and the required type as template arguments, and
375 * then define the object pointer parameter as `void *` for a call through to
376 * the appropriate msgbuf API. However, because the msgbuf API call-sites are
377 * encapsulated in gtest macros, use of commas in the template specification
378 * causes pre-processor confusion. In this way we're constrained to only one
379 * template argument per function.
380 *
381 * Implement the C++ path using template functions that take the destination
382 * object type as a template argument, while the name of the function symbols
383 * are derived from the required type. The manual implementations of these
384 * appear at the end of the header. The type safety is actually enforced
385 * by `static_assert()` this time, as we can use statements as we're not
386 * constrained to an expression in the templated function body.
387 *
388 * The invocations of pldm_msgbuf_extract_typecheck() typically result in
389 * double-evaluation of some arguments. We're not yet bothered by this for two
390 * reasons:
391 *
392 * 1. The nature of the current call-sites are such that there are no
393 * argument expressions that result in undesirable side-effects
394 *
395 * 2. It's an API internal to the libpldm implementation, and we can fix things
396 * whenever something crops up the violates the observation in 1.
397 */
398#ifdef __cplusplus
399#define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...) \
400 pldm_msgbuf_typecheck_##ty<decltype(dst)>(__VA_ARGS__)
401#else
402#define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...) \
403 (pldm_require_obj_type(dst, ty), fn(__VA_ARGS__))
404#endif
405
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930406/**
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030407 * @brief pldm_msgbuf extractor for a uint8_t
408 *
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +0530409 * @param[in,out] ctx - pldm_msgbuf context for extractor
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030410 * @param[out] dst - destination of extracted value
411 *
412 * @return PLDM_SUCCESS if buffer accesses were in-bounds,
413 * PLDM_ERROR_INVALID_LENGTH otherwise.
414 * PLDM_ERROR_INVALID_DATA if input a invalid ctx
415 */
Andrew Jeffery66c77232024-04-24 11:42:02 +0930416#define pldm_msgbuf_extract_uint8(ctx, dst) \
417 pldm_msgbuf_extract_typecheck(uint8_t, pldm__msgbuf_extract_uint8, \
418 dst, ctx, dst)
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300419LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300420LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930421// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930422pldm__msgbuf_extract_uint8(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030423{
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300424 if (!ctx->cursor) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930425 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030426 }
427
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930428 if (ctx->remaining == INTMAX_MIN) {
429 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930430 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930431 }
Andrew Jeffery66c77232024-04-24 11:42:02 +0930432 ctx->remaining -= sizeof(uint8_t);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030433 assert(ctx->remaining >= 0);
434 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930435 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030436 }
437
Andrew Jeffery66c77232024-04-24 11:42:02 +0930438 memcpy(dst, ctx->cursor, sizeof(uint8_t));
439
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030440 ctx->cursor++;
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930441 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030442}
443
Andrew Jeffery66c77232024-04-24 11:42:02 +0930444#define pldm_msgbuf_extract_int8(ctx, dst) \
445 pldm_msgbuf_extract_typecheck(int8_t, pldm__msgbuf_extract_int8, dst, \
446 ctx, dst)
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300447LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300448LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930449// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930450pldm__msgbuf_extract_int8(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030451{
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300452 if (!ctx->cursor) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930453 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030454 }
455
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930456 if (ctx->remaining == INTMAX_MIN) {
457 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930458 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930459 }
Andrew Jeffery66c77232024-04-24 11:42:02 +0930460 ctx->remaining -= sizeof(int8_t);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030461 assert(ctx->remaining >= 0);
462 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930463 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030464 }
465
Andrew Jeffery66c77232024-04-24 11:42:02 +0930466 memcpy(dst, ctx->cursor, sizeof(int8_t));
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030467 ctx->cursor++;
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930468 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030469}
470
Andrew Jeffery66c77232024-04-24 11:42:02 +0930471#define pldm_msgbuf_extract_uint16(ctx, dst) \
472 pldm_msgbuf_extract_typecheck(uint16_t, pldm__msgbuf_extract_uint16, \
473 dst, ctx, dst)
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300474LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300475LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930476// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930477pldm__msgbuf_extract_uint16(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030478{
479 uint16_t ldst;
480
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300481 if (!ctx->cursor) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930482 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030483 }
484
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930485 // Check for underflow while tracking the magnitude of the buffer overflow
486 static_assert(
487 // NOLINTNEXTLINE(bugprone-sizeof-expression)
488 sizeof(ldst) < INTMAX_MAX,
489 "The following addition may not uphold the runtime assertion");
490 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
491 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930492 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930493 }
494
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030495 // Check for buffer overflow. If we overflow, account for the request as
496 // negative values in ctx->remaining. This way we can debug how far
497 // we've overflowed.
498 ctx->remaining -= sizeof(ldst);
499
500 // Prevent the access if it would overflow. First, assert so we blow up
501 // the test suite right at the point of failure. However, cater to
502 // -DNDEBUG by explicitly testing that the access is valid.
503 assert(ctx->remaining >= 0);
504 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930505 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030506 }
507
508 // Use memcpy() to have the compiler deal with any alignment
509 // issues on the target architecture
510 memcpy(&ldst, ctx->cursor, sizeof(ldst));
511
512 // Only assign the target value once it's correctly decoded
Andrew Jeffery66c77232024-04-24 11:42:02 +0930513 ldst = le16toh(ldst);
514
515 // Allow storing to unaligned
516 memcpy(dst, &ldst, sizeof(ldst));
517
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030518 ctx->cursor += sizeof(ldst);
519
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930520 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030521}
522
Andrew Jeffery66c77232024-04-24 11:42:02 +0930523#define pldm_msgbuf_extract_int16(ctx, dst) \
524 pldm_msgbuf_extract_typecheck(int16_t, pldm__msgbuf_extract_int16, \
525 dst, ctx, dst)
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300526LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300527LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930528// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930529pldm__msgbuf_extract_int16(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030530{
531 int16_t ldst;
532
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300533 if (!ctx->cursor) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930534 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030535 }
536
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930537 static_assert(
538 // NOLINTNEXTLINE(bugprone-sizeof-expression)
539 sizeof(ldst) < INTMAX_MAX,
540 "The following addition may not uphold the runtime assertion");
541 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
542 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930543 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930544 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030545 ctx->remaining -= sizeof(ldst);
546 assert(ctx->remaining >= 0);
547 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930548 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030549 }
550
551 memcpy(&ldst, ctx->cursor, sizeof(ldst));
552
Andrew Jeffery66c77232024-04-24 11:42:02 +0930553 ldst = le16toh(ldst);
554 memcpy(dst, &ldst, sizeof(ldst));
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030555 ctx->cursor += sizeof(ldst);
556
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930557 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030558}
559
Andrew Jeffery66c77232024-04-24 11:42:02 +0930560#define pldm_msgbuf_extract_uint32(ctx, dst) \
561 pldm_msgbuf_extract_typecheck(uint32_t, pldm__msgbuf_extract_uint32, \
562 dst, ctx, dst)
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300563LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300564LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930565// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930566pldm__msgbuf_extract_uint32(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030567{
568 uint32_t ldst;
569
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300570 if (!ctx->cursor) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930571 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030572 }
573
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930574 static_assert(
575 // NOLINTNEXTLINE(bugprone-sizeof-expression)
576 sizeof(ldst) < INTMAX_MAX,
577 "The following addition may not uphold the runtime assertion");
578 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
579 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930580 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930581 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030582 ctx->remaining -= sizeof(ldst);
583 assert(ctx->remaining >= 0);
584 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930585 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030586 }
587
588 memcpy(&ldst, ctx->cursor, sizeof(ldst));
Andrew Jeffery66c77232024-04-24 11:42:02 +0930589 ldst = le32toh(ldst);
590 memcpy(dst, &ldst, sizeof(ldst));
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030591 ctx->cursor += sizeof(ldst);
592
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930593 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030594}
595
Andrew Jeffery66c77232024-04-24 11:42:02 +0930596#define pldm_msgbuf_extract_int32(ctx, dst) \
597 pldm_msgbuf_extract_typecheck(int32_t, pldm__msgbuf_extract_int32, \
598 dst, ctx, dst)
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300599LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300600LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930601// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930602pldm__msgbuf_extract_int32(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030603{
604 int32_t ldst;
605
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300606 if (!ctx->cursor) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930607 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030608 }
609
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930610 static_assert(
611 // NOLINTNEXTLINE(bugprone-sizeof-expression)
612 sizeof(ldst) < INTMAX_MAX,
613 "The following addition may not uphold the runtime assertion");
614 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
615 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930616 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930617 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030618 ctx->remaining -= sizeof(ldst);
619 assert(ctx->remaining >= 0);
620 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930621 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030622 }
623
624 memcpy(&ldst, ctx->cursor, sizeof(ldst));
Andrew Jeffery66c77232024-04-24 11:42:02 +0930625 ldst = le32toh(ldst);
626 memcpy(dst, &ldst, sizeof(ldst));
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030627 ctx->cursor += sizeof(ldst);
628
629 return PLDM_SUCCESS;
630}
631
Andrew Jeffery66c77232024-04-24 11:42:02 +0930632#define pldm_msgbuf_extract_real32(ctx, dst) \
633 pldm_msgbuf_extract_typecheck(real32_t, pldm__msgbuf_extract_real32, \
634 dst, ctx, dst)
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300635LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300636LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930637// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930638pldm__msgbuf_extract_real32(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030639{
640 uint32_t ldst;
641
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930642 static_assert(sizeof(real32_t) == sizeof(ldst),
643 "Mismatched type sizes for dst and ldst");
Andrew Jeffery66c77232024-04-24 11:42:02 +0930644
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300645 if (!ctx->cursor) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930646 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030647 }
648
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930649 static_assert(
650 // NOLINTNEXTLINE(bugprone-sizeof-expression)
651 sizeof(ldst) < INTMAX_MAX,
652 "The following addition may not uphold the runtime assertion");
653 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
654 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930655 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930656 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030657 ctx->remaining -= sizeof(ldst);
658 assert(ctx->remaining >= 0);
659 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930660 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030661 }
662
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030663 memcpy(&ldst, ctx->cursor, sizeof(ldst));
664 ldst = le32toh(ldst);
Andrew Jeffery66c77232024-04-24 11:42:02 +0930665 memcpy(dst, &ldst, sizeof(ldst));
666 ctx->cursor += sizeof(ldst);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030667
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930668 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030669}
670
Andrew Jeffery66c77232024-04-24 11:42:02 +0930671/**
672 * Extract the field at the msgbuf cursor into the lvalue named by dst.
673 *
674 * @param ctx The msgbuf context object
675 * @param dst The lvalue into which the field at the msgbuf cursor should be
676 * extracted
677 *
678 * @return PLDM_SUCCESS on success, otherwise another value on error
679 */
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030680#define pldm_msgbuf_extract(ctx, dst) \
Andrew Jeffery66c77232024-04-24 11:42:02 +0930681 _Generic((dst), \
682 uint8_t: pldm__msgbuf_extract_uint8, \
683 int8_t: pldm__msgbuf_extract_int8, \
684 uint16_t: pldm__msgbuf_extract_uint16, \
685 int16_t: pldm__msgbuf_extract_int16, \
686 uint32_t: pldm__msgbuf_extract_uint32, \
687 int32_t: pldm__msgbuf_extract_int32, \
688 real32_t: pldm__msgbuf_extract_real32)(ctx, (void *)&(dst))
689
690/**
691 * Extract the field at the msgbuf cursor into the object pointed-to by dst.
692 *
693 * @param ctx The msgbuf context object
694 * @param dst The pointer to the object into which the field at the msgbuf
695 * cursor should be extracted
696 *
697 * @return PLDM_SUCCESS on success, otherwise another value on error
698 */
699#define pldm_msgbuf_extract_p(ctx, dst) \
700 _Generic((dst), \
701 uint8_t *: pldm__msgbuf_extract_uint8, \
702 int8_t *: pldm__msgbuf_extract_int8, \
703 uint16_t *: pldm__msgbuf_extract_uint16, \
704 int16_t *: pldm__msgbuf_extract_int16, \
705 uint32_t *: pldm__msgbuf_extract_uint32, \
706 int32_t *: pldm__msgbuf_extract_int32, \
707 real32_t *: pldm__msgbuf_extract_real32)(ctx, dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030708
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000709/**
710 * @ref pldm_msgbuf_extract_array
711 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300712LIBPLDM_CC_NONNULL
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000713LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300714LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery1c571442024-07-08 10:25:48 +0930715// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000716pldm__msgbuf_extract_array_void(struct pldm_msgbuf *ctx, size_t count,
717 void *dst, size_t dst_count)
Andrew Jeffery369b1212023-04-20 15:44:48 +0930718{
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300719 if (!ctx->cursor || count > dst_count) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930720 return pldm_msgbuf_status(ctx, EINVAL);
Andrew Jeffery369b1212023-04-20 15:44:48 +0930721 }
722
723 if (!count) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930724 return 0;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930725 }
726
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930727#if INTMAX_MAX < SIZE_MAX
728 if (count > INTMAX_MAX) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930729 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery369b1212023-04-20 15:44:48 +0930730 }
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930731#endif
Andrew Jeffery369b1212023-04-20 15:44:48 +0930732
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930733 if (ctx->remaining < INTMAX_MIN + (intmax_t)count) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930734 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930735 }
736 ctx->remaining -= (intmax_t)count;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930737 assert(ctx->remaining >= 0);
738 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930739 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery369b1212023-04-20 15:44:48 +0930740 }
741
Andrew Jefferya065ecc2023-10-27 15:02:11 +1030742 memcpy(dst, ctx->cursor, count);
743 ctx->cursor += count;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930744
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930745 return 0;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930746}
747
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000748/**
749 * @ref pldm_msgbuf_extract_array
750 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300751LIBPLDM_CC_NONNULL
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000752LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300753LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000754pldm_msgbuf_extract_array_char(struct pldm_msgbuf *ctx, size_t count, char *dst,
755 size_t dst_count)
Andrew Jeffery1c571442024-07-08 10:25:48 +0930756{
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000757 return pldm__msgbuf_extract_array_void(ctx, count, dst, dst_count);
Andrew Jeffery1c571442024-07-08 10:25:48 +0930758}
759
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000760/**
761 * @ref pldm_msgbuf_extract_array
762 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300763LIBPLDM_CC_NONNULL
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000764LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300765LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000766pldm_msgbuf_extract_array_uint8(struct pldm_msgbuf *ctx, size_t count,
767 uint8_t *dst, size_t dst_count)
Andrew Jeffery1c571442024-07-08 10:25:48 +0930768{
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000769 return pldm__msgbuf_extract_array_void(ctx, count, dst, dst_count);
Andrew Jeffery1c571442024-07-08 10:25:48 +0930770}
771
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000772/**
773 * Extract an array of data from the msgbuf instance
774 *
775 * @param ctx - The msgbuf instance from which to extract an array of data
776 * @param count - The number of array elements to extract
777 * @param dst - The array object into which elements from @p ctx should be
778 extracted
779 * @param dst_count - The maximum number of elements to place into @p dst
780 *
781 * Note that both @p count and @p dst_count can only be counted by `sizeof` for
782 * arrays where `sizeof(*dst) == 1` holds. Specifically, they count the number
783 * of array elements and _not_ the object size of the array.
784 */
785#define pldm_msgbuf_extract_array(ctx, count, dst, dst_count) \
Andrew Jeffery1c571442024-07-08 10:25:48 +0930786 _Generic((*(dst)), \
787 uint8_t: pldm_msgbuf_extract_array_uint8, \
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000788 char: pldm_msgbuf_extract_array_char)(ctx, count, dst, \
789 dst_count)
Andrew Jeffery369b1212023-04-20 15:44:48 +0930790
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300791LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300792LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_uint32(struct pldm_msgbuf *ctx,
793 const uint32_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700794{
795 uint32_t val = htole32(src);
796
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930797 if (!ctx->cursor) {
798 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700799 }
800
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930801 static_assert(
802 // NOLINTNEXTLINE(bugprone-sizeof-expression)
803 sizeof(src) < INTMAX_MAX,
804 "The following addition may not uphold the runtime assertion");
805 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
806 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930807 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930808 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700809 ctx->remaining -= sizeof(src);
810 assert(ctx->remaining >= 0);
811 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930812 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700813 }
814
815 memcpy(ctx->cursor, &val, sizeof(val));
816 ctx->cursor += sizeof(src);
817
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930818 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700819}
820
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300821LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300822LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_uint16(struct pldm_msgbuf *ctx,
823 const uint16_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700824{
825 uint16_t val = htole16(src);
826
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930827 if (!ctx->cursor) {
828 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700829 }
830
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930831 static_assert(
832 // NOLINTNEXTLINE(bugprone-sizeof-expression)
833 sizeof(src) < INTMAX_MAX,
834 "The following addition may not uphold the runtime assertion");
835 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
836 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930837 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930838 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700839 ctx->remaining -= sizeof(src);
840 assert(ctx->remaining >= 0);
841 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930842 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700843 }
844
845 memcpy(ctx->cursor, &val, sizeof(val));
846 ctx->cursor += sizeof(src);
847
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930848 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700849}
850
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300851LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300852LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_uint8(struct pldm_msgbuf *ctx,
853 const uint8_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700854{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930855 if (!ctx->cursor) {
856 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700857 }
858
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930859 static_assert(
860 // NOLINTNEXTLINE(bugprone-sizeof-expression)
861 sizeof(src) < INTMAX_MAX,
862 "The following addition may not uphold the runtime assertion");
863 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
864 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930865 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930866 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700867 ctx->remaining -= sizeof(src);
868 assert(ctx->remaining >= 0);
869 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930870 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700871 }
872
873 memcpy(ctx->cursor, &src, sizeof(src));
874 ctx->cursor += sizeof(src);
875
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930876 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700877}
878
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300879LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300880LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_int32(struct pldm_msgbuf *ctx,
881 const int32_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700882{
883 int32_t val = htole32(src);
884
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930885 if (!ctx->cursor) {
886 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700887 }
888
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930889 static_assert(
890 // NOLINTNEXTLINE(bugprone-sizeof-expression)
891 sizeof(src) < INTMAX_MAX,
892 "The following addition may not uphold the runtime assertion");
893 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
894 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930895 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930896 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700897 ctx->remaining -= sizeof(src);
898 assert(ctx->remaining >= 0);
899 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930900 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700901 }
902
903 memcpy(ctx->cursor, &val, sizeof(val));
904 ctx->cursor += sizeof(src);
905
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930906 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700907}
908
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300909LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300910LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_int16(struct pldm_msgbuf *ctx,
911 const int16_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700912{
913 int16_t val = htole16(src);
914
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930915 if (!ctx->cursor) {
916 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700917 }
918
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930919 static_assert(
920 // NOLINTNEXTLINE(bugprone-sizeof-expression)
921 sizeof(src) < INTMAX_MAX,
922 "The following addition may not uphold the runtime assertion");
923 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
924 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930925 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930926 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700927 ctx->remaining -= sizeof(src);
928 assert(ctx->remaining >= 0);
929 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930930 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700931 }
932
933 memcpy(ctx->cursor, &val, sizeof(val));
934 ctx->cursor += sizeof(src);
935
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930936 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700937}
938
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300939LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300940LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_int8(struct pldm_msgbuf *ctx,
941 const int8_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700942{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930943 if (!ctx->cursor) {
944 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700945 }
946
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930947 static_assert(
948 // NOLINTNEXTLINE(bugprone-sizeof-expression)
949 sizeof(src) < INTMAX_MAX,
950 "The following addition may not uphold the runtime assertion");
951 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
952 assert(ctx->remaining < 0);
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930953 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930954 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700955 ctx->remaining -= sizeof(src);
956 assert(ctx->remaining >= 0);
957 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930958 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700959 }
960
961 memcpy(ctx->cursor, &src, sizeof(src));
962 ctx->cursor += sizeof(src);
963
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930964 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700965}
966
967#define pldm_msgbuf_insert(dst, src) \
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930968 _Generic((src), \
969 uint8_t: pldm_msgbuf_insert_uint8, \
970 int8_t: pldm_msgbuf_insert_int8, \
971 uint16_t: pldm_msgbuf_insert_uint16, \
972 int16_t: pldm_msgbuf_insert_int16, \
973 uint32_t: pldm_msgbuf_insert_uint32, \
974 int32_t: pldm_msgbuf_insert_int32)(dst, src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700975
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000976/**
977 * @ref pldm_msgbuf_insert_array
978 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300979LIBPLDM_CC_NONNULL
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000980LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300981LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery1c571442024-07-08 10:25:48 +0930982// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000983pldm__msgbuf_insert_array_void(struct pldm_msgbuf *ctx, size_t count,
984 const void *src, size_t src_count)
Thu Nguyen062c8762023-04-22 20:45:04 +0700985{
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300986 if (!ctx->cursor || count > src_count) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930987 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +0700988 }
989
990 if (!count) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930991 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700992 }
993
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930994#if INTMAX_MAX < SIZE_MAX
995 if (count > INTMAX_MAX) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930996 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +0700997 }
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930998#endif
Thu Nguyen062c8762023-04-22 20:45:04 +0700999
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +09301000 if (ctx->remaining < INTMAX_MIN + (intmax_t)count) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301001 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +09301002 }
1003 ctx->remaining -= (intmax_t)count;
Thu Nguyen062c8762023-04-22 20:45:04 +07001004 assert(ctx->remaining >= 0);
1005 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301006 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +07001007 }
1008
Andrew Jefferya065ecc2023-10-27 15:02:11 +10301009 memcpy(ctx->cursor, src, count);
1010 ctx->cursor += count;
Thu Nguyen062c8762023-04-22 20:45:04 +07001011
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301012 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +07001013}
1014
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001015/**
1016 * @ref pldm_msgbuf_insert_array
1017 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +03001018LIBPLDM_CC_NONNULL
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001019LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jefferycb569bc2024-09-01 09:38:09 +03001020LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001021pldm_msgbuf_insert_array_char(struct pldm_msgbuf *ctx, size_t count,
1022 const char *src, size_t src_count)
Andrew Jeffery1c571442024-07-08 10:25:48 +09301023{
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001024 return pldm__msgbuf_insert_array_void(ctx, count, src, src_count);
Andrew Jeffery1c571442024-07-08 10:25:48 +09301025}
1026
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001027/**
1028 * @ref pldm_msgbuf_insert_array
1029 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +03001030LIBPLDM_CC_NONNULL
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001031LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jefferycb569bc2024-09-01 09:38:09 +03001032LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001033pldm_msgbuf_insert_array_uint8(struct pldm_msgbuf *ctx, size_t count,
1034 const uint8_t *src, size_t src_count)
Andrew Jeffery1c571442024-07-08 10:25:48 +09301035{
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001036 return pldm__msgbuf_insert_array_void(ctx, count, src, src_count);
Andrew Jeffery1c571442024-07-08 10:25:48 +09301037}
1038
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001039/**
1040 * Insert an array of data into the msgbuf instance
1041 *
1042 * @param ctx - The msgbuf instance into which the array of data should be
1043 * inserted
1044 * @param count - The number of array elements to insert
1045 * @param src - The array object from which elements should be inserted into
1046 @p ctx
1047 * @param src_count - The maximum number of elements to insert from @p src
1048 *
1049 * Note that both @p count and @p src_count can only be counted by `sizeof` for
1050 * arrays where `sizeof(*dst) == 1` holds. Specifically, they count the number
1051 * of array elements and _not_ the object size of the array.
1052 */
1053#define pldm_msgbuf_insert_array(dst, count, src, src_count) \
Andrew Jeffery1c571442024-07-08 10:25:48 +09301054 _Generic((*(src)), \
1055 uint8_t: pldm_msgbuf_insert_array_uint8, \
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001056 char: pldm_msgbuf_insert_array_char)(dst, count, src, \
1057 src_count)
Thu Nguyen062c8762023-04-22 20:45:04 +07001058
Varsha Kaverappa79393822024-08-07 00:40:13 -05001059LIBPLDM_CC_NONNULL_ARGS(1)
Andrew Jefferycb569bc2024-09-01 09:38:09 +03001060LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_span_required(struct pldm_msgbuf *ctx,
1061 size_t required,
1062 void **cursor)
Thu Nguyen062c8762023-04-22 20:45:04 +07001063{
Varsha Kaverappa79393822024-08-07 00:40:13 -05001064 if (!ctx->cursor || (cursor && *cursor)) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301065 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +07001066 }
1067
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +09301068#if INTMAX_MAX < SIZE_MAX
1069 if (required > INTMAX_MAX) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301070 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +07001071 }
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +09301072#endif
Thu Nguyen062c8762023-04-22 20:45:04 +07001073
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +09301074 if (ctx->remaining < INTMAX_MIN + (intmax_t)required) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301075 return pldm_msgbuf_status(ctx, EOVERFLOW);
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +09301076 }
1077 ctx->remaining -= (intmax_t)required;
Thu Nguyen062c8762023-04-22 20:45:04 +07001078 assert(ctx->remaining >= 0);
1079 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301080 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +07001081 }
1082
Varsha Kaverappa79393822024-08-07 00:40:13 -05001083 if (cursor) {
1084 *cursor = ctx->cursor;
1085 }
Thu Nguyen062c8762023-04-22 20:45:04 +07001086 ctx->cursor += required;
1087
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301088 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +07001089}
1090
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +03001091LIBPLDM_CC_NONNULL_ARGS(1)
Andrew Jefferycb569bc2024-09-01 09:38:09 +03001092LIBPLDM_CC_ALWAYS_INLINE int
Thu Nguyen9c83d682024-07-02 08:43:09 +00001093pldm_msgbuf_span_string_ascii(struct pldm_msgbuf *ctx, void **cursor,
1094 size_t *length)
1095{
1096 intmax_t measured;
1097
Thu Nguyen9c83d682024-07-02 08:43:09 +00001098 if (!ctx->cursor || (cursor && *cursor)) {
1099 return pldm_msgbuf_status(ctx, EINVAL);
1100 }
1101
1102 if (ctx->remaining < 0) {
1103 /* Tracking the amount of overflow gets disturbed here */
1104 return pldm_msgbuf_status(ctx, EOVERFLOW);
1105 }
1106
1107 measured = (intmax_t)strnlen((const char *)ctx->cursor, ctx->remaining);
1108 if (measured == ctx->remaining) {
1109 /*
1110 * We have hit the end of the buffer prior to the NUL terminator.
1111 * Optimistically, the NUL terminator was one-beyond-the-end. Setting
1112 * ctx->remaining negative ensures the `pldm_msgbuf_destroy*()` APIs also
1113 * return an error.
1114 */
1115 ctx->remaining = -1;
1116 return pldm_msgbuf_status(ctx, EOVERFLOW);
1117 }
1118
1119 /* Include the NUL terminator in the span length, as spans are opaque */
1120 measured++;
1121
1122 if (ctx->remaining < INTMAX_MIN + measured) {
1123 return pldm_msgbuf_status(ctx, EOVERFLOW);
1124 }
1125
1126 ctx->remaining -= measured;
1127 assert(ctx->remaining >= 0);
1128 if (ctx->remaining < 0) {
1129 return pldm_msgbuf_status(ctx, EOVERFLOW);
1130 }
1131
1132 if (cursor) {
1133 *cursor = ctx->cursor;
1134 }
1135
1136 ctx->cursor += measured;
1137
1138 if (length) {
1139 *length = measured;
1140 }
1141
1142 return 0;
1143}
1144
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +03001145LIBPLDM_CC_NONNULL_ARGS(1)
Andrew Jefferycb569bc2024-09-01 09:38:09 +03001146LIBPLDM_CC_ALWAYS_INLINE int
Thu Nguyen15237782024-07-02 09:30:41 +00001147pldm_msgbuf_span_string_utf16(struct pldm_msgbuf *ctx, void **cursor,
1148 size_t *length)
1149{
1150 static const char16_t term = 0;
1151 ptrdiff_t measured;
1152 void *end;
1153
Thu Nguyen15237782024-07-02 09:30:41 +00001154 if (!ctx->cursor || (cursor && *cursor)) {
1155 return pldm_msgbuf_status(ctx, EINVAL);
1156 }
1157
1158 if (ctx->remaining < 0) {
1159 /* Tracking the amount of overflow gets disturbed here */
1160 return pldm_msgbuf_status(ctx, EOVERFLOW);
1161 }
1162
1163 /*
1164 * Avoid tripping up on UTF16-LE: We may have consecutive NUL _bytes_ that do
1165 * not form a UTF16 NUL _code-point_ due to alignment with respect to the
1166 * start of the string
1167 */
Andrew Jeffery2b440d42024-07-25 10:36:08 +09301168 end = ctx->cursor;
Thu Nguyen15237782024-07-02 09:30:41 +00001169 do {
1170 if (end != ctx->cursor) {
1171 /*
1172 * If we've looped we've found a relatively-unaligned NUL code-point.
1173 * Scan again from a relatively-aligned start point.
1174 */
1175 end = (char *)end + 1;
1176 }
1177 measured = (char *)end - (char *)ctx->cursor;
Andrew Jeffery2b440d42024-07-25 10:36:08 +09301178 end = memmem(end, ctx->remaining - measured, &term,
1179 sizeof(term));
Thu Nguyen15237782024-07-02 09:30:41 +00001180 } while (end && ((uintptr_t)end & 1) != ((uintptr_t)ctx->cursor & 1));
1181
1182 if (!end) {
1183 /*
1184 * Optimistically, the last required pattern byte was one beyond the end of
1185 * the buffer. Setting ctx->remaining negative ensures the
1186 * `pldm_msgbuf_destroy*()` APIs also return an error.
1187 */
1188 ctx->remaining = -1;
1189 return pldm_msgbuf_status(ctx, EOVERFLOW);
1190 }
1191
1192 end = (char *)end + sizeof(char16_t);
1193 measured = (char *)end - (char *)ctx->cursor;
1194
1195#if INTMAX_MAX < PTRDIFF_MAX
1196 if (measured >= INTMAX_MAX) {
1197 return pldm_msgbuf_status(ctx, EOVERFLOW);
1198 }
1199#endif
1200
1201 if (ctx->remaining < INTMAX_MIN + (intmax_t)measured) {
1202 assert(ctx->remaining < 0);
1203 return pldm_msgbuf_status(ctx, EOVERFLOW);
1204 }
1205
1206 ctx->remaining -= (intmax_t)measured;
1207 assert(ctx->remaining >= 0);
1208 if (ctx->remaining < 0) {
1209 return pldm_msgbuf_status(ctx, EOVERFLOW);
1210 }
1211
1212 if (cursor) {
1213 *cursor = ctx->cursor;
1214 }
1215
1216 ctx->cursor += measured;
1217
1218 if (length) {
1219 *length = (size_t)measured;
1220 }
1221
1222 return 0;
1223}
1224
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +03001225LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +03001226LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery76712f62024-05-22 15:19:00 +09301227pldm_msgbuf_span_remaining(struct pldm_msgbuf *ctx, void **cursor, size_t *len)
Thu Nguyen062c8762023-04-22 20:45:04 +07001228{
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +03001229 if (!ctx->cursor || *cursor) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301230 return pldm_msgbuf_status(ctx, EINVAL);
Thu Nguyen062c8762023-04-22 20:45:04 +07001231 }
1232
1233 assert(ctx->remaining >= 0);
1234 if (ctx->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301235 return pldm_msgbuf_status(ctx, EOVERFLOW);
Thu Nguyen062c8762023-04-22 20:45:04 +07001236 }
1237
1238 *cursor = ctx->cursor;
1239 ctx->cursor += ctx->remaining;
1240 *len = ctx->remaining;
1241 ctx->remaining = 0;
1242
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301243 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +07001244}
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001245
1246/**
1247 * @brief pldm_msgbuf copy data between two msg buffers
1248 *
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +05301249 * @param[in,out] src - pldm_msgbuf for source from where value should be copied
1250 * @param[in,out] dst - destination of copy from source
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001251 * @param[in] size - size of data to be copied
1252 * @param[in] description - description of data copied
1253 *
1254 * @return PLDM_SUCCESS if buffer accesses were in-bounds,
1255 * PLDM_ERROR_INVALID_LENGTH otherwise.
1256 * PLDM_ERROR_INVALID_DATA if input is invalid
1257 */
1258#define pldm_msgbuf_copy(dst, src, type, name) \
1259 pldm__msgbuf_copy(dst, src, sizeof(type), #name)
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +03001260LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +03001261LIBPLDM_CC_ALWAYS_INLINE int
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001262// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +09301263pldm__msgbuf_copy(struct pldm_msgbuf *dst, struct pldm_msgbuf *src, size_t size,
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +03001264 const char *description LIBPLDM_CC_UNUSED)
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001265{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301266 assert(src->mode == dst->mode);
1267
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +03001268 if (!src->cursor || !dst->cursor) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301269 return pldm_msgbuf_status(dst, EINVAL);
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001270 }
1271
1272#if INTMAX_MAX < SIZE_MAX
1273 if (size > INTMAX_MAX) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301274 return pldm_msgbuf_status(dst, EOVERFLOW);
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001275 }
1276#endif
1277
1278 if (src->remaining < INTMAX_MIN + (intmax_t)size) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301279 return pldm_msgbuf_status(dst, EOVERFLOW);
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001280 }
1281
1282 if (dst->remaining < INTMAX_MIN + (intmax_t)size) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301283 return pldm_msgbuf_status(dst, EOVERFLOW);
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001284 }
1285
1286 src->remaining -= (intmax_t)size;
1287 assert(src->remaining >= 0);
1288 if (src->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301289 return pldm_msgbuf_status(dst, EOVERFLOW);
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001290 }
1291
1292 dst->remaining -= (intmax_t)size;
1293 assert(dst->remaining >= 0);
1294 if (dst->remaining < 0) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301295 return pldm_msgbuf_status(dst, EOVERFLOW);
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001296 }
1297
1298 memcpy(dst->cursor, src->cursor, size);
1299 src->cursor += size;
1300 dst->cursor += size;
1301
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301302 return 0;
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001303}
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301304
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +03001305LIBPLDM_CC_NONNULL
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001306LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jefferycb569bc2024-09-01 09:38:09 +03001307LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery8b879602024-07-08 12:50:19 +09301308pldm_msgbuf_copy_string_ascii(struct pldm_msgbuf *dst, struct pldm_msgbuf *src)
1309{
1310 void *ascii = NULL;
1311 size_t len = 0;
1312 int rc;
1313
1314 rc = pldm_msgbuf_span_string_ascii(src, &ascii, &len);
1315 if (rc < 0) {
1316 return rc;
1317 }
1318
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001319 return pldm__msgbuf_insert_array_void(dst, len, ascii, len);
Andrew Jeffery8b879602024-07-08 12:50:19 +09301320}
1321
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +03001322LIBPLDM_CC_NONNULL
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001323LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jefferycb569bc2024-09-01 09:38:09 +03001324LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery56f73f92024-07-08 12:50:28 +09301325pldm_msgbuf_copy_string_utf16(struct pldm_msgbuf *dst, struct pldm_msgbuf *src)
1326{
1327 void *utf16 = NULL;
1328 size_t len = 0;
1329 int rc;
1330
1331 rc = pldm_msgbuf_span_string_utf16(src, &utf16, &len);
1332 if (rc < 0) {
1333 return rc;
1334 }
1335
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001336 return pldm__msgbuf_insert_array_void(dst, len, utf16, len);
Andrew Jeffery56f73f92024-07-08 12:50:28 +09301337}
1338
Andrew Jefferyc63f63a2023-02-24 22:29:33 +10301339#ifdef __cplusplus
1340}
1341#endif
1342
Andrew Jeffery66c77232024-04-24 11:42:02 +09301343#ifdef __cplusplus
1344#include <type_traits>
1345
1346template <typename T>
1347static inline int pldm_msgbuf_typecheck_uint8_t(struct pldm_msgbuf *ctx,
1348 void *buf)
1349{
1350 static_assert(std::is_same<uint8_t *, T>::value);
1351 return pldm__msgbuf_extract_uint8(ctx, buf);
1352}
1353
1354template <typename T>
1355static inline int pldm_msgbuf_typecheck_int8_t(struct pldm_msgbuf *ctx,
1356 void *buf)
1357{
1358 static_assert(std::is_same<int8_t *, T>::value);
1359 return pldm__msgbuf_extract_int8(ctx, buf);
1360}
1361
1362template <typename T>
1363static inline int pldm_msgbuf_typecheck_uint16_t(struct pldm_msgbuf *ctx,
1364 void *buf)
1365{
1366 static_assert(std::is_same<uint16_t *, T>::value);
1367 return pldm__msgbuf_extract_uint16(ctx, buf);
1368}
1369
1370template <typename T>
1371static inline int pldm_msgbuf_typecheck_int16_t(struct pldm_msgbuf *ctx,
1372 void *buf)
1373{
1374 static_assert(std::is_same<int16_t *, T>::value);
1375 return pldm__msgbuf_extract_int16(ctx, buf);
1376}
1377
1378template <typename T>
1379static inline int pldm_msgbuf_typecheck_uint32_t(struct pldm_msgbuf *ctx,
1380 void *buf)
1381{
1382 static_assert(std::is_same<uint32_t *, T>::value);
1383 return pldm__msgbuf_extract_uint32(ctx, buf);
1384}
1385
1386template <typename T>
1387static inline int pldm_msgbuf_typecheck_int32_t(struct pldm_msgbuf *ctx,
1388 void *buf)
1389{
1390 static_assert(std::is_same<int32_t *, T>::value);
1391 return pldm__msgbuf_extract_int32(ctx, buf);
1392}
1393
1394template <typename T>
1395static inline int pldm_msgbuf_typecheck_real32_t(struct pldm_msgbuf *ctx,
1396 void *buf)
1397{
1398 static_assert(std::is_same<real32_t *, T>::value);
1399 return pldm__msgbuf_extract_real32(ctx, buf);
1400}
1401#endif
1402
Andrew Jefferyc63f63a2023-02-24 22:29:33 +10301403#endif /* BUF_H */