blob: 50362119c2351980b6570b9512146e03eb9b87ef [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 Jeffery66c77232024-04-24 11:42:02 +09305/*
6 * Historically, many of the structs exposed in libpldm's public headers are
7 * defined with __attribute__((packed)). This is unfortunate: it gives the
8 * impression that a wire-format buffer can be cast to the message type to make
9 * the message's fields easily accessible. As it turns out, that's not
10 * that's valid for several reasons:
11 *
12 * 1. Casting the wire-format buffer to a struct of the message type doesn't
13 * abstract the endianness of message field values
14 *
15 * 2. Some messages contain packed tagged union fields which cannot be properly
16 * described in a C struct.
17 *
18 * The msgbuf APIs exist to assist with (un)packing the wire-format in a way
19 * that is type-safe, spatially memory-safe, endian-safe, performant, and
20 * free of undefined-behaviour. Message structs that are added to the public
21 * library API should no-longer be marked __attribute__((packed)), and the
22 * implementation of their encode and decode functions must exploit the msgbuf
23 * API.
24 *
25 * However, we would like to allow implementation of codec functions in terms of
26 * msgbuf APIs even if they're decoding a message into a (historically) packed
27 * struct. Some of the complexity that follows is a consequence of the packed/
28 * unpacked conflict.
29 */
30
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103031#ifdef __cplusplus
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093032/*
33 * Fix up C11's _Static_assert() vs C++'s static_assert().
34 *
35 * Can we please have nice things for once.
36 */
37// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
38#define _Static_assert(...) static_assert(__VA_ARGS__)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103039extern "C" {
40#endif
41
Andrew Jefferyb0c1d202023-11-07 22:08:44 +103042#include <libpldm/base.h>
43#include <libpldm/pldm_types.h>
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103044
Andrew Jeffery66c77232024-04-24 11:42:02 +093045#include "compiler.h"
46
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103047#include <assert.h>
48#include <endian.h>
49#include <limits.h>
50#include <stdbool.h>
Andrew Jeffery66c77232024-04-24 11:42:02 +093051#include <stdint.h>
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103052#include <string.h>
53#include <sys/types.h>
54
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +093055/*
56 * We can't use static_assert() outside of some other C construct. Deal
57 * with high-level global assertions by burying them in an unused struct
58 * declaration, that has a sole member for compliance with the requirement that
59 * types must have a size.
60*/
61static struct {
62 static_assert(
63 INTMAX_MAX != SIZE_MAX,
64 "Extraction and insertion value comparisons may be broken");
65 static_assert(INTMAX_MIN + INTMAX_MAX <= 0,
66 "Extraction and insertion arithmetic may be broken");
67 int compliance;
68} build_assertions __attribute__((unused));
69
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103070struct pldm_msgbuf {
Thu Nguyen062c8762023-04-22 20:45:04 +070071 uint8_t *cursor;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +093072 intmax_t remaining;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103073};
74
75/**
76 * @brief Initialize pldm buf struct for buf extractor
77 *
78 * @param[out] ctx - pldm_msgbuf context for extractor
79 * @param[in] minsize - The minimum required length of buffer `buf`
80 * @param[in] buf - buffer to be extracted
81 * @param[in] len - size of buffer
82 *
83 * @return PLDM_SUCCESS if all buffer accesses were in-bounds,
84 * PLDM_ERROR_INVALID_DATA if pointer parameters are invalid, or
85 * PLDM_ERROR_INVALID_LENGTH if length constraints are violated.
86 */
Andrew Jeffery76712f62024-05-22 15:19:00 +093087__attribute__((always_inline)) static inline int
88pldm_msgbuf_init(struct pldm_msgbuf *ctx, size_t minsize, const void *buf,
89 size_t len)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103090{
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103091 if (!ctx || !buf) {
92 return PLDM_ERROR_INVALID_DATA;
93 }
94
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +093095 if ((minsize > len)) {
Andrew Jefferyc63f63a2023-02-24 22:29:33 +103096 return PLDM_ERROR_INVALID_LENGTH;
97 }
98
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +093099#if INTMAX_MAX < SIZE_MAX
100 if (len > INTMAX_MAX) {
101 return PLDM_ERROR_INVALID_LENGTH;
102 }
103#endif
104
Andrew Jeffery07febdb2024-05-17 14:17:14 +0930105 if ((uintptr_t)buf + len < len) {
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030106 return PLDM_ERROR_INVALID_LENGTH;
107 }
108
109 ctx->cursor = (uint8_t *)buf;
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930110 ctx->remaining = (intmax_t)len;
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030111
112 return PLDM_SUCCESS;
113}
114
115/**
116 * @brief Validate buffer overflow state
117 *
118 * @param[in] ctx - pldm_msgbuf context for extractor
119 *
120 * @return PLDM_SUCCESS if there are zero or more bytes of data that remain
121 * unread from the buffer. Otherwise, PLDM_ERROR_INVALID_LENGTH indicates that a
122 * prior accesses would have occurred beyond the bounds of the buffer, and
123 * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid
124 * pointer.
125 */
Andrew Jeffery76712f62024-05-22 15:19:00 +0930126__attribute__((always_inline)) static inline int
127pldm_msgbuf_validate(struct pldm_msgbuf *ctx)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030128{
129 if (!ctx) {
130 return PLDM_ERROR_INVALID_DATA;
131 }
132
133 return ctx->remaining >= 0 ? PLDM_SUCCESS : PLDM_ERROR_INVALID_LENGTH;
134}
135
136/**
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930137 * @brief Test whether a message buffer has been exactly consumed
138 *
139 * @param[in] ctx - pldm_msgbuf context for extractor
140 *
141 * @return PLDM_SUCCESS iff there are zero bytes of data that remain unread from
142 * the buffer and no overflow has occurred. Otherwise, PLDM_ERROR_INVALID_LENGTH
143 * indicates that an incorrect sequence of accesses have occurred, and
144 * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid
145 * pointer.
146 */
Andrew Jeffery76712f62024-05-22 15:19:00 +0930147__attribute__((always_inline)) static inline int
148pldm_msgbuf_consumed(struct pldm_msgbuf *ctx)
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930149{
150 if (!ctx) {
151 return PLDM_ERROR_INVALID_DATA;
152 }
153
154 return ctx->remaining == 0 ? PLDM_SUCCESS : PLDM_ERROR_INVALID_LENGTH;
155}
156
157/**
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030158 * @brief Destroy the pldm buf
159 *
160 * @param[in] ctx - pldm_msgbuf context for extractor
161 *
162 * @return PLDM_SUCCESS if all buffer accesses were in-bounds,
163 * PLDM_ERROR_INVALID_DATA if the ctx parameter is invalid, or
164 * PLDM_ERROR_INVALID_LENGTH if prior accesses would have occurred beyond the
165 * bounds of the buffer.
166 */
Andrew Jeffery76712f62024-05-22 15:19:00 +0930167__attribute__((always_inline)) static inline int
168pldm_msgbuf_destroy(struct pldm_msgbuf *ctx)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030169{
170 int valid;
171
172 if (!ctx) {
173 return PLDM_ERROR_INVALID_DATA;
174 }
175
176 valid = pldm_msgbuf_validate(ctx);
177
178 ctx->cursor = NULL;
179 ctx->remaining = 0;
180
181 return valid;
182}
183
184/**
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930185 * @brief Destroy the pldm_msgbuf instance, and check that the underlying buffer
186 * has been completely consumed without overflow
187 *
188 * @param[in] ctx - pldm_msgbuf context
189 *
190 * @return PLDM_SUCCESS if all buffer access were in-bounds and completely
191 * consume the underlying buffer. Otherwise, PLDM_ERROR_INVALID_DATA if the ctx
192 * parameter is invalid, or PLDM_ERROR_INVALID_LENGTH if prior accesses would
193 * have occurred byond the bounds of the buffer
194 */
Andrew Jeffery76712f62024-05-22 15:19:00 +0930195__attribute__((always_inline)) static inline int
196pldm_msgbuf_destroy_consumed(struct pldm_msgbuf *ctx)
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930197{
198 int consumed;
199
200 if (!ctx) {
201 return PLDM_ERROR_INVALID_DATA;
202 }
203
204 consumed = pldm_msgbuf_consumed(ctx);
205
206 ctx->cursor = NULL;
207 ctx->remaining = 0;
208
209 return consumed;
210}
211
Andrew Jeffery66c77232024-04-24 11:42:02 +0930212/*
213 * Exploit the pre-processor to perform type checking by macro substitution.
214 *
215 * A C type is defined by its alignment as well as its object
216 * size, and compilers have a hammer to enforce it in the form of
217 * `-Waddress-of-packed-member`. Due to the unpacked/packed struct conflict in
218 * the libpldm public API this presents a problem: Naively attempting to use the
219 * msgbuf APIs on a member of a packed struct would yield an error.
220 *
221 * The msgbuf APIs are implemented such that data is moved through unaligned
222 * pointers in a safe way, but to mitigate `-Waddress-of-packed-member` we must
223 * make the object pointers take a trip through `void *` at its API boundary.
224 * That presents a bit too much of an opportunity to non-surgically remove your
225 * own foot, so here we set about doing something to mitigate that as well.
226 *
227 * pldm_msgbuf_extract_typecheck() exists to enforce pointer type correctness
228 * only for the purpose of object sizes, disregarding alignment. We have a few
229 * constraints that cause some headaches:
230 *
231 * 1. We have to perform the type-check before a call through a C function,
232 * as the function must take the object pointer argument as `void *`.
233 * Essentially, this constrains us to doing something with macros.
234 *
235 * 2. While libpldm is a C library, its test suite is written in C++ to take
236 * advantage of gtest.
237 *
238 * 3. Ideally we'd do something with C's `static_assert()`, however
239 * `static_assert()` is defined as void, and as we're constrained to macros,
240 * using `static_assert()` would require a statement-expression
241 *
242 * 4. Currently the project is built with `-std=c17`. CPP statement-expressions
243 * are a GNU extension. We prefer to avoid switching to `-std=gnu17` just for
244 * the purpose of enabling statement-expressions in this one instance.
245 *
246 * 5. We can achieve a conditional build error using `pldm_require_obj_type()`,
247 * however it's implemented in terms of `_Generic()`, which is not available
248 * in C++.
249 *
250 * Combined this means we need separate solutions for C and C++.
251 *
252 * For C, as we don't have statement-expressions, we need to exploit some other
253 * language feature to inject a `pldm_require_obj_type()` prior to the msgbuf
254 * API function call. We also have to take care of the fact that the call-sites
255 * may be in the context of a variable assignment for error-handling purposes.
256 * The key observation is that we can use the comma operator as a sequence point
257 * to order the type check before the API call, discarding the "result" value of
258 * the type check and yielding the return value of the API call.
259 *
260 * C++ could be less of a headache than the C as we can leverage template
261 * functions. An advantage of template functions is that while their definition
262 * is driven by instantion, the definition does not appear at the source
263 * location of the instantation, which gives it a great leg-up over the problems
264 * we have in the C path. However, the use of the msgbuf APIs in the test suite
265 * still makes things somewhat tricky, as the call-sites in the test suite are
266 * wrapped up in EXPECT_*() gtest macros. Ideally we'd implement functions that
267 * takes both the object type and the required type as template arguments, and
268 * then define the object pointer parameter as `void *` for a call through to
269 * the appropriate msgbuf API. However, because the msgbuf API call-sites are
270 * encapsulated in gtest macros, use of commas in the template specification
271 * causes pre-processor confusion. In this way we're constrained to only one
272 * template argument per function.
273 *
274 * Implement the C++ path using template functions that take the destination
275 * object type as a template argument, while the name of the function symbols
276 * are derived from the required type. The manual implementations of these
277 * appear at the end of the header. The type safety is actually enforced
278 * by `static_assert()` this time, as we can use statements as we're not
279 * constrained to an expression in the templated function body.
280 *
281 * The invocations of pldm_msgbuf_extract_typecheck() typically result in
282 * double-evaluation of some arguments. We're not yet bothered by this for two
283 * reasons:
284 *
285 * 1. The nature of the current call-sites are such that there are no
286 * argument expressions that result in undesirable side-effects
287 *
288 * 2. It's an API internal to the libpldm implementation, and we can fix things
289 * whenever something crops up the violates the observation in 1.
290 */
291#ifdef __cplusplus
292#define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...) \
293 pldm_msgbuf_typecheck_##ty<decltype(dst)>(__VA_ARGS__)
294#else
295#define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...) \
296 (pldm_require_obj_type(dst, ty), fn(__VA_ARGS__))
297#endif
298
Andrew Jefferydb7b8322023-04-12 23:05:21 +0930299/**
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030300 * @brief pldm_msgbuf extractor for a uint8_t
301 *
302 * @param[inout] ctx - pldm_msgbuf context for extractor
303 * @param[out] dst - destination of extracted value
304 *
305 * @return PLDM_SUCCESS if buffer accesses were in-bounds,
306 * PLDM_ERROR_INVALID_LENGTH otherwise.
307 * PLDM_ERROR_INVALID_DATA if input a invalid ctx
308 */
Andrew Jeffery66c77232024-04-24 11:42:02 +0930309#define pldm_msgbuf_extract_uint8(ctx, dst) \
310 pldm_msgbuf_extract_typecheck(uint8_t, pldm__msgbuf_extract_uint8, \
311 dst, ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930312__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930313// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930314pldm__msgbuf_extract_uint8(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030315{
316 if (!ctx || !ctx->cursor || !dst) {
317 return PLDM_ERROR_INVALID_DATA;
318 }
319
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930320 if (ctx->remaining == INTMAX_MIN) {
321 assert(ctx->remaining < 0);
322 return PLDM_ERROR_INVALID_LENGTH;
323 }
Andrew Jeffery66c77232024-04-24 11:42:02 +0930324 ctx->remaining -= sizeof(uint8_t);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030325 assert(ctx->remaining >= 0);
326 if (ctx->remaining < 0) {
327 return PLDM_ERROR_INVALID_LENGTH;
328 }
329
Andrew Jeffery66c77232024-04-24 11:42:02 +0930330 memcpy(dst, ctx->cursor, sizeof(uint8_t));
331
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030332 ctx->cursor++;
333 return PLDM_SUCCESS;
334}
335
Andrew Jeffery66c77232024-04-24 11:42:02 +0930336#define pldm_msgbuf_extract_int8(ctx, dst) \
337 pldm_msgbuf_extract_typecheck(int8_t, pldm__msgbuf_extract_int8, dst, \
338 ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930339__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930340// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930341pldm__msgbuf_extract_int8(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030342{
343 if (!ctx || !ctx->cursor || !dst) {
344 return PLDM_ERROR_INVALID_DATA;
345 }
346
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930347 if (ctx->remaining == INTMAX_MIN) {
348 assert(ctx->remaining < 0);
349 return PLDM_ERROR_INVALID_LENGTH;
350 }
Andrew Jeffery66c77232024-04-24 11:42:02 +0930351 ctx->remaining -= sizeof(int8_t);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030352 assert(ctx->remaining >= 0);
353 if (ctx->remaining < 0) {
354 return PLDM_ERROR_INVALID_LENGTH;
355 }
356
Andrew Jeffery66c77232024-04-24 11:42:02 +0930357 memcpy(dst, ctx->cursor, sizeof(int8_t));
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030358 ctx->cursor++;
359 return PLDM_SUCCESS;
360}
361
Andrew Jeffery66c77232024-04-24 11:42:02 +0930362#define pldm_msgbuf_extract_uint16(ctx, dst) \
363 pldm_msgbuf_extract_typecheck(uint16_t, pldm__msgbuf_extract_uint16, \
364 dst, ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930365__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930366// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930367pldm__msgbuf_extract_uint16(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030368{
369 uint16_t ldst;
370
371 if (!ctx || !ctx->cursor || !dst) {
372 return PLDM_ERROR_INVALID_DATA;
373 }
374
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930375 // Check for underflow while tracking the magnitude of the buffer overflow
376 static_assert(
377 // NOLINTNEXTLINE(bugprone-sizeof-expression)
378 sizeof(ldst) < INTMAX_MAX,
379 "The following addition may not uphold the runtime assertion");
380 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
381 assert(ctx->remaining < 0);
382 return PLDM_ERROR_INVALID_LENGTH;
383 }
384
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030385 // Check for buffer overflow. If we overflow, account for the request as
386 // negative values in ctx->remaining. This way we can debug how far
387 // we've overflowed.
388 ctx->remaining -= sizeof(ldst);
389
390 // Prevent the access if it would overflow. First, assert so we blow up
391 // the test suite right at the point of failure. However, cater to
392 // -DNDEBUG by explicitly testing that the access is valid.
393 assert(ctx->remaining >= 0);
394 if (ctx->remaining < 0) {
395 return PLDM_ERROR_INVALID_LENGTH;
396 }
397
398 // Use memcpy() to have the compiler deal with any alignment
399 // issues on the target architecture
400 memcpy(&ldst, ctx->cursor, sizeof(ldst));
401
402 // Only assign the target value once it's correctly decoded
Andrew Jeffery66c77232024-04-24 11:42:02 +0930403 ldst = le16toh(ldst);
404
405 // Allow storing to unaligned
406 memcpy(dst, &ldst, sizeof(ldst));
407
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030408 ctx->cursor += sizeof(ldst);
409
410 return PLDM_SUCCESS;
411}
412
Andrew Jeffery66c77232024-04-24 11:42:02 +0930413#define pldm_msgbuf_extract_int16(ctx, dst) \
414 pldm_msgbuf_extract_typecheck(int16_t, pldm__msgbuf_extract_int16, \
415 dst, ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930416__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930417// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930418pldm__msgbuf_extract_int16(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030419{
420 int16_t ldst;
421
422 if (!ctx || !ctx->cursor || !dst) {
423 return PLDM_ERROR_INVALID_DATA;
424 }
425
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930426 static_assert(
427 // NOLINTNEXTLINE(bugprone-sizeof-expression)
428 sizeof(ldst) < INTMAX_MAX,
429 "The following addition may not uphold the runtime assertion");
430 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
431 assert(ctx->remaining < 0);
432 return PLDM_ERROR_INVALID_LENGTH;
433 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030434 ctx->remaining -= sizeof(ldst);
435 assert(ctx->remaining >= 0);
436 if (ctx->remaining < 0) {
437 return PLDM_ERROR_INVALID_LENGTH;
438 }
439
440 memcpy(&ldst, ctx->cursor, sizeof(ldst));
441
Andrew Jeffery66c77232024-04-24 11:42:02 +0930442 ldst = le16toh(ldst);
443 memcpy(dst, &ldst, sizeof(ldst));
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030444 ctx->cursor += sizeof(ldst);
445
446 return PLDM_SUCCESS;
447}
448
Andrew Jeffery66c77232024-04-24 11:42:02 +0930449#define pldm_msgbuf_extract_uint32(ctx, dst) \
450 pldm_msgbuf_extract_typecheck(uint32_t, pldm__msgbuf_extract_uint32, \
451 dst, ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930452__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930453// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930454pldm__msgbuf_extract_uint32(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030455{
456 uint32_t ldst;
457
458 if (!ctx || !ctx->cursor || !dst) {
459 return PLDM_ERROR_INVALID_DATA;
460 }
461
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930462 static_assert(
463 // NOLINTNEXTLINE(bugprone-sizeof-expression)
464 sizeof(ldst) < INTMAX_MAX,
465 "The following addition may not uphold the runtime assertion");
466 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
467 assert(ctx->remaining < 0);
468 return PLDM_ERROR_INVALID_LENGTH;
469 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030470 ctx->remaining -= sizeof(ldst);
471 assert(ctx->remaining >= 0);
472 if (ctx->remaining < 0) {
473 return PLDM_ERROR_INVALID_LENGTH;
474 }
475
476 memcpy(&ldst, ctx->cursor, sizeof(ldst));
477
Andrew Jeffery66c77232024-04-24 11:42:02 +0930478 ldst = le32toh(ldst);
479 memcpy(dst, &ldst, sizeof(ldst));
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030480 ctx->cursor += sizeof(ldst);
481
482 return PLDM_SUCCESS;
483}
484
Andrew Jeffery66c77232024-04-24 11:42:02 +0930485#define pldm_msgbuf_extract_int32(ctx, dst) \
486 pldm_msgbuf_extract_typecheck(int32_t, pldm__msgbuf_extract_int32, \
487 dst, ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930488__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930489// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930490pldm__msgbuf_extract_int32(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030491{
492 int32_t ldst;
493
494 if (!ctx || !ctx->cursor || !dst) {
495 return PLDM_ERROR_INVALID_DATA;
496 }
497
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930498 static_assert(
499 // NOLINTNEXTLINE(bugprone-sizeof-expression)
500 sizeof(ldst) < INTMAX_MAX,
501 "The following addition may not uphold the runtime assertion");
502 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
503 assert(ctx->remaining < 0);
504 return PLDM_ERROR_INVALID_LENGTH;
505 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030506 ctx->remaining -= sizeof(ldst);
507 assert(ctx->remaining >= 0);
508 if (ctx->remaining < 0) {
509 return PLDM_ERROR_INVALID_LENGTH;
510 }
511
512 memcpy(&ldst, ctx->cursor, sizeof(ldst));
513
Andrew Jeffery66c77232024-04-24 11:42:02 +0930514 ldst = le32toh(ldst);
515 memcpy(dst, &ldst, sizeof(ldst));
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030516 ctx->cursor += sizeof(ldst);
517
518 return PLDM_SUCCESS;
519}
520
Andrew Jeffery66c77232024-04-24 11:42:02 +0930521#define pldm_msgbuf_extract_real32(ctx, dst) \
522 pldm_msgbuf_extract_typecheck(real32_t, pldm__msgbuf_extract_real32, \
523 dst, ctx, dst)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930524__attribute__((always_inline)) static inline int
Andrew Jeffery66c77232024-04-24 11:42:02 +0930525// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930526pldm__msgbuf_extract_real32(struct pldm_msgbuf *ctx, void *dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030527{
528 uint32_t ldst;
529
Andrew Jeffery66c77232024-04-24 11:42:02 +0930530 _Static_assert(sizeof(real32_t) == sizeof(ldst),
531 "Mismatched type sizes for dst and ldst");
532
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030533 if (!ctx || !ctx->cursor || !dst) {
534 return PLDM_ERROR_INVALID_DATA;
535 }
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);
543 return PLDM_ERROR_INVALID_LENGTH;
544 }
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030545 ctx->remaining -= sizeof(ldst);
546 assert(ctx->remaining >= 0);
547 if (ctx->remaining < 0) {
548 return PLDM_ERROR_INVALID_LENGTH;
549 }
550
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030551 memcpy(&ldst, ctx->cursor, sizeof(ldst));
552 ldst = le32toh(ldst);
Andrew Jeffery66c77232024-04-24 11:42:02 +0930553 memcpy(dst, &ldst, sizeof(ldst));
554 ctx->cursor += sizeof(ldst);
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030555
556 return PLDM_SUCCESS;
557}
558
Andrew Jeffery66c77232024-04-24 11:42:02 +0930559/**
560 * Extract the field at the msgbuf cursor into the lvalue named by dst.
561 *
562 * @param ctx The msgbuf context object
563 * @param dst The lvalue into which the field at the msgbuf cursor should be
564 * extracted
565 *
566 * @return PLDM_SUCCESS on success, otherwise another value on error
567 */
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030568#define pldm_msgbuf_extract(ctx, dst) \
Andrew Jeffery66c77232024-04-24 11:42:02 +0930569 _Generic((dst), \
570 uint8_t: pldm__msgbuf_extract_uint8, \
571 int8_t: pldm__msgbuf_extract_int8, \
572 uint16_t: pldm__msgbuf_extract_uint16, \
573 int16_t: pldm__msgbuf_extract_int16, \
574 uint32_t: pldm__msgbuf_extract_uint32, \
575 int32_t: pldm__msgbuf_extract_int32, \
576 real32_t: pldm__msgbuf_extract_real32)(ctx, (void *)&(dst))
577
578/**
579 * Extract the field at the msgbuf cursor into the object pointed-to by dst.
580 *
581 * @param ctx The msgbuf context object
582 * @param dst The pointer to the object into which the field at the msgbuf
583 * cursor should be extracted
584 *
585 * @return PLDM_SUCCESS on success, otherwise another value on error
586 */
587#define pldm_msgbuf_extract_p(ctx, dst) \
588 _Generic((dst), \
589 uint8_t *: pldm__msgbuf_extract_uint8, \
590 int8_t *: pldm__msgbuf_extract_int8, \
591 uint16_t *: pldm__msgbuf_extract_uint16, \
592 int16_t *: pldm__msgbuf_extract_int16, \
593 uint32_t *: pldm__msgbuf_extract_uint32, \
594 int32_t *: pldm__msgbuf_extract_int32, \
595 real32_t *: pldm__msgbuf_extract_real32)(ctx, dst)
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030596
Andrew Jeffery76712f62024-05-22 15:19:00 +0930597__attribute__((always_inline)) static inline int
598pldm_msgbuf_extract_array_uint8(struct pldm_msgbuf *ctx, uint8_t *dst,
599 size_t count)
Andrew Jeffery369b1212023-04-20 15:44:48 +0930600{
Andrew Jeffery369b1212023-04-20 15:44:48 +0930601 if (!ctx || !ctx->cursor || !dst) {
602 return PLDM_ERROR_INVALID_DATA;
603 }
604
605 if (!count) {
606 return PLDM_SUCCESS;
607 }
608
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930609#if INTMAX_MAX < SIZE_MAX
610 if (count > INTMAX_MAX) {
Andrew Jeffery369b1212023-04-20 15:44:48 +0930611 return PLDM_ERROR_INVALID_LENGTH;
612 }
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930613#endif
Andrew Jeffery369b1212023-04-20 15:44:48 +0930614
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930615 if (ctx->remaining < INTMAX_MIN + (intmax_t)count) {
616 return PLDM_ERROR_INVALID_LENGTH;
617 }
618 ctx->remaining -= (intmax_t)count;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930619 assert(ctx->remaining >= 0);
620 if (ctx->remaining < 0) {
621 return PLDM_ERROR_INVALID_LENGTH;
622 }
623
Andrew Jefferya065ecc2023-10-27 15:02:11 +1030624 memcpy(dst, ctx->cursor, count);
625 ctx->cursor += count;
Andrew Jeffery369b1212023-04-20 15:44:48 +0930626
627 return PLDM_SUCCESS;
628}
629
630#define pldm_msgbuf_extract_array(ctx, dst, count) \
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930631 _Generic((*(dst)), uint8_t: pldm_msgbuf_extract_array_uint8)(ctx, dst, \
632 count)
Andrew Jeffery369b1212023-04-20 15:44:48 +0930633
Andrew Jeffery76712f62024-05-22 15:19:00 +0930634__attribute__((always_inline)) static inline int
635pldm_msgbuf_insert_uint32(struct pldm_msgbuf *ctx, const uint32_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700636{
637 uint32_t val = htole32(src);
638
639 if (!ctx || !ctx->cursor) {
640 return PLDM_ERROR_INVALID_DATA;
641 }
642
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930643 static_assert(
644 // NOLINTNEXTLINE(bugprone-sizeof-expression)
645 sizeof(src) < INTMAX_MAX,
646 "The following addition may not uphold the runtime assertion");
647 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
648 assert(ctx->remaining < 0);
649 return PLDM_ERROR_INVALID_LENGTH;
650 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700651 ctx->remaining -= sizeof(src);
652 assert(ctx->remaining >= 0);
653 if (ctx->remaining < 0) {
654 return PLDM_ERROR_INVALID_LENGTH;
655 }
656
657 memcpy(ctx->cursor, &val, sizeof(val));
658 ctx->cursor += sizeof(src);
659
660 return PLDM_SUCCESS;
661}
662
Andrew Jeffery76712f62024-05-22 15:19:00 +0930663__attribute__((always_inline)) static inline int
664pldm_msgbuf_insert_uint16(struct pldm_msgbuf *ctx, const uint16_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700665{
666 uint16_t val = htole16(src);
667
668 if (!ctx || !ctx->cursor) {
669 return PLDM_ERROR_INVALID_DATA;
670 }
671
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930672 static_assert(
673 // NOLINTNEXTLINE(bugprone-sizeof-expression)
674 sizeof(src) < INTMAX_MAX,
675 "The following addition may not uphold the runtime assertion");
676 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
677 assert(ctx->remaining < 0);
678 return PLDM_ERROR_INVALID_LENGTH;
679 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700680 ctx->remaining -= sizeof(src);
681 assert(ctx->remaining >= 0);
682 if (ctx->remaining < 0) {
683 return PLDM_ERROR_INVALID_LENGTH;
684 }
685
686 memcpy(ctx->cursor, &val, sizeof(val));
687 ctx->cursor += sizeof(src);
688
689 return PLDM_SUCCESS;
690}
691
Andrew Jeffery76712f62024-05-22 15:19:00 +0930692__attribute__((always_inline)) static inline int
693pldm_msgbuf_insert_uint8(struct pldm_msgbuf *ctx, const uint8_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700694{
695 if (!ctx || !ctx->cursor) {
696 return PLDM_ERROR_INVALID_DATA;
697 }
698
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930699 static_assert(
700 // NOLINTNEXTLINE(bugprone-sizeof-expression)
701 sizeof(src) < INTMAX_MAX,
702 "The following addition may not uphold the runtime assertion");
703 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
704 assert(ctx->remaining < 0);
705 return PLDM_ERROR_INVALID_LENGTH;
706 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700707 ctx->remaining -= sizeof(src);
708 assert(ctx->remaining >= 0);
709 if (ctx->remaining < 0) {
710 return PLDM_ERROR_INVALID_LENGTH;
711 }
712
713 memcpy(ctx->cursor, &src, sizeof(src));
714 ctx->cursor += sizeof(src);
715
716 return PLDM_SUCCESS;
717}
718
Andrew Jeffery76712f62024-05-22 15:19:00 +0930719__attribute__((always_inline)) static inline int
720pldm_msgbuf_insert_int32(struct pldm_msgbuf *ctx, const int32_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700721{
722 int32_t val = htole32(src);
723
724 if (!ctx || !ctx->cursor) {
725 return PLDM_ERROR_INVALID_DATA;
726 }
727
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930728 static_assert(
729 // NOLINTNEXTLINE(bugprone-sizeof-expression)
730 sizeof(src) < INTMAX_MAX,
731 "The following addition may not uphold the runtime assertion");
732 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
733 assert(ctx->remaining < 0);
734 return PLDM_ERROR_INVALID_LENGTH;
735 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700736 ctx->remaining -= sizeof(src);
737 assert(ctx->remaining >= 0);
738 if (ctx->remaining < 0) {
739 return PLDM_ERROR_INVALID_LENGTH;
740 }
741
742 memcpy(ctx->cursor, &val, sizeof(val));
743 ctx->cursor += sizeof(src);
744
745 return PLDM_SUCCESS;
746}
747
Andrew Jeffery76712f62024-05-22 15:19:00 +0930748__attribute__((always_inline)) static inline int
749pldm_msgbuf_insert_int16(struct pldm_msgbuf *ctx, const int16_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700750{
751 int16_t val = htole16(src);
752
753 if (!ctx || !ctx->cursor) {
754 return PLDM_ERROR_INVALID_DATA;
755 }
756
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930757 static_assert(
758 // NOLINTNEXTLINE(bugprone-sizeof-expression)
759 sizeof(src) < INTMAX_MAX,
760 "The following addition may not uphold the runtime assertion");
761 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
762 assert(ctx->remaining < 0);
763 return PLDM_ERROR_INVALID_LENGTH;
764 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700765 ctx->remaining -= sizeof(src);
766 assert(ctx->remaining >= 0);
767 if (ctx->remaining < 0) {
768 return PLDM_ERROR_INVALID_LENGTH;
769 }
770
771 memcpy(ctx->cursor, &val, sizeof(val));
772 ctx->cursor += sizeof(src);
773
774 return PLDM_SUCCESS;
775}
776
Andrew Jeffery76712f62024-05-22 15:19:00 +0930777__attribute__((always_inline)) static inline int
778pldm_msgbuf_insert_int8(struct pldm_msgbuf *ctx, const int8_t src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700779{
780 if (!ctx || !ctx->cursor) {
781 return PLDM_ERROR_INVALID_DATA;
782 }
783
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930784 static_assert(
785 // NOLINTNEXTLINE(bugprone-sizeof-expression)
786 sizeof(src) < INTMAX_MAX,
787 "The following addition may not uphold the runtime assertion");
788 if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
789 assert(ctx->remaining < 0);
790 return PLDM_ERROR_INVALID_LENGTH;
791 }
Thu Nguyen062c8762023-04-22 20:45:04 +0700792 ctx->remaining -= sizeof(src);
793 assert(ctx->remaining >= 0);
794 if (ctx->remaining < 0) {
795 return PLDM_ERROR_INVALID_LENGTH;
796 }
797
798 memcpy(ctx->cursor, &src, sizeof(src));
799 ctx->cursor += sizeof(src);
800
801 return PLDM_SUCCESS;
802}
803
804#define pldm_msgbuf_insert(dst, src) \
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930805 _Generic((src), \
806 uint8_t: pldm_msgbuf_insert_uint8, \
807 int8_t: pldm_msgbuf_insert_int8, \
808 uint16_t: pldm_msgbuf_insert_uint16, \
809 int16_t: pldm_msgbuf_insert_int16, \
810 uint32_t: pldm_msgbuf_insert_uint32, \
811 int32_t: pldm_msgbuf_insert_int32)(dst, src)
Thu Nguyen062c8762023-04-22 20:45:04 +0700812
Andrew Jeffery76712f62024-05-22 15:19:00 +0930813__attribute__((always_inline)) static inline int
814pldm_msgbuf_insert_array_uint8(struct pldm_msgbuf *ctx, const uint8_t *src,
815 size_t count)
Thu Nguyen062c8762023-04-22 20:45:04 +0700816{
Thu Nguyen062c8762023-04-22 20:45:04 +0700817 if (!ctx || !ctx->cursor || !src) {
818 return PLDM_ERROR_INVALID_DATA;
819 }
820
821 if (!count) {
822 return PLDM_SUCCESS;
823 }
824
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930825#if INTMAX_MAX < SIZE_MAX
826 if (count > INTMAX_MAX) {
Thu Nguyen062c8762023-04-22 20:45:04 +0700827 return PLDM_ERROR_INVALID_LENGTH;
828 }
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930829#endif
Thu Nguyen062c8762023-04-22 20:45:04 +0700830
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930831 if (ctx->remaining < INTMAX_MIN + (intmax_t)count) {
832 return PLDM_ERROR_INVALID_LENGTH;
833 }
834 ctx->remaining -= (intmax_t)count;
Thu Nguyen062c8762023-04-22 20:45:04 +0700835 assert(ctx->remaining >= 0);
836 if (ctx->remaining < 0) {
837 return PLDM_ERROR_INVALID_LENGTH;
838 }
839
Andrew Jefferya065ecc2023-10-27 15:02:11 +1030840 memcpy(ctx->cursor, src, count);
841 ctx->cursor += count;
Thu Nguyen062c8762023-04-22 20:45:04 +0700842
843 return PLDM_SUCCESS;
844}
845
846#define pldm_msgbuf_insert_array(dst, src, count) \
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930847 _Generic((*(src)), uint8_t: pldm_msgbuf_insert_array_uint8)(dst, src, \
848 count)
Thu Nguyen062c8762023-04-22 20:45:04 +0700849
Andrew Jeffery76712f62024-05-22 15:19:00 +0930850__attribute__((always_inline)) static inline int
851pldm_msgbuf_span_required(struct pldm_msgbuf *ctx, size_t required,
852 void **cursor)
Thu Nguyen062c8762023-04-22 20:45:04 +0700853{
854 if (!ctx || !ctx->cursor || !cursor || *cursor) {
855 return PLDM_ERROR_INVALID_DATA;
856 }
857
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930858#if INTMAX_MAX < SIZE_MAX
859 if (required > INTMAX_MAX) {
Thu Nguyen062c8762023-04-22 20:45:04 +0700860 return PLDM_ERROR_INVALID_LENGTH;
861 }
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930862#endif
Thu Nguyen062c8762023-04-22 20:45:04 +0700863
Andrew Jeffery2ff8cf82024-05-17 15:20:46 +0930864 if (ctx->remaining < INTMAX_MIN + (intmax_t)required) {
865 return PLDM_ERROR_INVALID_LENGTH;
866 }
867 ctx->remaining -= (intmax_t)required;
Thu Nguyen062c8762023-04-22 20:45:04 +0700868 assert(ctx->remaining >= 0);
869 if (ctx->remaining < 0) {
870 return PLDM_ERROR_INVALID_LENGTH;
871 }
872
873 *cursor = ctx->cursor;
874 ctx->cursor += required;
875
876 return PLDM_SUCCESS;
877}
878
Andrew Jeffery76712f62024-05-22 15:19:00 +0930879__attribute__((always_inline)) static inline int
880pldm_msgbuf_span_remaining(struct pldm_msgbuf *ctx, void **cursor, size_t *len)
Thu Nguyen062c8762023-04-22 20:45:04 +0700881{
882 if (!ctx || !ctx->cursor || !cursor || *cursor || !len) {
883 return PLDM_ERROR_INVALID_DATA;
884 }
885
886 assert(ctx->remaining >= 0);
887 if (ctx->remaining < 0) {
888 return PLDM_ERROR_INVALID_LENGTH;
889 }
890
891 *cursor = ctx->cursor;
892 ctx->cursor += ctx->remaining;
893 *len = ctx->remaining;
894 ctx->remaining = 0;
895
896 return PLDM_SUCCESS;
897}
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -0500898
899/**
900 * @brief pldm_msgbuf copy data between two msg buffers
901 *
902 * @param[inout] src - pldm_msgbuf for source from where value should be copied
903 * @param[inout] dst - destination of copy from source
904 * @param[in] size - size of data to be copied
905 * @param[in] description - description of data copied
906 *
907 * @return PLDM_SUCCESS if buffer accesses were in-bounds,
908 * PLDM_ERROR_INVALID_LENGTH otherwise.
909 * PLDM_ERROR_INVALID_DATA if input is invalid
910 */
911#define pldm_msgbuf_copy(dst, src, type, name) \
912 pldm__msgbuf_copy(dst, src, sizeof(type), #name)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930913__attribute__((always_inline)) static inline int
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -0500914// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
Andrew Jeffery76712f62024-05-22 15:19:00 +0930915pldm__msgbuf_copy(struct pldm_msgbuf *dst, struct pldm_msgbuf *src, size_t size,
916 const char *description)
Varsha Kaverappa909bf7c2024-05-03 06:18:42 -0500917{
918 if (!src || !src->cursor || !dst || !dst->cursor || !description) {
919 return PLDM_ERROR_INVALID_DATA;
920 }
921
922#if INTMAX_MAX < SIZE_MAX
923 if (size > INTMAX_MAX) {
924 return PLDM_ERROR_INVALID_LENGTH;
925 }
926#endif
927
928 if (src->remaining < INTMAX_MIN + (intmax_t)size) {
929 return PLDM_ERROR_INVALID_LENGTH;
930 }
931
932 if (dst->remaining < INTMAX_MIN + (intmax_t)size) {
933 return PLDM_ERROR_INVALID_LENGTH;
934 }
935
936 src->remaining -= (intmax_t)size;
937 assert(src->remaining >= 0);
938 if (src->remaining < 0) {
939 return PLDM_ERROR_INVALID_LENGTH;
940 }
941
942 dst->remaining -= (intmax_t)size;
943 assert(dst->remaining >= 0);
944 if (dst->remaining < 0) {
945 return PLDM_ERROR_INVALID_LENGTH;
946 }
947
948 memcpy(dst->cursor, src->cursor, size);
949 src->cursor += size;
950 dst->cursor += size;
951
952 return PLDM_SUCCESS;
953}
Andrew Jefferyc63f63a2023-02-24 22:29:33 +1030954#ifdef __cplusplus
955}
956#endif
957
Andrew Jeffery66c77232024-04-24 11:42:02 +0930958#ifdef __cplusplus
959#include <type_traits>
960
961template <typename T>
962static inline int pldm_msgbuf_typecheck_uint8_t(struct pldm_msgbuf *ctx,
963 void *buf)
964{
965 static_assert(std::is_same<uint8_t *, T>::value);
966 return pldm__msgbuf_extract_uint8(ctx, buf);
967}
968
969template <typename T>
970static inline int pldm_msgbuf_typecheck_int8_t(struct pldm_msgbuf *ctx,
971 void *buf)
972{
973 static_assert(std::is_same<int8_t *, T>::value);
974 return pldm__msgbuf_extract_int8(ctx, buf);
975}
976
977template <typename T>
978static inline int pldm_msgbuf_typecheck_uint16_t(struct pldm_msgbuf *ctx,
979 void *buf)
980{
981 static_assert(std::is_same<uint16_t *, T>::value);
982 return pldm__msgbuf_extract_uint16(ctx, buf);
983}
984
985template <typename T>
986static inline int pldm_msgbuf_typecheck_int16_t(struct pldm_msgbuf *ctx,
987 void *buf)
988{
989 static_assert(std::is_same<int16_t *, T>::value);
990 return pldm__msgbuf_extract_int16(ctx, buf);
991}
992
993template <typename T>
994static inline int pldm_msgbuf_typecheck_uint32_t(struct pldm_msgbuf *ctx,
995 void *buf)
996{
997 static_assert(std::is_same<uint32_t *, T>::value);
998 return pldm__msgbuf_extract_uint32(ctx, buf);
999}
1000
1001template <typename T>
1002static inline int pldm_msgbuf_typecheck_int32_t(struct pldm_msgbuf *ctx,
1003 void *buf)
1004{
1005 static_assert(std::is_same<int32_t *, T>::value);
1006 return pldm__msgbuf_extract_int32(ctx, buf);
1007}
1008
1009template <typename T>
1010static inline int pldm_msgbuf_typecheck_real32_t(struct pldm_msgbuf *ctx,
1011 void *buf)
1012{
1013 static_assert(std::is_same<real32_t *, T>::value);
1014 return pldm__msgbuf_extract_real32(ctx, buf);
1015}
1016#endif
1017
Andrew Jefferyc63f63a2023-02-24 22:29:33 +10301018#endif /* BUF_H */