blob: c7871da0a676f2e8864934aa4f33a5347e68a755 [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");
71 int compliance;
Andrew Jeffery860a43d2024-08-23 01:21:58 +000072} build_assertions LIBPLDM_CC_UNUSED;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +093073
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103074struct pldm_msgbuf {
Thu Nguyen062c8762023-04-22 20:45:04 +070075 uint8_t *cursor;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +093076 intmax_t remaining;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103077};
78
Andrew Jefferyd861a682024-06-03 21:43:09 +093079/**
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103080 * @brief Initialize pldm buf struct for buf extractor
81 *
82 * @param[out] ctx - pldm_msgbuf context for extractor
83 * @param[in] minsize - The minimum required length of buffer `buf`
84 * @param[in] buf - buffer to be extracted
85 * @param[in] len - size of buffer
86 *
Andrew Jefferyc8df31c2024-05-21 16:47:43 +093087 * @return 0 on success, otherwise an error code appropriate for the current
88 * personality.
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103089 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +030090LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +030091LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jefferyc8df31c2024-05-21 16:47:43 +093092// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery830c1eb2024-10-04 10:48:10 +093093pldm_msgbuf_init_errno(struct pldm_msgbuf *ctx, size_t minsize, const void *buf,
94 size_t len)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103095{
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +093096 if ((minsize > len)) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +093097 return -EOVERFLOW;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103098 }
99
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930100#if INTMAX_MAX < SIZE_MAX
101 if (len > INTMAX_MAX) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930102 return -EOVERFLOW;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930103 }
104#endif
105
Andrew Jeffery07febdb2024-05-17 14:17:14 +0930106 if ((uintptr_t)buf + len < len) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930107 return -EOVERFLOW;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030108 }
109
110 ctx->cursor = (uint8_t *)buf;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930111 ctx->remaining = (intmax_t)len;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030112
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930113 return 0;
114}
115
116/**
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030117 * @brief Validate buffer overflow state
118 *
119 * @param[in] ctx - pldm_msgbuf context for extractor
120 *
121 * @return PLDM_SUCCESS if there are zero or more bytes of data that remain
122 * unread from the buffer. Otherwise, PLDM_ERROR_INVALID_LENGTH indicates that a
123 * prior accesses would have occurred beyond the bounds of the buffer, and
124 * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid
125 * pointer.
126 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300127LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300128LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_validate(struct pldm_msgbuf *ctx)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030129{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930130 if (ctx->remaining < 0) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930131 return -EOVERFLOW;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030132 }
133
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930134 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030135}
136
137/**
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930138 * @brief Test whether a message buffer has been exactly consumed
139 *
140 * @param[in] ctx - pldm_msgbuf context for extractor
141 *
142 * @return PLDM_SUCCESS iff there are zero bytes of data that remain unread from
143 * the buffer and no overflow has occurred. Otherwise, PLDM_ERROR_INVALID_LENGTH
144 * indicates that an incorrect sequence of accesses have occurred, and
145 * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid
146 * pointer.
147 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300148LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300149LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_consumed(struct pldm_msgbuf *ctx)
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930150{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930151 if (ctx->remaining != 0) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930152 return -EBADMSG;
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930153 }
154
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930155 return 0;
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930156}
157
158/**
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030159 * @brief Destroy the pldm buf
160 *
161 * @param[in] ctx - pldm_msgbuf context for extractor
162 *
163 * @return PLDM_SUCCESS if all buffer accesses were in-bounds,
164 * PLDM_ERROR_INVALID_DATA if the ctx parameter is invalid, or
165 * PLDM_ERROR_INVALID_LENGTH if prior accesses would have occurred beyond the
166 * bounds of the buffer.
167 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300168LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300169LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_destroy(struct pldm_msgbuf *ctx)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030170{
171 int valid;
172
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030173 valid = pldm_msgbuf_validate(ctx);
174
175 ctx->cursor = NULL;
176 ctx->remaining = 0;
177
178 return valid;
179}
180
181/**
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930182 * @brief Destroy the pldm_msgbuf instance, and check that the underlying buffer
183 * has been completely consumed without overflow
184 *
185 * @param[in] ctx - pldm_msgbuf context
186 *
187 * @return PLDM_SUCCESS if all buffer access were in-bounds and completely
188 * consume the underlying buffer. Otherwise, PLDM_ERROR_INVALID_DATA if the ctx
189 * parameter is invalid, or PLDM_ERROR_INVALID_LENGTH if prior accesses would
190 * have occurred byond the bounds of the buffer
191 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300192LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300193LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery76712f62024-05-22 15:19:00 +0930194pldm_msgbuf_destroy_consumed(struct pldm_msgbuf *ctx)
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930195{
196 int consumed;
197
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930198 consumed = pldm_msgbuf_consumed(ctx);
199
200 ctx->cursor = NULL;
201 ctx->remaining = 0;
202
203 return consumed;
204}
205
Andrew Jeffery66c77232024-04-24 11:42:02 +0930206/*
207 * Exploit the pre-processor to perform type checking by macro substitution.
208 *
209 * A C type is defined by its alignment as well as its object
210 * size, and compilers have a hammer to enforce it in the form of
211 * `-Waddress-of-packed-member`. Due to the unpacked/packed struct conflict in
212 * the libpldm public API this presents a problem: Naively attempting to use the
213 * msgbuf APIs on a member of a packed struct would yield an error.
214 *
215 * The msgbuf APIs are implemented such that data is moved through unaligned
216 * pointers in a safe way, but to mitigate `-Waddress-of-packed-member` we must
217 * make the object pointers take a trip through `void *` at its API boundary.
218 * That presents a bit too much of an opportunity to non-surgically remove your
219 * own foot, so here we set about doing something to mitigate that as well.
220 *
221 * pldm_msgbuf_extract_typecheck() exists to enforce pointer type correctness
222 * only for the purpose of object sizes, disregarding alignment. We have a few
223 * constraints that cause some headaches:
224 *
225 * 1. We have to perform the type-check before a call through a C function,
226 * as the function must take the object pointer argument as `void *`.
227 * Essentially, this constrains us to doing something with macros.
228 *
229 * 2. While libpldm is a C library, its test suite is written in C++ to take
230 * advantage of gtest.
231 *
232 * 3. Ideally we'd do something with C's `static_assert()`, however
233 * `static_assert()` is defined as void, and as we're constrained to macros,
234 * using `static_assert()` would require a statement-expression
235 *
236 * 4. Currently the project is built with `-std=c17`. CPP statement-expressions
237 * are a GNU extension. We prefer to avoid switching to `-std=gnu17` just for
238 * the purpose of enabling statement-expressions in this one instance.
239 *
240 * 5. We can achieve a conditional build error using `pldm_require_obj_type()`,
241 * however it's implemented in terms of `_Generic()`, which is not available
242 * in C++.
243 *
244 * Combined this means we need separate solutions for C and C++.
245 *
246 * For C, as we don't have statement-expressions, we need to exploit some other
247 * language feature to inject a `pldm_require_obj_type()` prior to the msgbuf
248 * API function call. We also have to take care of the fact that the call-sites
249 * may be in the context of a variable assignment for error-handling purposes.
250 * The key observation is that we can use the comma operator as a sequence point
251 * to order the type check before the API call, discarding the "result" value of
252 * the type check and yielding the return value of the API call.
253 *
254 * C++ could be less of a headache than the C as we can leverage template
255 * functions. An advantage of template functions is that while their definition
256 * is driven by instantion, the definition does not appear at the source
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +0530257 * location of the instantiation, which gives it a great leg-up over the problems
Andrew Jeffery66c77232024-04-24 11:42:02 +0930258 * we have in the C path. However, the use of the msgbuf APIs in the test suite
259 * still makes things somewhat tricky, as the call-sites in the test suite are
260 * wrapped up in EXPECT_*() gtest macros. Ideally we'd implement functions that
261 * takes both the object type and the required type as template arguments, and
262 * then define the object pointer parameter as `void *` for a call through to
263 * the appropriate msgbuf API. However, because the msgbuf API call-sites are
264 * encapsulated in gtest macros, use of commas in the template specification
265 * causes pre-processor confusion. In this way we're constrained to only one
266 * template argument per function.
267 *
268 * Implement the C++ path using template functions that take the destination
269 * object type as a template argument, while the name of the function symbols
270 * are derived from the required type. The manual implementations of these
271 * appear at the end of the header. The type safety is actually enforced
272 * by `static_assert()` this time, as we can use statements as we're not
273 * constrained to an expression in the templated function body.
274 *
275 * The invocations of pldm_msgbuf_extract_typecheck() typically result in
276 * double-evaluation of some arguments. We're not yet bothered by this for two
277 * reasons:
278 *
279 * 1. The nature of the current call-sites are such that there are no
280 * argument expressions that result in undesirable side-effects
281 *
282 * 2. It's an API internal to the libpldm implementation, and we can fix things
283 * whenever something crops up the violates the observation in 1.
284 */
285#ifdef __cplusplus
286#define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...) \
287 pldm_msgbuf_typecheck_##ty<decltype(dst)>(__VA_ARGS__)
288#else
289#define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...) \
290 (pldm_require_obj_type(dst, ty), fn(__VA_ARGS__))
291#endif
292
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930293/**
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030294 * @brief pldm_msgbuf extractor for a uint8_t
295 *
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +0530296 * @param[in,out] ctx - pldm_msgbuf context for extractor
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030297 * @param[out] dst - destination of extracted value
298 *
299 * @return PLDM_SUCCESS if buffer accesses were in-bounds,
300 * PLDM_ERROR_INVALID_LENGTH otherwise.
301 * PLDM_ERROR_INVALID_DATA if input a invalid ctx
302 */
Andrew Jeffery66c77232024-04-24 11:42:02 +0930303#define pldm_msgbuf_extract_uint8(ctx, dst) \
304 pldm_msgbuf_extract_typecheck(uint8_t, pldm__msgbuf_extract_uint8, \
Andrew Jefferye5f12532024-10-01 12:18:49 +0930305 dst, ctx, (void *)&(dst))
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300306LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300307LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930308// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930309pldm__msgbuf_extract_uint8(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030310{
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300311 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930312 return -EINVAL;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030313 }
314
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930315 if (ctx->remaining == INTMAX_MIN) {
316 assert(ctx->remaining < 0);
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930317 return -EOVERFLOW;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930318 }
Andrew Jeffery66c77232024-04-24 11:42:02 +0930319 ctx->remaining -= sizeof(uint8_t);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030320 assert(ctx->remaining >= 0);
321 if (ctx->remaining < 0) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930322 return -EOVERFLOW;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030323 }
324
Andrew Jeffery66c77232024-04-24 11:42:02 +0930325 memcpy(dst, ctx->cursor, sizeof(uint8_t));
326
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030327 ctx->cursor++;
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930328 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030329}
330
Andrew Jeffery66c77232024-04-24 11:42:02 +0930331#define pldm_msgbuf_extract_int8(ctx, dst) \
332 pldm_msgbuf_extract_typecheck(int8_t, pldm__msgbuf_extract_int8, dst, \
Andrew Jefferye5f12532024-10-01 12:18:49 +0930333 ctx, (void *)&(dst))
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300334LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300335LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930336// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930337pldm__msgbuf_extract_int8(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030338{
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300339 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930340 return -EINVAL;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030341 }
342
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930343 if (ctx->remaining == INTMAX_MIN) {
344 assert(ctx->remaining < 0);
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930345 return -EOVERFLOW;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930346 }
Andrew Jeffery66c77232024-04-24 11:42:02 +0930347 ctx->remaining -= sizeof(int8_t);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030348 assert(ctx->remaining >= 0);
349 if (ctx->remaining < 0) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930350 return -EOVERFLOW;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030351 }
352
Andrew Jeffery66c77232024-04-24 11:42:02 +0930353 memcpy(dst, ctx->cursor, sizeof(int8_t));
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030354 ctx->cursor++;
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930355 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030356}
357
Andrew Jeffery66c77232024-04-24 11:42:02 +0930358#define pldm_msgbuf_extract_uint16(ctx, dst) \
359 pldm_msgbuf_extract_typecheck(uint16_t, pldm__msgbuf_extract_uint16, \
Andrew Jefferye5f12532024-10-01 12:18:49 +0930360 dst, ctx, (void *)&(dst))
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300361LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300362LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930363// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930364pldm__msgbuf_extract_uint16(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030365{
366 uint16_t ldst;
367
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300368 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930369 return -EINVAL;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030370 }
371
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930372 // Check for underflow while tracking the magnitude of the buffer overflow
373 static_assert(
374 // NOLINTNEXTLINE(bugprone-sizeof-expression)
375 sizeof(ldst) < INTMAX_MAX,
376 "The following addition may not uphold the runtime assertion");
377 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
378 assert(ctx->remaining < 0);
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930379 return -EOVERFLOW;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930380 }
381
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030382 // Check for buffer overflow. If we overflow, account for the request as
383 // negative values in ctx->remaining. This way we can debug how far
384 // we've overflowed.
385 ctx->remaining -= sizeof(ldst);
386
387 // Prevent the access if it would overflow. First, assert so we blow up
388 // the test suite right at the point of failure. However, cater to
389 // -DNDEBUG by explicitly testing that the access is valid.
390 assert(ctx->remaining >= 0);
391 if (ctx->remaining < 0) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930392 return -EOVERFLOW;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030393 }
394
395 // Use memcpy() to have the compiler deal with any alignment
396 // issues on the target architecture
397 memcpy(&ldst, ctx->cursor, sizeof(ldst));
398
399 // Only assign the target value once it's correctly decoded
Andrew Jeffery66c77232024-04-24 11:42:02 +0930400 ldst = le16toh(ldst);
401
402 // Allow storing to unaligned
403 memcpy(dst, &ldst, sizeof(ldst));
404
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030405 ctx->cursor += sizeof(ldst);
406
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930407 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030408}
409
Andrew Jeffery66c77232024-04-24 11:42:02 +0930410#define pldm_msgbuf_extract_int16(ctx, dst) \
411 pldm_msgbuf_extract_typecheck(int16_t, pldm__msgbuf_extract_int16, \
Andrew Jefferye5f12532024-10-01 12:18:49 +0930412 dst, ctx, (void *)&(dst))
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300413LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300414LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930415// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930416pldm__msgbuf_extract_int16(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030417{
418 int16_t ldst;
419
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300420 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930421 return -EINVAL;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030422 }
423
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930424 static_assert(
425 // NOLINTNEXTLINE(bugprone-sizeof-expression)
426 sizeof(ldst) < INTMAX_MAX,
427 "The following addition may not uphold the runtime assertion");
428 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
429 assert(ctx->remaining < 0);
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930430 return -EOVERFLOW;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930431 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030432 ctx->remaining -= sizeof(ldst);
433 assert(ctx->remaining >= 0);
434 if (ctx->remaining < 0) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930435 return -EOVERFLOW;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030436 }
437
438 memcpy(&ldst, ctx->cursor, sizeof(ldst));
439
Andrew Jeffery66c77232024-04-24 11:42:02 +0930440 ldst = le16toh(ldst);
441 memcpy(dst, &ldst, sizeof(ldst));
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030442 ctx->cursor += sizeof(ldst);
443
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930444 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030445}
446
Andrew Jeffery66c77232024-04-24 11:42:02 +0930447#define pldm_msgbuf_extract_uint32(ctx, dst) \
448 pldm_msgbuf_extract_typecheck(uint32_t, pldm__msgbuf_extract_uint32, \
Andrew Jefferye5f12532024-10-01 12:18:49 +0930449 dst, ctx, (void *)&(dst))
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300450LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300451LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930452// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930453pldm__msgbuf_extract_uint32(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030454{
455 uint32_t ldst;
456
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300457 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930458 return -EINVAL;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030459 }
460
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930461 static_assert(
462 // NOLINTNEXTLINE(bugprone-sizeof-expression)
463 sizeof(ldst) < INTMAX_MAX,
464 "The following addition may not uphold the runtime assertion");
465 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
466 assert(ctx->remaining < 0);
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930467 return -EOVERFLOW;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930468 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030469 ctx->remaining -= sizeof(ldst);
470 assert(ctx->remaining >= 0);
471 if (ctx->remaining < 0) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930472 return -EOVERFLOW;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030473 }
474
475 memcpy(&ldst, ctx->cursor, sizeof(ldst));
Andrew Jeffery66c77232024-04-24 11:42:02 +0930476 ldst = le32toh(ldst);
477 memcpy(dst, &ldst, sizeof(ldst));
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030478 ctx->cursor += sizeof(ldst);
479
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930480 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030481}
482
Andrew Jeffery66c77232024-04-24 11:42:02 +0930483#define pldm_msgbuf_extract_int32(ctx, dst) \
484 pldm_msgbuf_extract_typecheck(int32_t, pldm__msgbuf_extract_int32, \
Andrew Jefferye5f12532024-10-01 12:18:49 +0930485 dst, ctx, (void *)&(dst))
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300486LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300487LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930488// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930489pldm__msgbuf_extract_int32(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030490{
491 int32_t ldst;
492
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300493 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930494 return -EINVAL;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030495 }
496
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930497 static_assert(
498 // NOLINTNEXTLINE(bugprone-sizeof-expression)
499 sizeof(ldst) < INTMAX_MAX,
500 "The following addition may not uphold the runtime assertion");
501 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
502 assert(ctx->remaining < 0);
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930503 return -EOVERFLOW;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930504 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030505 ctx->remaining -= sizeof(ldst);
506 assert(ctx->remaining >= 0);
507 if (ctx->remaining < 0) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930508 return -EOVERFLOW;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030509 }
510
511 memcpy(&ldst, ctx->cursor, sizeof(ldst));
Andrew Jeffery66c77232024-04-24 11:42:02 +0930512 ldst = le32toh(ldst);
513 memcpy(dst, &ldst, sizeof(ldst));
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030514 ctx->cursor += sizeof(ldst);
515
516 return PLDM_SUCCESS;
517}
518
Andrew Jeffery66c77232024-04-24 11:42:02 +0930519#define pldm_msgbuf_extract_real32(ctx, dst) \
520 pldm_msgbuf_extract_typecheck(real32_t, pldm__msgbuf_extract_real32, \
Andrew Jefferye5f12532024-10-01 12:18:49 +0930521 dst, ctx, (void *)&(dst))
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300522LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300523LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930524// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930525pldm__msgbuf_extract_real32(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030526{
527 uint32_t ldst;
528
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930529 static_assert(sizeof(real32_t) == sizeof(ldst),
530 "Mismatched type sizes for dst and ldst");
Andrew Jeffery66c77232024-04-24 11:42:02 +0930531
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300532 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930533 return -EINVAL;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030534 }
535
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930536 static_assert(
537 // NOLINTNEXTLINE(bugprone-sizeof-expression)
538 sizeof(ldst) < INTMAX_MAX,
539 "The following addition may not uphold the runtime assertion");
540 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
541 assert(ctx->remaining < 0);
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930542 return -EOVERFLOW;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930543 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030544 ctx->remaining -= sizeof(ldst);
545 assert(ctx->remaining >= 0);
546 if (ctx->remaining < 0) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930547 return -EOVERFLOW;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030548 }
549
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030550 memcpy(&ldst, ctx->cursor, sizeof(ldst));
551 ldst = le32toh(ldst);
Andrew Jeffery66c77232024-04-24 11:42:02 +0930552 memcpy(dst, &ldst, sizeof(ldst));
553 ctx->cursor += sizeof(ldst);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030554
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930555 return 0;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030556}
557
Andrew Jeffery66c77232024-04-24 11:42:02 +0930558/**
559 * Extract the field at the msgbuf cursor into the lvalue named by dst.
560 *
561 * @param ctx The msgbuf context object
562 * @param dst The lvalue into which the field at the msgbuf cursor should be
563 * extracted
564 *
565 * @return PLDM_SUCCESS on success, otherwise another value on error
566 */
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030567#define pldm_msgbuf_extract(ctx, dst) \
Andrew Jeffery66c77232024-04-24 11:42:02 +0930568 _Generic((dst), \
569 uint8_t: pldm__msgbuf_extract_uint8, \
570 int8_t: pldm__msgbuf_extract_int8, \
571 uint16_t: pldm__msgbuf_extract_uint16, \
572 int16_t: pldm__msgbuf_extract_int16, \
573 uint32_t: pldm__msgbuf_extract_uint32, \
574 int32_t: pldm__msgbuf_extract_int32, \
575 real32_t: pldm__msgbuf_extract_real32)(ctx, (void *)&(dst))
576
577/**
578 * Extract the field at the msgbuf cursor into the object pointed-to by dst.
579 *
580 * @param ctx The msgbuf context object
581 * @param dst The pointer to the object into which the field at the msgbuf
582 * cursor should be extracted
583 *
584 * @return PLDM_SUCCESS on success, otherwise another value on error
585 */
586#define pldm_msgbuf_extract_p(ctx, dst) \
587 _Generic((dst), \
588 uint8_t *: pldm__msgbuf_extract_uint8, \
589 int8_t *: pldm__msgbuf_extract_int8, \
590 uint16_t *: pldm__msgbuf_extract_uint16, \
591 int16_t *: pldm__msgbuf_extract_int16, \
592 uint32_t *: pldm__msgbuf_extract_uint32, \
593 int32_t *: pldm__msgbuf_extract_int32, \
594 real32_t *: pldm__msgbuf_extract_real32)(ctx, dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030595
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000596/**
597 * @ref pldm_msgbuf_extract_array
598 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300599LIBPLDM_CC_NONNULL
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000600LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300601LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery1c571442024-07-08 10:25:48 +0930602// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000603pldm__msgbuf_extract_array_void(struct pldm_msgbuf *ctx, size_t count,
604 void *dst, size_t dst_count)
Andrew Jeffery369b1212023-04-20 15:44:48 +0930605{
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300606 if (!ctx->cursor || count > dst_count) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930607 return -EINVAL;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930608 }
609
610 if (!count) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930611 return 0;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930612 }
613
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930614#if INTMAX_MAX < SIZE_MAX
615 if (count > INTMAX_MAX) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930616 return -EOVERFLOW;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930617 }
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930618#endif
Andrew Jeffery369b1212023-04-20 15:44:48 +0930619
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930620 if (ctx->remaining < INTMAX_MIN + (intmax_t)count) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930621 return -EOVERFLOW;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930622 }
623 ctx->remaining -= (intmax_t)count;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930624 assert(ctx->remaining >= 0);
625 if (ctx->remaining < 0) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930626 return -EOVERFLOW;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930627 }
628
Andrew Jefferya065ecc2023-10-27 15:02:11 +1030629 memcpy(dst, ctx->cursor, count);
630 ctx->cursor += count;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930631
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930632 return 0;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930633}
634
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000635/**
636 * @ref pldm_msgbuf_extract_array
637 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300638LIBPLDM_CC_NONNULL
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000639LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300640LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000641pldm_msgbuf_extract_array_char(struct pldm_msgbuf *ctx, size_t count, char *dst,
642 size_t dst_count)
Andrew Jeffery1c571442024-07-08 10:25:48 +0930643{
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000644 return pldm__msgbuf_extract_array_void(ctx, count, dst, dst_count);
Andrew Jeffery1c571442024-07-08 10:25:48 +0930645}
646
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000647/**
648 * @ref pldm_msgbuf_extract_array
649 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300650LIBPLDM_CC_NONNULL
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000651LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300652LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000653pldm_msgbuf_extract_array_uint8(struct pldm_msgbuf *ctx, size_t count,
654 uint8_t *dst, size_t dst_count)
Andrew Jeffery1c571442024-07-08 10:25:48 +0930655{
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000656 return pldm__msgbuf_extract_array_void(ctx, count, dst, dst_count);
Andrew Jeffery1c571442024-07-08 10:25:48 +0930657}
658
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000659/**
660 * Extract an array of data from the msgbuf instance
661 *
662 * @param ctx - The msgbuf instance from which to extract an array of data
663 * @param count - The number of array elements to extract
664 * @param dst - The array object into which elements from @p ctx should be
665 extracted
666 * @param dst_count - The maximum number of elements to place into @p dst
667 *
668 * Note that both @p count and @p dst_count can only be counted by `sizeof` for
669 * arrays where `sizeof(*dst) == 1` holds. Specifically, they count the number
670 * of array elements and _not_ the object size of the array.
671 */
672#define pldm_msgbuf_extract_array(ctx, count, dst, dst_count) \
Andrew Jeffery1c571442024-07-08 10:25:48 +0930673 _Generic((*(dst)), \
674 uint8_t: pldm_msgbuf_extract_array_uint8, \
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000675 char: pldm_msgbuf_extract_array_char)(ctx, count, dst, \
676 dst_count)
Andrew Jeffery369b1212023-04-20 15:44:48 +0930677
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300678LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300679LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_uint32(struct pldm_msgbuf *ctx,
680 const uint32_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700681{
682 uint32_t val = htole32(src);
683
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930684 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930685 return -EINVAL;
Thu Nguyen062c8762023-04-22 20:45:04 +0700686 }
687
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930688 static_assert(
689 // NOLINTNEXTLINE(bugprone-sizeof-expression)
690 sizeof(src) < INTMAX_MAX,
691 "The following addition may not uphold the runtime assertion");
692 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
693 assert(ctx->remaining < 0);
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930694 return -EOVERFLOW;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930695 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700696 ctx->remaining -= sizeof(src);
697 assert(ctx->remaining >= 0);
698 if (ctx->remaining < 0) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930699 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +0700700 }
701
702 memcpy(ctx->cursor, &val, sizeof(val));
703 ctx->cursor += sizeof(src);
704
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930705 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700706}
707
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300708LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300709LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_uint16(struct pldm_msgbuf *ctx,
710 const uint16_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700711{
712 uint16_t val = htole16(src);
713
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930714 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930715 return -EINVAL;
Thu Nguyen062c8762023-04-22 20:45:04 +0700716 }
717
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930718 static_assert(
719 // NOLINTNEXTLINE(bugprone-sizeof-expression)
720 sizeof(src) < INTMAX_MAX,
721 "The following addition may not uphold the runtime assertion");
722 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
723 assert(ctx->remaining < 0);
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930724 return -EOVERFLOW;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930725 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700726 ctx->remaining -= sizeof(src);
727 assert(ctx->remaining >= 0);
728 if (ctx->remaining < 0) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930729 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +0700730 }
731
732 memcpy(ctx->cursor, &val, sizeof(val));
733 ctx->cursor += sizeof(src);
734
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930735 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700736}
737
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300738LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300739LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_uint8(struct pldm_msgbuf *ctx,
740 const uint8_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700741{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930742 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930743 return -EINVAL;
Thu Nguyen062c8762023-04-22 20:45:04 +0700744 }
745
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930746 static_assert(
747 // NOLINTNEXTLINE(bugprone-sizeof-expression)
748 sizeof(src) < INTMAX_MAX,
749 "The following addition may not uphold the runtime assertion");
750 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
751 assert(ctx->remaining < 0);
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930752 return -EOVERFLOW;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930753 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700754 ctx->remaining -= sizeof(src);
755 assert(ctx->remaining >= 0);
756 if (ctx->remaining < 0) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930757 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +0700758 }
759
760 memcpy(ctx->cursor, &src, sizeof(src));
761 ctx->cursor += sizeof(src);
762
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930763 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700764}
765
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300766LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300767LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_int32(struct pldm_msgbuf *ctx,
768 const int32_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700769{
770 int32_t val = htole32(src);
771
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930772 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930773 return -EINVAL;
Thu Nguyen062c8762023-04-22 20:45:04 +0700774 }
775
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930776 static_assert(
777 // NOLINTNEXTLINE(bugprone-sizeof-expression)
778 sizeof(src) < INTMAX_MAX,
779 "The following addition may not uphold the runtime assertion");
780 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
781 assert(ctx->remaining < 0);
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930782 return -EOVERFLOW;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930783 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700784 ctx->remaining -= sizeof(src);
785 assert(ctx->remaining >= 0);
786 if (ctx->remaining < 0) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930787 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +0700788 }
789
790 memcpy(ctx->cursor, &val, sizeof(val));
791 ctx->cursor += sizeof(src);
792
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930793 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700794}
795
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300796LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300797LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_int16(struct pldm_msgbuf *ctx,
798 const int16_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700799{
800 int16_t val = htole16(src);
801
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930802 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930803 return -EINVAL;
Thu Nguyen062c8762023-04-22 20:45:04 +0700804 }
805
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930806 static_assert(
807 // NOLINTNEXTLINE(bugprone-sizeof-expression)
808 sizeof(src) < INTMAX_MAX,
809 "The following addition may not uphold the runtime assertion");
810 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
811 assert(ctx->remaining < 0);
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930812 return -EOVERFLOW;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930813 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700814 ctx->remaining -= sizeof(src);
815 assert(ctx->remaining >= 0);
816 if (ctx->remaining < 0) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930817 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +0700818 }
819
820 memcpy(ctx->cursor, &val, sizeof(val));
821 ctx->cursor += sizeof(src);
822
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930823 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700824}
825
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300826LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300827LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_int8(struct pldm_msgbuf *ctx,
828 const int8_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700829{
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930830 if (!ctx->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930831 return -EINVAL;
Thu Nguyen062c8762023-04-22 20:45:04 +0700832 }
833
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930834 static_assert(
835 // NOLINTNEXTLINE(bugprone-sizeof-expression)
836 sizeof(src) < INTMAX_MAX,
837 "The following addition may not uphold the runtime assertion");
838 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
839 assert(ctx->remaining < 0);
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930840 return -EOVERFLOW;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930841 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700842 ctx->remaining -= sizeof(src);
843 assert(ctx->remaining >= 0);
844 if (ctx->remaining < 0) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930845 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +0700846 }
847
848 memcpy(ctx->cursor, &src, sizeof(src));
849 ctx->cursor += sizeof(src);
850
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930851 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700852}
853
854#define pldm_msgbuf_insert(dst, src) \
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930855 _Generic((src), \
856 uint8_t: pldm_msgbuf_insert_uint8, \
857 int8_t: pldm_msgbuf_insert_int8, \
858 uint16_t: pldm_msgbuf_insert_uint16, \
859 int16_t: pldm_msgbuf_insert_int16, \
860 uint32_t: pldm_msgbuf_insert_uint32, \
861 int32_t: pldm_msgbuf_insert_int32)(dst, src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700862
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000863/**
864 * @ref pldm_msgbuf_insert_array
865 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300866LIBPLDM_CC_NONNULL
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000867LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300868LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery1c571442024-07-08 10:25:48 +0930869// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000870pldm__msgbuf_insert_array_void(struct pldm_msgbuf *ctx, size_t count,
871 const void *src, size_t src_count)
Thu Nguyen062c8762023-04-22 20:45:04 +0700872{
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300873 if (!ctx->cursor || count > src_count) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930874 return -EINVAL;
Thu Nguyen062c8762023-04-22 20:45:04 +0700875 }
876
877 if (!count) {
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930878 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700879 }
880
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930881#if INTMAX_MAX < SIZE_MAX
882 if (count > INTMAX_MAX) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930883 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +0700884 }
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930885#endif
Thu Nguyen062c8762023-04-22 20:45:04 +0700886
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930887 if (ctx->remaining < INTMAX_MIN + (intmax_t)count) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930888 return -EOVERFLOW;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930889 }
890 ctx->remaining -= (intmax_t)count;
Thu Nguyen062c8762023-04-22 20:45:04 +0700891 assert(ctx->remaining >= 0);
892 if (ctx->remaining < 0) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930893 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +0700894 }
895
Andrew Jefferya065ecc2023-10-27 15:02:11 +1030896 memcpy(ctx->cursor, src, count);
897 ctx->cursor += count;
Thu Nguyen062c8762023-04-22 20:45:04 +0700898
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930899 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700900}
901
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000902/**
903 * @ref pldm_msgbuf_insert_array
904 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300905LIBPLDM_CC_NONNULL
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000906LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300907LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000908pldm_msgbuf_insert_array_char(struct pldm_msgbuf *ctx, size_t count,
909 const char *src, size_t src_count)
Andrew Jeffery1c571442024-07-08 10:25:48 +0930910{
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000911 return pldm__msgbuf_insert_array_void(ctx, count, src, src_count);
Andrew Jeffery1c571442024-07-08 10:25:48 +0930912}
913
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000914/**
915 * @ref pldm_msgbuf_insert_array
916 */
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300917LIBPLDM_CC_NONNULL
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000918LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300919LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000920pldm_msgbuf_insert_array_uint8(struct pldm_msgbuf *ctx, size_t count,
921 const uint8_t *src, size_t src_count)
Andrew Jeffery1c571442024-07-08 10:25:48 +0930922{
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000923 return pldm__msgbuf_insert_array_void(ctx, count, src, src_count);
Andrew Jeffery1c571442024-07-08 10:25:48 +0930924}
925
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000926/**
927 * Insert an array of data into the msgbuf instance
928 *
929 * @param ctx - The msgbuf instance into which the array of data should be
930 * inserted
931 * @param count - The number of array elements to insert
932 * @param src - The array object from which elements should be inserted into
933 @p ctx
934 * @param src_count - The maximum number of elements to insert from @p src
935 *
936 * Note that both @p count and @p src_count can only be counted by `sizeof` for
937 * arrays where `sizeof(*dst) == 1` holds. Specifically, they count the number
938 * of array elements and _not_ the object size of the array.
939 */
940#define pldm_msgbuf_insert_array(dst, count, src, src_count) \
Andrew Jeffery1c571442024-07-08 10:25:48 +0930941 _Generic((*(src)), \
942 uint8_t: pldm_msgbuf_insert_array_uint8, \
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +0000943 char: pldm_msgbuf_insert_array_char)(dst, count, src, \
944 src_count)
Thu Nguyen062c8762023-04-22 20:45:04 +0700945
Varsha Kaverappa79393822024-08-07 00:40:13 -0500946LIBPLDM_CC_NONNULL_ARGS(1)
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300947LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_span_required(struct pldm_msgbuf *ctx,
948 size_t required,
949 void **cursor)
Thu Nguyen062c8762023-04-22 20:45:04 +0700950{
Varsha Kaverappa79393822024-08-07 00:40:13 -0500951 if (!ctx->cursor || (cursor && *cursor)) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930952 return -EINVAL;
Thu Nguyen062c8762023-04-22 20:45:04 +0700953 }
954
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930955#if INTMAX_MAX < SIZE_MAX
956 if (required > INTMAX_MAX) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930957 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +0700958 }
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930959#endif
Thu Nguyen062c8762023-04-22 20:45:04 +0700960
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930961 if (ctx->remaining < INTMAX_MIN + (intmax_t)required) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930962 return -EOVERFLOW;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930963 }
964 ctx->remaining -= (intmax_t)required;
Thu Nguyen062c8762023-04-22 20:45:04 +0700965 assert(ctx->remaining >= 0);
966 if (ctx->remaining < 0) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930967 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +0700968 }
969
Varsha Kaverappa79393822024-08-07 00:40:13 -0500970 if (cursor) {
971 *cursor = ctx->cursor;
972 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700973 ctx->cursor += required;
974
Andrew Jefferyc8df31c2024-05-21 16:47:43 +0930975 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +0700976}
977
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +0300978LIBPLDM_CC_NONNULL_ARGS(1)
Andrew Jefferycb569bc2024-09-01 09:38:09 +0300979LIBPLDM_CC_ALWAYS_INLINE int
Thu Nguyen9c83d682024-07-02 08:43:09 +0000980pldm_msgbuf_span_string_ascii(struct pldm_msgbuf *ctx, void **cursor,
981 size_t *length)
982{
983 intmax_t measured;
984
Thu Nguyen9c83d682024-07-02 08:43:09 +0000985 if (!ctx->cursor || (cursor && *cursor)) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930986 return -EINVAL;
Thu Nguyen9c83d682024-07-02 08:43:09 +0000987 }
988
989 if (ctx->remaining < 0) {
990 /* Tracking the amount of overflow gets disturbed here */
Andrew Jeffery830c1eb2024-10-04 10:48:10 +0930991 return -EOVERFLOW;
Thu Nguyen9c83d682024-07-02 08:43:09 +0000992 }
993
994 measured = (intmax_t)strnlen((const char *)ctx->cursor, ctx->remaining);
995 if (measured == ctx->remaining) {
996 /*
997 * We have hit the end of the buffer prior to the NUL terminator.
998 * Optimistically, the NUL terminator was one-beyond-the-end. Setting
999 * ctx->remaining negative ensures the `pldm_msgbuf_destroy*()` APIs also
1000 * return an error.
1001 */
1002 ctx->remaining = -1;
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301003 return -EOVERFLOW;
Thu Nguyen9c83d682024-07-02 08:43:09 +00001004 }
1005
1006 /* Include the NUL terminator in the span length, as spans are opaque */
1007 measured++;
1008
1009 if (ctx->remaining < INTMAX_MIN + measured) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301010 return -EOVERFLOW;
Thu Nguyen9c83d682024-07-02 08:43:09 +00001011 }
1012
1013 ctx->remaining -= measured;
1014 assert(ctx->remaining >= 0);
1015 if (ctx->remaining < 0) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301016 return -EOVERFLOW;
Thu Nguyen9c83d682024-07-02 08:43:09 +00001017 }
1018
1019 if (cursor) {
1020 *cursor = ctx->cursor;
1021 }
1022
1023 ctx->cursor += measured;
1024
1025 if (length) {
1026 *length = measured;
1027 }
1028
1029 return 0;
1030}
1031
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +03001032LIBPLDM_CC_NONNULL_ARGS(1)
Andrew Jefferycb569bc2024-09-01 09:38:09 +03001033LIBPLDM_CC_ALWAYS_INLINE int
Thu Nguyen15237782024-07-02 09:30:41 +00001034pldm_msgbuf_span_string_utf16(struct pldm_msgbuf *ctx, void **cursor,
1035 size_t *length)
1036{
1037 static const char16_t term = 0;
1038 ptrdiff_t measured;
1039 void *end;
1040
Thu Nguyen15237782024-07-02 09:30:41 +00001041 if (!ctx->cursor || (cursor && *cursor)) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301042 return -EINVAL;
Thu Nguyen15237782024-07-02 09:30:41 +00001043 }
1044
1045 if (ctx->remaining < 0) {
1046 /* Tracking the amount of overflow gets disturbed here */
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301047 return -EOVERFLOW;
Thu Nguyen15237782024-07-02 09:30:41 +00001048 }
1049
1050 /*
1051 * Avoid tripping up on UTF16-LE: We may have consecutive NUL _bytes_ that do
1052 * not form a UTF16 NUL _code-point_ due to alignment with respect to the
1053 * start of the string
1054 */
Andrew Jeffery2b440d42024-07-25 10:36:08 +09301055 end = ctx->cursor;
Thu Nguyen15237782024-07-02 09:30:41 +00001056 do {
1057 if (end != ctx->cursor) {
1058 /*
1059 * If we've looped we've found a relatively-unaligned NUL code-point.
1060 * Scan again from a relatively-aligned start point.
1061 */
1062 end = (char *)end + 1;
1063 }
1064 measured = (char *)end - (char *)ctx->cursor;
Andrew Jeffery2b440d42024-07-25 10:36:08 +09301065 end = memmem(end, ctx->remaining - measured, &term,
1066 sizeof(term));
Thu Nguyen15237782024-07-02 09:30:41 +00001067 } while (end && ((uintptr_t)end & 1) != ((uintptr_t)ctx->cursor & 1));
1068
1069 if (!end) {
1070 /*
1071 * Optimistically, the last required pattern byte was one beyond the end of
1072 * the buffer. Setting ctx->remaining negative ensures the
1073 * `pldm_msgbuf_destroy*()` APIs also return an error.
1074 */
1075 ctx->remaining = -1;
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301076 return -EOVERFLOW;
Thu Nguyen15237782024-07-02 09:30:41 +00001077 }
1078
1079 end = (char *)end + sizeof(char16_t);
1080 measured = (char *)end - (char *)ctx->cursor;
1081
1082#if INTMAX_MAX < PTRDIFF_MAX
1083 if (measured >= INTMAX_MAX) {
1084 return pldm_msgbuf_status(ctx, EOVERFLOW);
1085 }
1086#endif
1087
1088 if (ctx->remaining < INTMAX_MIN + (intmax_t)measured) {
1089 assert(ctx->remaining < 0);
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301090 return -EOVERFLOW;
Thu Nguyen15237782024-07-02 09:30:41 +00001091 }
1092
1093 ctx->remaining -= (intmax_t)measured;
1094 assert(ctx->remaining >= 0);
1095 if (ctx->remaining < 0) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301096 return -EOVERFLOW;
Thu Nguyen15237782024-07-02 09:30:41 +00001097 }
1098
1099 if (cursor) {
1100 *cursor = ctx->cursor;
1101 }
1102
1103 ctx->cursor += measured;
1104
1105 if (length) {
1106 *length = (size_t)measured;
1107 }
1108
1109 return 0;
1110}
1111
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +03001112LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +03001113LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery76712f62024-05-22 15:19:00 +09301114pldm_msgbuf_span_remaining(struct pldm_msgbuf *ctx, void **cursor, size_t *len)
Thu Nguyen062c8762023-04-22 20:45:04 +07001115{
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +03001116 if (!ctx->cursor || *cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301117 return -EINVAL;
Thu Nguyen062c8762023-04-22 20:45:04 +07001118 }
1119
1120 assert(ctx->remaining >= 0);
1121 if (ctx->remaining < 0) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301122 return -EOVERFLOW;
Thu Nguyen062c8762023-04-22 20:45:04 +07001123 }
1124
1125 *cursor = ctx->cursor;
1126 ctx->cursor += ctx->remaining;
1127 *len = ctx->remaining;
1128 ctx->remaining = 0;
1129
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301130 return 0;
Thu Nguyen062c8762023-04-22 20:45:04 +07001131}
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001132
1133/**
1134 * @brief pldm_msgbuf copy data between two msg buffers
1135 *
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +05301136 * @param[in,out] src - pldm_msgbuf for source from where value should be copied
1137 * @param[in,out] dst - destination of copy from source
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001138 * @param[in] size - size of data to be copied
1139 * @param[in] description - description of data copied
1140 *
1141 * @return PLDM_SUCCESS if buffer accesses were in-bounds,
1142 * PLDM_ERROR_INVALID_LENGTH otherwise.
1143 * PLDM_ERROR_INVALID_DATA if input is invalid
1144 */
1145#define pldm_msgbuf_copy(dst, src, type, name) \
1146 pldm__msgbuf_copy(dst, src, sizeof(type), #name)
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +03001147LIBPLDM_CC_NONNULL
Andrew Jefferycb569bc2024-09-01 09:38:09 +03001148LIBPLDM_CC_ALWAYS_INLINE int
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001149// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +09301150pldm__msgbuf_copy(struct pldm_msgbuf *dst, struct pldm_msgbuf *src, size_t size,
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +03001151 const char *description LIBPLDM_CC_UNUSED)
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001152{
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +03001153 if (!src->cursor || !dst->cursor) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301154 return -EINVAL;
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001155 }
1156
1157#if INTMAX_MAX < SIZE_MAX
1158 if (size > INTMAX_MAX) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301159 return -EOVERFLOW;
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001160 }
1161#endif
1162
1163 if (src->remaining < INTMAX_MIN + (intmax_t)size) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301164 return -EOVERFLOW;
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001165 }
1166
1167 if (dst->remaining < INTMAX_MIN + (intmax_t)size) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301168 return -EOVERFLOW;
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001169 }
1170
1171 src->remaining -= (intmax_t)size;
1172 assert(src->remaining >= 0);
1173 if (src->remaining < 0) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301174 return -EOVERFLOW;
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001175 }
1176
1177 dst->remaining -= (intmax_t)size;
1178 assert(dst->remaining >= 0);
1179 if (dst->remaining < 0) {
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301180 return -EOVERFLOW;
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001181 }
1182
1183 memcpy(dst->cursor, src->cursor, size);
1184 src->cursor += size;
1185 dst->cursor += size;
1186
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301187 return 0;
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -05001188}
Andrew Jefferyc8df31c2024-05-21 16:47:43 +09301189
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +03001190LIBPLDM_CC_NONNULL
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001191LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jefferycb569bc2024-09-01 09:38:09 +03001192LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery8b879602024-07-08 12:50:19 +09301193pldm_msgbuf_copy_string_ascii(struct pldm_msgbuf *dst, struct pldm_msgbuf *src)
1194{
1195 void *ascii = NULL;
1196 size_t len = 0;
1197 int rc;
1198
1199 rc = pldm_msgbuf_span_string_ascii(src, &ascii, &len);
1200 if (rc < 0) {
1201 return rc;
1202 }
1203
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001204 return pldm__msgbuf_insert_array_void(dst, len, ascii, len);
Andrew Jeffery8b879602024-07-08 12:50:19 +09301205}
1206
Andrew Jeffery90bbe6c2024-09-01 13:02:02 +03001207LIBPLDM_CC_NONNULL
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001208LIBPLDM_CC_WARN_UNUSED_RESULT
Andrew Jefferycb569bc2024-09-01 09:38:09 +03001209LIBPLDM_CC_ALWAYS_INLINE int
Andrew Jeffery56f73f92024-07-08 12:50:28 +09301210pldm_msgbuf_copy_string_utf16(struct pldm_msgbuf *dst, struct pldm_msgbuf *src)
1211{
1212 void *utf16 = NULL;
1213 size_t len = 0;
1214 int rc;
1215
1216 rc = pldm_msgbuf_span_string_utf16(src, &utf16, &len);
1217 if (rc < 0) {
1218 return rc;
1219 }
1220
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001221 return pldm__msgbuf_insert_array_void(dst, len, utf16, len);
Andrew Jeffery56f73f92024-07-08 12:50:28 +09301222}
1223
Andrew Jefferyc63f63a2023-02-24 22:29:33 +10301224#ifdef __cplusplus
1225}
1226#endif
1227
Andrew Jeffery66c77232024-04-24 11:42:02 +09301228#ifdef __cplusplus
1229#include <type_traits>
1230
1231template <typename T>
1232static inline int pldm_msgbuf_typecheck_uint8_t(struct pldm_msgbuf *ctx,
1233 void *buf)
1234{
Andrew Jefferye5f12532024-10-01 12:18:49 +09301235 static_assert(std::is_same<uint8_t, T>::value);
Andrew Jeffery66c77232024-04-24 11:42:02 +09301236 return pldm__msgbuf_extract_uint8(ctx, buf);
1237}
1238
1239template <typename T>
1240static inline int pldm_msgbuf_typecheck_int8_t(struct pldm_msgbuf *ctx,
1241 void *buf)
1242{
Andrew Jefferye5f12532024-10-01 12:18:49 +09301243 static_assert(std::is_same<int8_t, T>::value);
Andrew Jeffery66c77232024-04-24 11:42:02 +09301244 return pldm__msgbuf_extract_int8(ctx, buf);
1245}
1246
1247template <typename T>
1248static inline int pldm_msgbuf_typecheck_uint16_t(struct pldm_msgbuf *ctx,
1249 void *buf)
1250{
Andrew Jefferye5f12532024-10-01 12:18:49 +09301251 static_assert(std::is_same<uint16_t, T>::value);
Andrew Jeffery66c77232024-04-24 11:42:02 +09301252 return pldm__msgbuf_extract_uint16(ctx, buf);
1253}
1254
1255template <typename T>
1256static inline int pldm_msgbuf_typecheck_int16_t(struct pldm_msgbuf *ctx,
1257 void *buf)
1258{
Andrew Jefferye5f12532024-10-01 12:18:49 +09301259 static_assert(std::is_same<int16_t, T>::value);
Andrew Jeffery66c77232024-04-24 11:42:02 +09301260 return pldm__msgbuf_extract_int16(ctx, buf);
1261}
1262
1263template <typename T>
1264static inline int pldm_msgbuf_typecheck_uint32_t(struct pldm_msgbuf *ctx,
1265 void *buf)
1266{
Andrew Jefferye5f12532024-10-01 12:18:49 +09301267 static_assert(std::is_same<uint32_t, T>::value);
Andrew Jeffery66c77232024-04-24 11:42:02 +09301268 return pldm__msgbuf_extract_uint32(ctx, buf);
1269}
1270
1271template <typename T>
1272static inline int pldm_msgbuf_typecheck_int32_t(struct pldm_msgbuf *ctx,
1273 void *buf)
1274{
Andrew Jefferye5f12532024-10-01 12:18:49 +09301275 static_assert(std::is_same<int32_t, T>::value);
Andrew Jeffery66c77232024-04-24 11:42:02 +09301276 return pldm__msgbuf_extract_int32(ctx, buf);
1277}
1278
1279template <typename T>
1280static inline int pldm_msgbuf_typecheck_real32_t(struct pldm_msgbuf *ctx,
1281 void *buf)
1282{
Andrew Jefferye5f12532024-10-01 12:18:49 +09301283 static_assert(std::is_same<real32_t, T>::value);
Andrew Jeffery66c77232024-04-24 11:42:02 +09301284 return pldm__msgbuf_extract_real32(ctx, buf);
1285}
1286#endif
1287
Andrew Jefferyc63f63a2023-02-24 22:29:33 +10301288#endif /* BUF_H */