xref: /openbmc/libpldm/src/msgbuf/core.h (revision f4d8810373a74760d5424218d45b8c9c56dcf3b2)
1 /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
2 #ifndef PLDM_MSGBUF_CORE_H
3 #define PLDM_MSGBUF_CORE_H
4 
5 /*
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 
31 #ifdef __cplusplus
32 /*
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__)
39 
40 extern "C" {
41 #endif
42 
43 #include "compiler.h"
44 
45 #include <libpldm/pldm_types.h>
46 
47 #include <endian.h>
48 #include <errno.h>
49 #include <stddef.h>
50 #include <stdint.h>
51 #include <string.h>
52 #include <uchar.h>
53 
54 /*
55  * We can't use static_assert() outside of some other C construct. Deal
56  * with high-level global assertions by burying them in an unused struct
57  * declaration, that has a sole member for compliance with the requirement that
58  * types must have a size.
59 */
60 static struct {
61 	static_assert(
62 		INTMAX_MAX != SIZE_MAX,
63 		"Extraction and insertion value comparisons may be broken");
64 	static_assert(INTMAX_MIN + INTMAX_MAX <= 0,
65 		      "Extraction and insertion arithmetic may be broken");
66 	int compliance;
67 } build_assertions LIBPLDM_CC_UNUSED;
68 
69 struct pldm_msgbuf_rw {
70 	uint8_t *cursor;
71 	intmax_t remaining;
72 };
73 
74 struct pldm_msgbuf_ro {
75 	const uint8_t *cursor;
76 	intmax_t remaining;
77 };
78 
79 LIBPLDM_CC_ALWAYS_INLINE
80 // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm__msgbuf_cleanup(const void * cursor LIBPLDM_CC_UNUSED,intmax_t remaining LIBPLDM_CC_UNUSED)81 void pldm__msgbuf_cleanup(const void *cursor LIBPLDM_CC_UNUSED,
82 			  intmax_t remaining LIBPLDM_CC_UNUSED)
83 {
84 	assert(cursor == NULL && remaining == INTMAX_MIN);
85 }
86 
87 LIBPLDM_CC_NONNULL
88 LIBPLDM_CC_ALWAYS_INLINE
89 // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm__msgbuf_rw_cleanup(struct pldm_msgbuf_rw * ctx LIBPLDM_CC_UNUSED)90 void pldm__msgbuf_rw_cleanup(struct pldm_msgbuf_rw *ctx LIBPLDM_CC_UNUSED)
91 {
92 	pldm__msgbuf_cleanup((const void *)ctx->cursor, ctx->remaining);
93 }
94 
95 LIBPLDM_CC_NONNULL
96 LIBPLDM_CC_ALWAYS_INLINE
97 // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm__msgbuf_ro_cleanup(struct pldm_msgbuf_ro * ctx LIBPLDM_CC_UNUSED)98 void pldm__msgbuf_ro_cleanup(struct pldm_msgbuf_ro *ctx LIBPLDM_CC_UNUSED)
99 {
100 	pldm__msgbuf_cleanup((const void *)ctx->cursor, ctx->remaining);
101 }
102 
103 LIBPLDM_CC_NONNULL
104 LIBPLDM_CC_ALWAYS_INLINE
105 // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm__msgbuf_set_invalid(intmax_t * remaining)106 int pldm__msgbuf_set_invalid(intmax_t *remaining)
107 {
108 	*remaining = INTMAX_MIN;
109 	return -EOVERFLOW;
110 }
111 
112 LIBPLDM_CC_NONNULL
113 LIBPLDM_CC_ALWAYS_INLINE
114 // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm__msgbuf_rw_invalidate(struct pldm_msgbuf_rw * ctx)115 int pldm__msgbuf_rw_invalidate(struct pldm_msgbuf_rw *ctx)
116 {
117 	return pldm__msgbuf_set_invalid(&ctx->remaining);
118 }
119 
120 LIBPLDM_CC_NONNULL
121 LIBPLDM_CC_ALWAYS_INLINE
122 // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm__msgbuf_ro_invalidate(struct pldm_msgbuf_ro * ctx)123 int pldm__msgbuf_ro_invalidate(struct pldm_msgbuf_ro *ctx)
124 {
125 	return pldm__msgbuf_set_invalid(&ctx->remaining);
126 }
127 
128 LIBPLDM_CC_NONNULL
129 LIBPLDM_CC_ALWAYS_INLINE
130 LIBPLDM_CC_WARN_UNUSED_RESULT
131 int
132 // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm__msgbuf_init_errno(const uint8_t ** cursor,intmax_t * remaining,size_t minsize,const void * buf,size_t len)133 pldm__msgbuf_init_errno(const uint8_t **cursor, intmax_t *remaining,
134 			size_t minsize, const void *buf, size_t len)
135 {
136 	*cursor = NULL;
137 
138 	if ((minsize > len)) {
139 		return pldm__msgbuf_set_invalid(remaining);
140 	}
141 
142 #if INTMAX_MAX < SIZE_MAX
143 	if (len > INTMAX_MAX) {
144 		return pldm__msgbuf_set_invalid(remaining);
145 	}
146 #endif
147 
148 	if (UINTPTR_MAX - (uintptr_t)buf < len) {
149 		return pldm__msgbuf_set_invalid(remaining);
150 	}
151 
152 	*cursor = (const uint8_t *)buf;
153 	*remaining = (intmax_t)len;
154 
155 	return 0;
156 }
157 
158 /**
159  * @brief Initialize pldm buf struct for buf extractor
160  *
161  * @param[out] ctx - pldm_msgbuf_rw context for extractor
162  * @param[in] minsize - The minimum required length of buffer `buf`
163  * @param[in] buf - buffer to be extracted
164  * @param[in] len - size of buffer
165  *
166  * @return 0 on success, otherwise an error code appropriate for the current
167  *         personality.
168  */
169 LIBPLDM_CC_NONNULL
170 LIBPLDM_CC_ALWAYS_INLINE
171 LIBPLDM_CC_WARN_UNUSED_RESULT
172 int
173 // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm_msgbuf_rw_init_errno(struct pldm_msgbuf_rw * ctx,size_t minsize,const void * buf,size_t len)174 pldm_msgbuf_rw_init_errno(struct pldm_msgbuf_rw *ctx, size_t minsize,
175 			  const void *buf, size_t len)
176 {
177 	return pldm__msgbuf_init_errno((const uint8_t **)&ctx->cursor,
178 				       &ctx->remaining, minsize, buf, len);
179 }
180 
181 /**
182  * @brief Initialize pldm buf struct for buf extractor
183  *
184  * @param[out] ctx - pldm_msgbuf_ro context for extractor
185  * @param[in] minsize - The minimum required length of buffer `buf`
186  * @param[in] buf - buffer to be extracted
187  * @param[in] len - size of buffer
188  *
189  * @return 0 on success, otherwise an error code appropriate for the current
190  *         personality.
191  */
192 LIBPLDM_CC_NONNULL
193 LIBPLDM_CC_ALWAYS_INLINE
194 LIBPLDM_CC_WARN_UNUSED_RESULT
195 int
196 // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm_msgbuf_ro_init_errno(struct pldm_msgbuf_ro * ctx,size_t minsize,const void * buf,size_t len)197 pldm_msgbuf_ro_init_errno(struct pldm_msgbuf_ro *ctx, size_t minsize,
198 			  const void *buf, size_t len)
199 {
200 	return pldm__msgbuf_init_errno(&ctx->cursor, &ctx->remaining, minsize,
201 				       buf, len);
202 }
203 
204 /**
205  * @brief Validate buffer overflow state
206  *
207  * @param[in] ctx - msgbuf context for extractor
208  *
209  * @return PLDM_SUCCESS if there are zero or more bytes of data that remain
210  * unread from the buffer. Otherwise, PLDM_ERROR_INVALID_LENGTH indicates that a
211  * prior accesses would have occurred beyond the bounds of the buffer, and
212  * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid
213  * pointer.
214  */
215 LIBPLDM_CC_NONNULL
216 LIBPLDM_CC_ALWAYS_INLINE
217 LIBPLDM_CC_WARN_UNUSED_RESULT
218 // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm__msgbuf_validate(intmax_t remaining)219 int pldm__msgbuf_validate(intmax_t remaining)
220 {
221 	if (remaining < 0) {
222 		return -EOVERFLOW;
223 	}
224 
225 	return 0;
226 }
227 
228 LIBPLDM_CC_NONNULL
229 LIBPLDM_CC_ALWAYS_INLINE
230 LIBPLDM_CC_WARN_UNUSED_RESULT
pldm_msgbuf_ro_validate(struct pldm_msgbuf_ro * ctx)231 int pldm_msgbuf_ro_validate(struct pldm_msgbuf_ro *ctx)
232 {
233 	return pldm__msgbuf_validate(ctx->remaining);
234 }
235 
236 LIBPLDM_CC_NONNULL
237 LIBPLDM_CC_ALWAYS_INLINE
238 LIBPLDM_CC_WARN_UNUSED_RESULT
pldm_msgbuf_rw_validate(struct pldm_msgbuf_rw * ctx)239 int pldm_msgbuf_rw_validate(struct pldm_msgbuf_rw *ctx)
240 {
241 	return pldm__msgbuf_validate(ctx->remaining);
242 }
243 
244 /**
245  * @brief Test whether a message buffer has been exactly consumed
246  *
247  * @param[in] ctx - pldm_msgbuf context for extractor
248  *
249  * @return 0 iff there are zero bytes of data that remain unread from the buffer
250  * and no overflow has occurred. Otherwise, -EBADMSG if the buffer has not been
251  * completely consumed, or -EOVERFLOW if accesses were attempted beyond the
252  * bounds of the buffer.
253  */
254 LIBPLDM_CC_NONNULL
255 LIBPLDM_CC_ALWAYS_INLINE
256 LIBPLDM_CC_WARN_UNUSED_RESULT
257 // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm__msgbuf_consumed(intmax_t remaining)258 int pldm__msgbuf_consumed(intmax_t remaining)
259 {
260 	if (remaining > 0) {
261 		return -EBADMSG;
262 	}
263 
264 	if (remaining < 0) {
265 		return -EOVERFLOW;
266 	}
267 
268 	return 0;
269 }
270 
271 LIBPLDM_CC_NONNULL
272 LIBPLDM_CC_ALWAYS_INLINE
273 LIBPLDM_CC_WARN_UNUSED_RESULT
pldm_msgbuf_ro_consumed(struct pldm_msgbuf_ro * ctx)274 int pldm_msgbuf_ro_consumed(struct pldm_msgbuf_ro *ctx)
275 {
276 	return pldm__msgbuf_consumed(ctx->remaining);
277 }
278 
279 LIBPLDM_CC_NONNULL
280 LIBPLDM_CC_ALWAYS_INLINE
281 LIBPLDM_CC_WARN_UNUSED_RESULT
pldm_msgbuf_rw_consumed(struct pldm_msgbuf_rw * ctx)282 int pldm_msgbuf_rw_consumed(struct pldm_msgbuf_rw *ctx)
283 {
284 	return pldm__msgbuf_consumed(ctx->remaining);
285 }
286 
287 /**
288  * @brief End use of a msgbuf under error conditions
289  *
290  * @param[in] ctx - The msgbuf instance to discard
291  * @param[in] error - The error value to propagate
292  *
293  * Under normal conditions use of a msgbuf instance must be ended using @ref
294  * pldm_msgbuf_complete or one of its related APIs. Under error conditions, @ref
295  * pldm_msgbuf_discard should be used instead, as it makes it straight-forward
296  * to finalise the msgbuf while propagating the existing error code.
297  *
298  * @return The value provided in @param error
299  */
300 LIBPLDM_CC_NONNULL
301 LIBPLDM_CC_ALWAYS_INLINE
302 LIBPLDM_CC_WARN_UNUSED_RESULT
303 // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm__msgbuf_discard(const uint8_t ** cursor,intmax_t * remaining,int error)304 int pldm__msgbuf_discard(const uint8_t **cursor, intmax_t *remaining, int error)
305 {
306 	*cursor = NULL;
307 	pldm__msgbuf_set_invalid(remaining);
308 	return error;
309 }
310 
311 LIBPLDM_CC_NONNULL
312 LIBPLDM_CC_ALWAYS_INLINE
313 LIBPLDM_CC_WARN_UNUSED_RESULT
pldm_msgbuf_rw_discard(struct pldm_msgbuf_rw * ctx,int error)314 int pldm_msgbuf_rw_discard(struct pldm_msgbuf_rw *ctx, int error)
315 {
316 	return pldm__msgbuf_discard((const uint8_t **)&ctx->cursor,
317 				    &ctx->remaining, error);
318 }
319 
320 LIBPLDM_CC_NONNULL
321 LIBPLDM_CC_ALWAYS_INLINE
322 LIBPLDM_CC_WARN_UNUSED_RESULT
pldm_msgbuf_ro_discard(struct pldm_msgbuf_ro * ctx,int error)323 int pldm_msgbuf_ro_discard(struct pldm_msgbuf_ro *ctx, int error)
324 {
325 	return pldm__msgbuf_discard(&ctx->cursor, &ctx->remaining, error);
326 }
327 
328 /**
329  * @brief Complete the pldm_msgbuf_rw instance
330  *
331  * @param[in] ctx - pldm_msgbuf_rw context for extractor
332  *
333  * @return 0 if all buffer accesses were in-bounds, -EOVERFLOW otherwise.
334  */
335 LIBPLDM_CC_NONNULL
336 LIBPLDM_CC_ALWAYS_INLINE
337 LIBPLDM_CC_WARN_UNUSED_RESULT
pldm_msgbuf_rw_complete(struct pldm_msgbuf_rw * ctx)338 int pldm_msgbuf_rw_complete(struct pldm_msgbuf_rw *ctx)
339 {
340 	return pldm_msgbuf_rw_discard(ctx, pldm_msgbuf_rw_validate(ctx));
341 }
342 
343 /**
344  * @brief Complete the pldm_msgbuf_ro instance
345  *
346  * @param[in] ctx - pldm_msgbuf_ro context for extractor
347  *
348  * @return 0 if all buffer accesses were in-bounds, -EOVERFLOW otherwise.
349  */
350 LIBPLDM_CC_NONNULL
351 LIBPLDM_CC_ALWAYS_INLINE
352 LIBPLDM_CC_WARN_UNUSED_RESULT
pldm_msgbuf_ro_complete(struct pldm_msgbuf_ro * ctx)353 int pldm_msgbuf_ro_complete(struct pldm_msgbuf_ro *ctx)
354 {
355 	return pldm_msgbuf_ro_discard(ctx, pldm_msgbuf_ro_validate(ctx));
356 }
357 
358 /**
359  * @brief Complete the pldm_msgbuf_rw instance, and check that the underlying buffer
360  * has been entirely consumed without overflow
361  *
362  * @param[in] ctx - pldm_msgbuf_rw context
363  *
364  * @return 0 if all buffer access were in-bounds and completely consume the
365  * underlying buffer. Otherwise, -EBADMSG if the buffer has not been completely
366  * consumed, or -EOVERFLOW if accesses were attempted beyond the bounds of the
367  * buffer.
368  */
369 LIBPLDM_CC_NONNULL
370 LIBPLDM_CC_ALWAYS_INLINE
371 LIBPLDM_CC_WARN_UNUSED_RESULT
pldm_msgbuf_rw_complete_consumed(struct pldm_msgbuf_rw * ctx)372 int pldm_msgbuf_rw_complete_consumed(struct pldm_msgbuf_rw *ctx)
373 {
374 	return pldm_msgbuf_rw_discard(ctx, pldm_msgbuf_rw_consumed(ctx));
375 }
376 
377 /**
378  * @brief Complete the pldm_msgbuf_ro instance, and check that the underlying buffer
379  * has been entirely consumed without overflow
380  *
381  * @param[in] ctx - pldm_msgbuf_ro context
382  *
383  * @return 0 if all buffer access were in-bounds and completely consume the
384  * underlying buffer. Otherwise, -EBADMSG if the buffer has not been completely
385  * consumed, or -EOVERFLOW if accesses were attempted beyond the bounds of the
386  * buffer.
387  */
388 LIBPLDM_CC_NONNULL
389 LIBPLDM_CC_ALWAYS_INLINE
390 LIBPLDM_CC_WARN_UNUSED_RESULT
pldm_msgbuf_ro_complete_consumed(struct pldm_msgbuf_ro * ctx)391 int pldm_msgbuf_ro_complete_consumed(struct pldm_msgbuf_ro *ctx)
392 {
393 	return pldm_msgbuf_ro_discard(ctx, pldm_msgbuf_ro_consumed(ctx));
394 }
395 
396 /*
397  * Exploit the pre-processor to perform type checking by macro substitution.
398  *
399  * A C type is defined by its alignment as well as its object
400  * size, and compilers have a hammer to enforce it in the form of
401  * `-Waddress-of-packed-member`. Due to the unpacked/packed struct conflict in
402  * the libpldm public API this presents a problem: Naively attempting to use the
403  * msgbuf APIs on a member of a packed struct would yield an error.
404  *
405  * The msgbuf APIs are implemented such that data is moved through unaligned
406  * pointers in a safe way, but to mitigate `-Waddress-of-packed-member` we must
407  * make the object pointers take a trip through `void *` at its API boundary.
408  * That presents a bit too much of an opportunity to non-surgically remove your
409  * own foot, so here we set about doing something to mitigate that as well.
410  *
411  * pldm_msgbuf_extract_typecheck() exists to enforce pointer type correctness
412  * only for the purpose of object sizes, disregarding alignment. We have a few
413  * constraints that cause some headaches:
414  *
415  * 1. We have to perform the type-check before a call through a C function,
416  *    as the function must take the object pointer argument as `void *`.
417  *    Essentially, this constrains us to doing something with macros.
418  *
419  * 2. While libpldm is a C library, its test suite is written in C++ to take
420  *    advantage of gtest.
421  *
422  * 3. Ideally we'd do something with C's `static_assert()`, however
423  *    `static_assert()` is defined as void, and as we're constrained to macros,
424  *    using `static_assert()` would require a statement-expression
425  *
426  * 4. Currently the project is built with `-std=c17`. CPP statement-expressions
427  *    are a GNU extension. We prefer to avoid switching to `-std=gnu17` just for
428  *    the purpose of enabling statement-expressions in this one instance.
429  *
430  * 5. We can achieve a conditional build error using `pldm_require_obj_type()`,
431  *    however it's implemented in terms of `_Generic()`, which is not available
432  *    in C++.
433  *
434  * Combined this means we need separate solutions for C and C++.
435  *
436  * For C, as we don't have statement-expressions, we need to exploit some other
437  * language feature to inject a `pldm_require_obj_type()` prior to the msgbuf
438  * API function call. We also have to take care of the fact that the call-sites
439  * may be in the context of a variable assignment for error-handling purposes.
440  * The key observation is that we can use the comma operator as a sequence point
441  * to order the type check before the API call, discarding the "result" value of
442  * the type check and yielding the return value of the API call.
443  *
444  * C++ could be less of a headache than the C as we can leverage template
445  * functions. An advantage of template functions is that while their definition
446  * is driven by instantion, the definition does not appear at the source
447  * location of the instantiation, which gives it a great leg-up over the problems
448  * we have in the C path. However, the use of the msgbuf APIs in the test suite
449  * still makes things somewhat tricky, as the call-sites in the test suite are
450  * wrapped up in EXPECT_*() gtest macros. Ideally we'd implement functions that
451  * takes both the object type and the required type as template arguments, and
452  * then define the object pointer parameter as `void *` for a call through to
453  * the appropriate msgbuf API. However, because the msgbuf API call-sites are
454  * encapsulated in gtest macros, use of commas in the template specification
455  * causes pre-processor confusion. In this way we're constrained to only one
456  * template argument per function.
457  *
458  * Implement the C++ path using template functions that take the destination
459  * object type as a template argument, while the name of the function symbols
460  * are derived from the required type. The manual implementations of these
461  * appear at the end of the header. The type safety is actually enforced
462  * by `static_assert()` this time, as we can use statements as we're not
463  * constrained to an expression in the templated function body.
464  *
465  * The invocations of pldm_msgbuf_extract_typecheck() typically result in
466  * double-evaluation of some arguments. We're not yet bothered by this for two
467  * reasons:
468  *
469  * 1. The nature of the current call-sites are such that there are no
470  *    argument expressions that result in undesirable side-effects
471  *
472  * 2. It's an API internal to the libpldm implementation, and we can fix things
473  *    whenever something crops up the violates the observation in 1.
474  */
475 
476 /**
477  * @brief pldm_msgbuf extractor for a uint8_t
478  *
479  * @param[in,out] ctx - pldm_msgbuf context for extractor
480  * @param[out] dst - destination of extracted value
481  *
482  * @return PLDM_SUCCESS if buffer accesses were in-bounds,
483  * PLDM_ERROR_INVALID_LENGTH otherwise.
484  * PLDM_ERROR_INVALID_DATA if input a invalid ctx
485  */
486 LIBPLDM_CC_NONNULL
487 LIBPLDM_CC_ALWAYS_INLINE int
488 // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm__msgbuf_extract_uint8(struct pldm_msgbuf_ro * ctx,void * dst)489 pldm__msgbuf_extract_uint8(struct pldm_msgbuf_ro *ctx, void *dst)
490 {
491 	if (ctx->remaining >= (intmax_t)sizeof(uint8_t)) {
492 		assert(ctx->cursor);
493 		memcpy(dst, ctx->cursor, sizeof(uint8_t));
494 		ctx->cursor++;
495 		ctx->remaining -= sizeof(uint8_t);
496 		return 0;
497 	}
498 
499 	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(uint8_t)) {
500 		ctx->remaining -= sizeof(uint8_t);
501 		return -EOVERFLOW;
502 	}
503 
504 	return pldm__msgbuf_ro_invalidate(ctx);
505 }
506 
507 LIBPLDM_CC_NONNULL
508 LIBPLDM_CC_ALWAYS_INLINE int
509 // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm__msgbuf_extract_int8(struct pldm_msgbuf_ro * ctx,void * dst)510 pldm__msgbuf_extract_int8(struct pldm_msgbuf_ro *ctx, void *dst)
511 {
512 	if (ctx->remaining >= (intmax_t)sizeof(int8_t)) {
513 		assert(ctx->cursor);
514 		memcpy(dst, ctx->cursor, sizeof(int8_t));
515 		ctx->cursor++;
516 		ctx->remaining -= sizeof(int8_t);
517 		return 0;
518 	}
519 
520 	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(int8_t)) {
521 		ctx->remaining -= sizeof(int8_t);
522 		return -EOVERFLOW;
523 	}
524 
525 	return pldm__msgbuf_ro_invalidate(ctx);
526 }
527 
528 LIBPLDM_CC_NONNULL
529 LIBPLDM_CC_ALWAYS_INLINE int
530 // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm__msgbuf_extract_uint16(struct pldm_msgbuf_ro * ctx,void * dst)531 pldm__msgbuf_extract_uint16(struct pldm_msgbuf_ro *ctx, void *dst)
532 {
533 	uint16_t ldst;
534 
535 	// Check for underflow while tracking the magnitude of the buffer overflow
536 	static_assert(
537 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
538 		sizeof(ldst) < INTMAX_MAX,
539 		"The following addition may not uphold the runtime assertion");
540 
541 	if (ctx->remaining >= (intmax_t)sizeof(ldst)) {
542 		assert(ctx->cursor);
543 
544 		// Use memcpy() to have the compiler deal with any alignment
545 		// issues on the target architecture
546 		memcpy(&ldst, ctx->cursor, sizeof(ldst));
547 
548 		// Only assign the target value once it's correctly decoded
549 		ldst = le16toh(ldst);
550 
551 		// Allow storing to unaligned
552 		memcpy(dst, &ldst, sizeof(ldst));
553 
554 		ctx->cursor += sizeof(ldst);
555 		ctx->remaining -= sizeof(ldst);
556 		return 0;
557 	}
558 
559 	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(ldst)) {
560 		ctx->remaining -= sizeof(ldst);
561 		return -EOVERFLOW;
562 	}
563 
564 	return pldm__msgbuf_ro_invalidate(ctx);
565 }
566 
567 LIBPLDM_CC_NONNULL
568 LIBPLDM_CC_ALWAYS_INLINE int
569 // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm__msgbuf_extract_int16(struct pldm_msgbuf_ro * ctx,void * dst)570 pldm__msgbuf_extract_int16(struct pldm_msgbuf_ro *ctx, void *dst)
571 {
572 	int16_t ldst;
573 
574 	static_assert(
575 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
576 		sizeof(ldst) < INTMAX_MAX,
577 		"The following addition may not uphold the runtime assertion");
578 
579 	if (ctx->remaining >= (intmax_t)sizeof(ldst)) {
580 		assert(ctx->cursor);
581 		memcpy(&ldst, ctx->cursor, sizeof(ldst));
582 		ldst = le16toh(ldst);
583 		memcpy(dst, &ldst, sizeof(ldst));
584 		ctx->cursor += sizeof(ldst);
585 		ctx->remaining -= sizeof(ldst);
586 		return 0;
587 	}
588 
589 	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(ldst)) {
590 		ctx->remaining -= sizeof(ldst);
591 		return -EOVERFLOW;
592 	}
593 
594 	return pldm__msgbuf_ro_invalidate(ctx);
595 }
596 
597 LIBPLDM_CC_NONNULL
598 LIBPLDM_CC_ALWAYS_INLINE int
599 // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm__msgbuf_extract_uint32(struct pldm_msgbuf_ro * ctx,void * dst)600 pldm__msgbuf_extract_uint32(struct pldm_msgbuf_ro *ctx, void *dst)
601 {
602 	uint32_t ldst;
603 
604 	static_assert(
605 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
606 		sizeof(ldst) < INTMAX_MAX,
607 		"The following addition may not uphold the runtime assertion");
608 
609 	if (ctx->remaining >= (intmax_t)sizeof(ldst)) {
610 		assert(ctx->cursor);
611 		memcpy(&ldst, ctx->cursor, sizeof(ldst));
612 		ldst = le32toh(ldst);
613 		memcpy(dst, &ldst, sizeof(ldst));
614 		ctx->cursor += sizeof(ldst);
615 		ctx->remaining -= sizeof(ldst);
616 		return 0;
617 	}
618 
619 	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(ldst)) {
620 		ctx->remaining -= sizeof(ldst);
621 		return -EOVERFLOW;
622 	}
623 
624 	return pldm__msgbuf_ro_invalidate(ctx);
625 }
626 
627 LIBPLDM_CC_NONNULL
628 LIBPLDM_CC_ALWAYS_INLINE int
629 // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm__msgbuf_extract_int32(struct pldm_msgbuf_ro * ctx,void * dst)630 pldm__msgbuf_extract_int32(struct pldm_msgbuf_ro *ctx, void *dst)
631 {
632 	int32_t ldst;
633 
634 	static_assert(
635 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
636 		sizeof(ldst) < INTMAX_MAX,
637 		"The following addition may not uphold the runtime assertion");
638 
639 	if (ctx->remaining >= (intmax_t)sizeof(ldst)) {
640 		assert(ctx->cursor);
641 		memcpy(&ldst, ctx->cursor, sizeof(ldst));
642 		ldst = le32toh(ldst);
643 		memcpy(dst, &ldst, sizeof(ldst));
644 		ctx->cursor += sizeof(ldst);
645 		ctx->remaining -= sizeof(ldst);
646 		return 0;
647 	}
648 
649 	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(ldst)) {
650 		ctx->remaining -= sizeof(ldst);
651 		return -EOVERFLOW;
652 	}
653 
654 	return pldm__msgbuf_ro_invalidate(ctx);
655 }
656 
657 LIBPLDM_CC_NONNULL
658 LIBPLDM_CC_ALWAYS_INLINE int
659 // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm__msgbuf_extract_real32(struct pldm_msgbuf_ro * ctx,void * dst)660 pldm__msgbuf_extract_real32(struct pldm_msgbuf_ro *ctx, void *dst)
661 {
662 	uint32_t ldst;
663 
664 	static_assert(sizeof(real32_t) == sizeof(ldst),
665 		      "Mismatched type sizes for dst and ldst");
666 
667 	static_assert(
668 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
669 		sizeof(ldst) < INTMAX_MAX,
670 		"The following addition may not uphold the runtime assertion");
671 
672 	if (ctx->remaining >= (intmax_t)sizeof(ldst)) {
673 		assert(ctx->cursor);
674 		memcpy(&ldst, ctx->cursor, sizeof(ldst));
675 		ldst = le32toh(ldst);
676 		memcpy(dst, &ldst, sizeof(ldst));
677 		ctx->cursor += sizeof(ldst);
678 		ctx->remaining -= sizeof(ldst);
679 		return 0;
680 	}
681 
682 	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(ldst)) {
683 		ctx->remaining -= sizeof(ldst);
684 		return -EOVERFLOW;
685 	}
686 
687 	return pldm__msgbuf_ro_invalidate(ctx);
688 }
689 
690 LIBPLDM_CC_NONNULL
691 LIBPLDM_CC_WARN_UNUSED_RESULT
692 LIBPLDM_CC_ALWAYS_INLINE int
693 // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm__msgbuf_extract_array_void(struct pldm_msgbuf_ro * ctx,size_t count,void * dst,size_t dst_count)694 pldm__msgbuf_extract_array_void(struct pldm_msgbuf_ro *ctx, size_t count,
695 				void *dst, size_t dst_count)
696 {
697 	if (count > dst_count) {
698 		return -EINVAL;
699 	}
700 
701 	if (!count) {
702 		return 0;
703 	}
704 
705 #if INTMAX_MAX < SIZE_MAX
706 	if (count > INTMAX_MAX) {
707 		return pldm__msgbuf_ro_invalidate(ctx);
708 	}
709 #endif
710 
711 	if (ctx->remaining >= (intmax_t)count) {
712 		assert(ctx->cursor);
713 		memcpy(dst, ctx->cursor, count);
714 		ctx->cursor += count;
715 		ctx->remaining -= (intmax_t)count;
716 		return 0;
717 	}
718 
719 	if (ctx->remaining > INTMAX_MIN + (intmax_t)count) {
720 		ctx->remaining -= (intmax_t)count;
721 		return -EOVERFLOW;
722 	}
723 
724 	return pldm__msgbuf_ro_invalidate(ctx);
725 }
726 
727 /**
728  * @ref pldm_msgbuf_extract_array
729  */
730 LIBPLDM_CC_NONNULL
731 LIBPLDM_CC_WARN_UNUSED_RESULT
732 LIBPLDM_CC_ALWAYS_INLINE int
pldm_msgbuf_extract_array_char(struct pldm_msgbuf_ro * ctx,size_t count,char * dst,size_t dst_count)733 pldm_msgbuf_extract_array_char(struct pldm_msgbuf_ro *ctx, size_t count,
734 			       char *dst, size_t dst_count)
735 {
736 	return pldm__msgbuf_extract_array_void(ctx, count, dst, dst_count);
737 }
738 
739 /**
740  * @ref pldm_msgbuf_extract_array
741  */
742 LIBPLDM_CC_NONNULL
743 LIBPLDM_CC_WARN_UNUSED_RESULT
744 LIBPLDM_CC_ALWAYS_INLINE int
pldm_msgbuf_extract_array_uint8(struct pldm_msgbuf_ro * ctx,size_t count,uint8_t * dst,size_t dst_count)745 pldm_msgbuf_extract_array_uint8(struct pldm_msgbuf_ro *ctx, size_t count,
746 				uint8_t *dst, size_t dst_count)
747 {
748 	return pldm__msgbuf_extract_array_void(ctx, count, dst, dst_count);
749 }
750 
751 /**
752  * Extract an array of data from the msgbuf instance
753  *
754  * @param ctx - The msgbuf instance from which to extract an array of data
755  * @param count - The number of array elements to extract
756  * @param dst - The array object into which elements from @p ctx should be
757                 extracted
758  * @param dst_count - The maximum number of elements to place into @p dst
759  *
760  * Note that both @p count and @p dst_count can only be counted by `sizeof` for
761  * arrays where `sizeof(*dst) == 1` holds. Specifically, they count the number
762  * of array elements and _not_ the object size of the array.
763  */
764 #define pldm_msgbuf_extract_array(ctx, count, dst, dst_count)                  \
765 	_Generic((*(dst)),                                                     \
766 		uint8_t: pldm_msgbuf_extract_array_uint8,                      \
767 		char: pldm_msgbuf_extract_array_char)(ctx, count, dst,         \
768 						      dst_count)
769 
770 LIBPLDM_CC_NONNULL
771 LIBPLDM_CC_ALWAYS_INLINE int
pldm_msgbuf_insert_uint64(struct pldm_msgbuf_rw * ctx,const uint64_t src)772 pldm_msgbuf_insert_uint64(struct pldm_msgbuf_rw *ctx, const uint64_t src)
773 {
774 	uint64_t val = htole64(src);
775 
776 	static_assert(
777 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
778 		sizeof(src) < INTMAX_MAX,
779 		"The following addition may not uphold the runtime assertion");
780 
781 	if (ctx->remaining >= (intmax_t)sizeof(src)) {
782 		assert(ctx->cursor);
783 		memcpy(ctx->cursor, &val, sizeof(val));
784 		ctx->cursor += sizeof(src);
785 		ctx->remaining -= sizeof(src);
786 		return 0;
787 	}
788 
789 	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(src)) {
790 		ctx->remaining -= sizeof(src);
791 		return -EOVERFLOW;
792 	}
793 
794 	return pldm__msgbuf_rw_invalidate(ctx);
795 }
796 
797 LIBPLDM_CC_NONNULL
798 LIBPLDM_CC_ALWAYS_INLINE int
pldm_msgbuf_insert_real32(struct pldm_msgbuf_rw * ctx,const real32_t src)799 pldm_msgbuf_insert_real32(struct pldm_msgbuf_rw *ctx, const real32_t src)
800 {
801 	uint32_t raw;
802 	memcpy(&raw, &src, sizeof(raw));
803 	uint32_t val = htole32(raw);
804 
805 	static_assert(
806 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
807 		sizeof(src) < INTMAX_MAX,
808 		"The following addition may not uphold the runtime assertion");
809 
810 	if (ctx->remaining >= (intmax_t)sizeof(src)) {
811 		assert(ctx->cursor);
812 		memcpy(ctx->cursor, &val, sizeof(val));
813 		ctx->cursor += sizeof(src);
814 		ctx->remaining -= sizeof(src);
815 		return 0;
816 	}
817 
818 	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(src)) {
819 		ctx->remaining -= sizeof(src);
820 		return -EOVERFLOW;
821 	}
822 
823 	return pldm__msgbuf_rw_invalidate(ctx);
824 }
825 
826 LIBPLDM_CC_NONNULL
827 LIBPLDM_CC_ALWAYS_INLINE int
pldm_msgbuf_insert_uint32(struct pldm_msgbuf_rw * ctx,const uint32_t src)828 pldm_msgbuf_insert_uint32(struct pldm_msgbuf_rw *ctx, const uint32_t src)
829 {
830 	uint32_t val = htole32(src);
831 
832 	static_assert(
833 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
834 		sizeof(src) < INTMAX_MAX,
835 		"The following addition may not uphold the runtime assertion");
836 
837 	if (ctx->remaining >= (intmax_t)sizeof(src)) {
838 		assert(ctx->cursor);
839 		memcpy(ctx->cursor, &val, sizeof(val));
840 		ctx->cursor += sizeof(src);
841 		ctx->remaining -= sizeof(src);
842 		return 0;
843 	}
844 
845 	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(src)) {
846 		ctx->remaining -= sizeof(src);
847 		return -EOVERFLOW;
848 	}
849 
850 	return pldm__msgbuf_rw_invalidate(ctx);
851 }
852 
853 LIBPLDM_CC_NONNULL
854 LIBPLDM_CC_ALWAYS_INLINE int
pldm_msgbuf_insert_uint16(struct pldm_msgbuf_rw * ctx,const uint16_t src)855 pldm_msgbuf_insert_uint16(struct pldm_msgbuf_rw *ctx, const uint16_t src)
856 {
857 	uint16_t val = htole16(src);
858 
859 	static_assert(
860 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
861 		sizeof(src) < INTMAX_MAX,
862 		"The following addition may not uphold the runtime assertion");
863 
864 	if (ctx->remaining >= (intmax_t)sizeof(src)) {
865 		assert(ctx->cursor);
866 		memcpy(ctx->cursor, &val, sizeof(val));
867 		ctx->cursor += sizeof(src);
868 		ctx->remaining -= sizeof(src);
869 		return 0;
870 	}
871 
872 	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(src)) {
873 		ctx->remaining -= sizeof(src);
874 		return -EOVERFLOW;
875 	}
876 
877 	return pldm__msgbuf_rw_invalidate(ctx);
878 }
879 
880 LIBPLDM_CC_NONNULL
881 LIBPLDM_CC_ALWAYS_INLINE int
pldm_msgbuf_insert_uint8(struct pldm_msgbuf_rw * ctx,const uint8_t src)882 pldm_msgbuf_insert_uint8(struct pldm_msgbuf_rw *ctx, const uint8_t src)
883 {
884 	static_assert(
885 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
886 		sizeof(src) < INTMAX_MAX,
887 		"The following addition may not uphold the runtime assertion");
888 
889 	if (ctx->remaining >= (intmax_t)sizeof(src)) {
890 		assert(ctx->cursor);
891 		memcpy(ctx->cursor, &src, sizeof(src));
892 		ctx->cursor += sizeof(src);
893 		ctx->remaining -= sizeof(src);
894 		return 0;
895 	}
896 
897 	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(src)) {
898 		ctx->remaining -= sizeof(src);
899 		return -EOVERFLOW;
900 	}
901 
902 	return pldm__msgbuf_rw_invalidate(ctx);
903 }
904 
905 LIBPLDM_CC_NONNULL
906 LIBPLDM_CC_ALWAYS_INLINE int
pldm_msgbuf_insert_int32(struct pldm_msgbuf_rw * ctx,const int32_t src)907 pldm_msgbuf_insert_int32(struct pldm_msgbuf_rw *ctx, const int32_t src)
908 {
909 	int32_t val = htole32(src);
910 
911 	static_assert(
912 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
913 		sizeof(src) < INTMAX_MAX,
914 		"The following addition may not uphold the runtime assertion");
915 
916 	if (ctx->remaining >= (intmax_t)sizeof(src)) {
917 		assert(ctx->cursor);
918 		memcpy(ctx->cursor, &val, sizeof(val));
919 		ctx->cursor += sizeof(src);
920 		ctx->remaining -= sizeof(src);
921 		return 0;
922 	}
923 
924 	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(src)) {
925 		ctx->remaining -= sizeof(src);
926 		return -EOVERFLOW;
927 	}
928 
929 	return pldm__msgbuf_rw_invalidate(ctx);
930 }
931 
932 LIBPLDM_CC_NONNULL
933 LIBPLDM_CC_ALWAYS_INLINE int
pldm_msgbuf_insert_int16(struct pldm_msgbuf_rw * ctx,const int16_t src)934 pldm_msgbuf_insert_int16(struct pldm_msgbuf_rw *ctx, const int16_t src)
935 {
936 	int16_t val = htole16(src);
937 
938 	static_assert(
939 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
940 		sizeof(src) < INTMAX_MAX,
941 		"The following addition may not uphold the runtime assertion");
942 
943 	if (ctx->remaining >= (intmax_t)sizeof(src)) {
944 		assert(ctx->cursor);
945 		memcpy(ctx->cursor, &val, sizeof(val));
946 		ctx->cursor += sizeof(src);
947 		ctx->remaining -= sizeof(src);
948 		return 0;
949 	}
950 
951 	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(src)) {
952 		ctx->remaining -= sizeof(src);
953 		return -EOVERFLOW;
954 	}
955 
956 	return pldm__msgbuf_rw_invalidate(ctx);
957 }
958 
959 LIBPLDM_CC_NONNULL
pldm_msgbuf_insert_int8(struct pldm_msgbuf_rw * ctx,const int8_t src)960 LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_int8(struct pldm_msgbuf_rw *ctx,
961 						     const int8_t src)
962 {
963 	static_assert(
964 		// NOLINTNEXTLINE(bugprone-sizeof-expression)
965 		sizeof(src) < INTMAX_MAX,
966 		"The following addition may not uphold the runtime assertion");
967 
968 	if (ctx->remaining >= (intmax_t)sizeof(src)) {
969 		assert(ctx->cursor);
970 		memcpy(ctx->cursor, &src, sizeof(src));
971 		ctx->cursor += sizeof(src);
972 		ctx->remaining -= sizeof(src);
973 		return 0;
974 	}
975 
976 	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(src)) {
977 		ctx->remaining -= sizeof(src);
978 		return -EOVERFLOW;
979 	}
980 
981 	return pldm__msgbuf_rw_invalidate(ctx);
982 }
983 
984 LIBPLDM_CC_NONNULL
985 LIBPLDM_CC_WARN_UNUSED_RESULT
986 LIBPLDM_CC_ALWAYS_INLINE int
987 // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm__msgbuf_insert_array_void(struct pldm_msgbuf_rw * ctx,size_t count,const void * src,size_t src_count)988 pldm__msgbuf_insert_array_void(struct pldm_msgbuf_rw *ctx, size_t count,
989 			       const void *src, size_t src_count)
990 {
991 	if (count > src_count) {
992 		return -EINVAL;
993 	}
994 
995 	if (!count) {
996 		return 0;
997 	}
998 
999 #if INTMAX_MAX < SIZE_MAX
1000 	if (count > INTMAX_MAX) {
1001 		return pldm__msgbuf_rw_invalidate(ctx);
1002 	}
1003 #endif
1004 
1005 	if (ctx->remaining >= (intmax_t)count) {
1006 		assert(ctx->cursor);
1007 		memcpy(ctx->cursor, src, count);
1008 		ctx->cursor += count;
1009 		ctx->remaining -= (intmax_t)count;
1010 		return 0;
1011 	}
1012 
1013 	if (ctx->remaining > INTMAX_MIN + (intmax_t)count) {
1014 		ctx->remaining -= (intmax_t)count;
1015 		return -EOVERFLOW;
1016 	}
1017 
1018 	return pldm__msgbuf_rw_invalidate(ctx);
1019 }
1020 
1021 LIBPLDM_CC_NONNULL
1022 LIBPLDM_CC_WARN_UNUSED_RESULT
1023 LIBPLDM_CC_ALWAYS_INLINE int
pldm_msgbuf_insert_array_char(struct pldm_msgbuf_rw * ctx,size_t count,const char * src,size_t src_count)1024 pldm_msgbuf_insert_array_char(struct pldm_msgbuf_rw *ctx, size_t count,
1025 			      const char *src, size_t src_count)
1026 {
1027 	return pldm__msgbuf_insert_array_void(ctx, count, src, src_count);
1028 }
1029 
1030 LIBPLDM_CC_NONNULL
1031 LIBPLDM_CC_WARN_UNUSED_RESULT
1032 LIBPLDM_CC_ALWAYS_INLINE int
pldm_msgbuf_insert_array_uint8(struct pldm_msgbuf_rw * ctx,size_t count,const uint8_t * src,size_t src_count)1033 pldm_msgbuf_insert_array_uint8(struct pldm_msgbuf_rw *ctx, size_t count,
1034 			       const uint8_t *src, size_t src_count)
1035 {
1036 	return pldm__msgbuf_insert_array_void(ctx, count, src, src_count);
1037 }
1038 
1039 LIBPLDM_CC_NONNULL_ARGS(1)
1040 LIBPLDM_CC_ALWAYS_INLINE int
1041 // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm__msgbuf_span_required(const uint8_t ** buf,intmax_t * remaining,size_t required,const void ** cursor)1042 pldm__msgbuf_span_required(const uint8_t **buf, intmax_t *remaining,
1043 			   size_t required, const void **cursor)
1044 {
1045 #if INTMAX_MAX < SIZE_MAX
1046 	if (required > INTMAX_MAX) {
1047 		return pldm__msgbuf_set_invalid(remaining);
1048 	}
1049 #endif
1050 
1051 	if (*remaining >= (intmax_t)required) {
1052 		assert(*buf);
1053 		if (cursor) {
1054 			*cursor = *buf;
1055 		}
1056 		*buf += required;
1057 		*remaining -= (intmax_t)required;
1058 		return 0;
1059 	}
1060 
1061 	if (*remaining > INTMAX_MIN + (intmax_t)required) {
1062 		*remaining -= (intmax_t)required;
1063 		return -EOVERFLOW;
1064 	}
1065 
1066 	return pldm__msgbuf_set_invalid(remaining);
1067 }
1068 
1069 LIBPLDM_CC_NONNULL_ARGS(1)
1070 LIBPLDM_CC_ALWAYS_INLINE int
pldm_msgbuf_ro_span_required(struct pldm_msgbuf_ro * ctx,size_t required,const void ** cursor)1071 pldm_msgbuf_ro_span_required(struct pldm_msgbuf_ro *ctx, size_t required,
1072 			     const void **cursor)
1073 {
1074 	return pldm__msgbuf_span_required(&ctx->cursor, &ctx->remaining,
1075 					  required, cursor);
1076 }
1077 
1078 LIBPLDM_CC_NONNULL_ARGS(1)
1079 LIBPLDM_CC_ALWAYS_INLINE int
pldm_msgbuf_rw_span_required(struct pldm_msgbuf_rw * ctx,size_t required,void ** cursor)1080 pldm_msgbuf_rw_span_required(struct pldm_msgbuf_rw *ctx, size_t required,
1081 			     void **cursor)
1082 {
1083 	return pldm__msgbuf_span_required((const uint8_t **)&ctx->cursor,
1084 					  &ctx->remaining, required,
1085 					  (const void **)cursor);
1086 }
1087 
1088 LIBPLDM_CC_NONNULL_ARGS(1)
1089 LIBPLDM_CC_ALWAYS_INLINE int
1090 // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm__msgbuf_span_string_ascii(const uint8_t ** buf,intmax_t * remaining,const void ** cursor,size_t * length)1091 pldm__msgbuf_span_string_ascii(const uint8_t **buf, intmax_t *remaining,
1092 			       const void **cursor, size_t *length)
1093 {
1094 	intmax_t measured;
1095 
1096 	if (*remaining < 0) {
1097 		return pldm__msgbuf_set_invalid(remaining);
1098 	}
1099 	assert(*buf);
1100 
1101 	measured = (intmax_t)strnlen((const char *)*buf, *remaining);
1102 	if (measured == *remaining) {
1103 		return pldm__msgbuf_set_invalid(remaining);
1104 	}
1105 
1106 	/* Include the NUL terminator in the span length, as spans are opaque */
1107 	measured++;
1108 
1109 	if (*remaining >= measured) {
1110 		assert(*buf);
1111 		if (cursor) {
1112 			*cursor = *buf;
1113 		}
1114 
1115 		*buf += measured;
1116 
1117 		if (length) {
1118 			*length = measured;
1119 		}
1120 
1121 		*remaining -= measured;
1122 		return 0;
1123 	}
1124 
1125 	if (*remaining > INTMAX_MIN + measured) {
1126 		*remaining -= measured;
1127 		return -EOVERFLOW;
1128 	}
1129 
1130 	return pldm__msgbuf_set_invalid(remaining);
1131 }
1132 
1133 LIBPLDM_CC_NONNULL_ARGS(1)
1134 LIBPLDM_CC_ALWAYS_INLINE int
pldm_msgbuf_rw_span_string_ascii(struct pldm_msgbuf_rw * ctx,void ** cursor,size_t * length)1135 pldm_msgbuf_rw_span_string_ascii(struct pldm_msgbuf_rw *ctx, void **cursor,
1136 				 size_t *length)
1137 {
1138 	return pldm__msgbuf_span_string_ascii((const uint8_t **)&ctx->cursor,
1139 					      &ctx->remaining,
1140 					      (const void **)cursor, length);
1141 }
1142 
1143 LIBPLDM_CC_NONNULL_ARGS(1)
1144 LIBPLDM_CC_ALWAYS_INLINE int
pldm_msgbuf_ro_span_string_ascii(struct pldm_msgbuf_ro * ctx,const void ** cursor,size_t * length)1145 pldm_msgbuf_ro_span_string_ascii(struct pldm_msgbuf_ro *ctx,
1146 				 const void **cursor, size_t *length)
1147 {
1148 	return pldm__msgbuf_span_string_ascii(&ctx->cursor, &ctx->remaining,
1149 					      cursor, length);
1150 }
1151 
1152 LIBPLDM_CC_NONNULL_ARGS(1)
1153 LIBPLDM_CC_ALWAYS_INLINE
1154 // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm__msgbuf_span_string_utf16(const uint8_t ** buf,intmax_t * remaining,const void ** cursor,size_t * length)1155 int pldm__msgbuf_span_string_utf16(const uint8_t **buf, intmax_t *remaining,
1156 				   const void **cursor, size_t *length)
1157 {
1158 	static const char16_t term = 0;
1159 	ptrdiff_t measured;
1160 	const void *end;
1161 
1162 	if (*remaining < 0) {
1163 		return pldm__msgbuf_set_invalid(remaining);
1164 	}
1165 	assert(*buf);
1166 
1167 	/*
1168 	 * Avoid tripping up on UTF16-LE: We may have consecutive NUL _bytes_ that do
1169 	 * not form a UTF16 NUL _code-point_ due to alignment with respect to the
1170 	 * start of the string
1171 	 */
1172 	end = *buf;
1173 	do {
1174 		if (end != *buf) {
1175 			/*
1176 			 * If we've looped we've found a relatively-unaligned NUL code-point.
1177 			 * Scan again from a relatively-aligned start point.
1178 			 */
1179 			end = (char *)end + 1;
1180 		}
1181 		measured = (char *)end - (char *)*buf;
1182 		end = memmem(end, *remaining - measured, &term, sizeof(term));
1183 	} while (end && ((uintptr_t)end & 1) != ((uintptr_t)*buf & 1));
1184 
1185 	if (!end) {
1186 		/*
1187 		 * Optimistically, the last required pattern byte was one beyond the end of
1188 		 * the buffer. Setting ctx->remaining negative ensures the
1189 		 * `pldm_msgbuf_complete*()` APIs also return an error.
1190 		 */
1191 		return pldm__msgbuf_set_invalid(remaining);
1192 	}
1193 
1194 	end = (char *)end + sizeof(char16_t);
1195 	measured = (char *)end - (char *)*buf;
1196 
1197 #if INTMAX_MAX < PTRDIFF_MAX
1198 	if (measured >= INTMAX_MAX) {
1199 		return pldm__msgbuf_set_invalid(remaining);
1200 	}
1201 #endif
1202 
1203 	if (*remaining >= (intmax_t)measured) {
1204 		assert(*buf);
1205 		if (cursor) {
1206 			*cursor = *buf;
1207 		}
1208 
1209 		*buf += measured;
1210 
1211 		if (length) {
1212 			*length = (size_t)measured;
1213 		}
1214 
1215 		*remaining -= (intmax_t)measured;
1216 		return 0;
1217 	}
1218 
1219 	if (*remaining > INTMAX_MIN + (intmax_t)measured) {
1220 		*remaining -= (intmax_t)measured;
1221 		return -EOVERFLOW;
1222 	}
1223 
1224 	return pldm__msgbuf_set_invalid(remaining);
1225 }
1226 
1227 LIBPLDM_CC_NONNULL_ARGS(1)
1228 LIBPLDM_CC_ALWAYS_INLINE int
pldm_msgbuf_ro_span_string_utf16(struct pldm_msgbuf_ro * ctx,const void ** cursor,size_t * length)1229 pldm_msgbuf_ro_span_string_utf16(struct pldm_msgbuf_ro *ctx,
1230 				 const void **cursor, size_t *length)
1231 {
1232 	return pldm__msgbuf_span_string_utf16(&ctx->cursor, &ctx->remaining,
1233 					      cursor, length);
1234 }
1235 
1236 LIBPLDM_CC_NONNULL_ARGS(1)
1237 LIBPLDM_CC_ALWAYS_INLINE int
pldm_msgbuf_rw_span_string_utf16(struct pldm_msgbuf_rw * ctx,void ** cursor,size_t * length)1238 pldm_msgbuf_rw_span_string_utf16(struct pldm_msgbuf_rw *ctx, void **cursor,
1239 				 size_t *length)
1240 {
1241 	return pldm__msgbuf_span_string_utf16((const uint8_t **)&ctx->cursor,
1242 					      &ctx->remaining,
1243 					      (const void **)cursor, length);
1244 }
1245 
1246 LIBPLDM_CC_NONNULL
1247 LIBPLDM_CC_ALWAYS_INLINE int
1248 // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm__msgbuf_span_remaining(const uint8_t ** buf,intmax_t * remaining,const void ** cursor,size_t * len)1249 pldm__msgbuf_span_remaining(const uint8_t **buf, intmax_t *remaining,
1250 			    const void **cursor, size_t *len)
1251 {
1252 	if (*remaining < 0) {
1253 		return -EOVERFLOW;
1254 	}
1255 
1256 	assert(*buf);
1257 	*cursor = *buf;
1258 	*buf += *remaining;
1259 	*len = *remaining;
1260 	*remaining = 0;
1261 
1262 	return 0;
1263 }
1264 
1265 LIBPLDM_CC_NONNULL
1266 LIBPLDM_CC_ALWAYS_INLINE int
pldm_msgbuf_rw_span_remaining(struct pldm_msgbuf_rw * ctx,void ** cursor,size_t * len)1267 pldm_msgbuf_rw_span_remaining(struct pldm_msgbuf_rw *ctx, void **cursor,
1268 			      size_t *len)
1269 {
1270 	return pldm__msgbuf_span_remaining((const uint8_t **)&ctx->cursor,
1271 					   &ctx->remaining,
1272 					   (const void **)cursor, len);
1273 }
1274 
1275 LIBPLDM_CC_NONNULL
1276 LIBPLDM_CC_ALWAYS_INLINE int
pldm_msgbuf_ro_span_remaining(struct pldm_msgbuf_ro * ctx,const void ** cursor,size_t * len)1277 pldm_msgbuf_ro_span_remaining(struct pldm_msgbuf_ro *ctx, const void **cursor,
1278 			      size_t *len)
1279 {
1280 	return pldm__msgbuf_span_remaining(&ctx->cursor, &ctx->remaining,
1281 					   cursor, len);
1282 }
1283 
1284 LIBPLDM_CC_NONNULL_ARGS(1)
1285 LIBPLDM_CC_ALWAYS_INLINE
1286 // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm__msgbuf_span_until(const uint8_t ** buf,intmax_t * remaining,size_t trailer,const void ** cursor,size_t * length)1287 int pldm__msgbuf_span_until(const uint8_t **buf, intmax_t *remaining,
1288 			    size_t trailer, const void **cursor, size_t *length)
1289 {
1290 #if INTMAX_MAX < SIZE_MAX
1291 	if (trailer > INTMAX_MAX) {
1292 		return pldm__msgbuf_set_invalid(remaining);
1293 	}
1294 #endif
1295 
1296 	if (*remaining >= (intmax_t)trailer) {
1297 		ptrdiff_t delta;
1298 
1299 		assert(*buf);
1300 
1301 		delta = *remaining - (intmax_t)trailer;
1302 		if (cursor) {
1303 			*cursor = *buf;
1304 		}
1305 		*buf += delta;
1306 		if (length) {
1307 			*length = delta;
1308 		}
1309 		*remaining = (intmax_t)trailer;
1310 		return 0;
1311 	}
1312 
1313 	if (*remaining > INTMAX_MIN + (intmax_t)trailer) {
1314 		*remaining = INTMAX_MIN + (intmax_t)trailer;
1315 		return -EOVERFLOW;
1316 	}
1317 
1318 	return pldm__msgbuf_set_invalid(remaining);
1319 }
1320 
1321 LIBPLDM_CC_NONNULL_ARGS(1)
1322 LIBPLDM_CC_ALWAYS_INLINE
pldm_msgbuf_ro_span_until(struct pldm_msgbuf_ro * ctx,size_t trailer,const void ** cursor,size_t * length)1323 int pldm_msgbuf_ro_span_until(struct pldm_msgbuf_ro *ctx, size_t trailer,
1324 			      const void **cursor, size_t *length)
1325 {
1326 	return pldm__msgbuf_span_until(&ctx->cursor, &ctx->remaining, trailer,
1327 				       cursor, length);
1328 }
1329 
1330 LIBPLDM_CC_NONNULL_ARGS(1)
1331 LIBPLDM_CC_ALWAYS_INLINE
pldm_msgbuf_rw_span_until(struct pldm_msgbuf_rw * ctx,size_t trailer,void ** cursor,size_t * length)1332 int pldm_msgbuf_rw_span_until(struct pldm_msgbuf_rw *ctx, size_t trailer,
1333 			      void **cursor, size_t *length)
1334 {
1335 	return pldm__msgbuf_span_until((const uint8_t **)&ctx->cursor,
1336 				       &ctx->remaining, trailer,
1337 				       (const void **)cursor, length);
1338 }
1339 
1340 LIBPLDM_CC_NONNULL
1341 LIBPLDM_CC_ALWAYS_INLINE int
pldm_msgbuf_peek_remaining(struct pldm_msgbuf_rw * ctx,void ** cursor,size_t * len)1342 pldm_msgbuf_peek_remaining(struct pldm_msgbuf_rw *ctx, void **cursor,
1343 			   size_t *len)
1344 {
1345 	if (ctx->remaining < 0) {
1346 		return -EOVERFLOW;
1347 	}
1348 
1349 	assert(ctx->cursor);
1350 	*cursor = ctx->cursor;
1351 	*len = ctx->remaining;
1352 
1353 	return 0;
1354 }
1355 
1356 LIBPLDM_CC_NONNULL
pldm_msgbuf_skip(struct pldm_msgbuf_rw * ctx,size_t count)1357 LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_skip(struct pldm_msgbuf_rw *ctx,
1358 					      size_t count)
1359 {
1360 #if INTMAX_MAX < SIZE_MAX
1361 	if (count > INTMAX_MAX) {
1362 		return pldm__msgbuf_rw_invalidate(ctx);
1363 	}
1364 #endif
1365 
1366 	if (ctx->remaining >= (intmax_t)count) {
1367 		assert(ctx->cursor);
1368 		ctx->cursor += count;
1369 		ctx->remaining -= (intmax_t)count;
1370 		return 0;
1371 	}
1372 
1373 	if (ctx->remaining > INTMAX_MIN + (intmax_t)count) {
1374 		ctx->remaining -= (intmax_t)count;
1375 		return -EOVERFLOW;
1376 	}
1377 
1378 	return pldm__msgbuf_rw_invalidate(ctx);
1379 }
1380 
1381 /**
1382  * @brief Complete the pldm_msgbuf instance and return the number of bytes
1383  * consumed.
1384  *
1385  * @param ctx - The msgbuf.
1386  * @param orig_len - The original size of the msgbuf, the `len` argument passed to
1387  * 		pldm_msgbuf_init_errno().
1388  * @param ret_used_len - The number of bytes that have been used from the msgbuf instance.
1389  *
1390  * This can be called after a number of pldm_msgbuf_insert...() calls to
1391  * determine the total size that was written.
1392  *
1393  * @return 0 on success, -EOVERFLOW if an implausible orig_len was provided or
1394  * an out-of-bounds access occurred.
1395  */
1396 LIBPLDM_CC_NONNULL
1397 LIBPLDM_CC_ALWAYS_INLINE
1398 LIBPLDM_CC_WARN_UNUSED_RESULT
pldm_msgbuf_complete_used(struct pldm_msgbuf_rw * ctx,size_t orig_len,size_t * ret_used_len)1399 int pldm_msgbuf_complete_used(struct pldm_msgbuf_rw *ctx, size_t orig_len,
1400 			      size_t *ret_used_len)
1401 {
1402 	int rc;
1403 
1404 	ctx->cursor = NULL;
1405 	rc = pldm_msgbuf_rw_validate(ctx);
1406 	if (rc) {
1407 		pldm__msgbuf_rw_invalidate(ctx);
1408 		return rc;
1409 	}
1410 
1411 	if ((size_t)ctx->remaining > orig_len) {
1412 		/* Caller passed incorrect orig_len */
1413 		return pldm__msgbuf_rw_invalidate(ctx);
1414 	}
1415 
1416 	*ret_used_len = orig_len - ctx->remaining;
1417 	pldm__msgbuf_rw_invalidate(ctx);
1418 	return 0;
1419 }
1420 
1421 /**
1422  * @brief pldm_msgbuf copy data between two msg buffers
1423  *
1424  * @param[in,out] src - pldm_msgbuf for source from where value should be copied
1425  * @param[in,out] dst - destination of copy from source
1426  * @param[in] size - size of data to be copied
1427  * @param[in] description - description of data copied
1428  *
1429  * @return PLDM_SUCCESS if buffer accesses were in-bounds,
1430  * PLDM_ERROR_INVALID_LENGTH otherwise.
1431  * PLDM_ERROR_INVALID_DATA if input is invalid
1432  */
1433 #define pldm_msgbuf_copy(dst, src, type, name)                                 \
1434 	pldm__msgbuf_copy(dst, src, sizeof(type), #name)
1435 LIBPLDM_CC_NONNULL
1436 LIBPLDM_CC_ALWAYS_INLINE int
1437 // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm__msgbuf_copy(struct pldm_msgbuf_rw * dst,struct pldm_msgbuf_ro * src,size_t size,const char * description LIBPLDM_CC_UNUSED)1438 pldm__msgbuf_copy(struct pldm_msgbuf_rw *dst, struct pldm_msgbuf_ro *src,
1439 		  size_t size, const char *description LIBPLDM_CC_UNUSED)
1440 {
1441 #if INTMAX_MAX < SIZE_MAX
1442 	if (size > INTMAX_MAX) {
1443 		pldm__msgbuf_ro_invalidate(src);
1444 		pldm__msgbuf_rw_invalidate(dst);
1445 		return -EOVERFLOW;
1446 	}
1447 #endif
1448 
1449 	if (src->remaining >= (intmax_t)size &&
1450 	    dst->remaining >= (intmax_t)size) {
1451 		assert(src->cursor && dst->cursor);
1452 		memcpy(dst->cursor, src->cursor, size);
1453 		src->cursor += size;
1454 		src->remaining -= (intmax_t)size;
1455 		dst->cursor += size;
1456 		dst->remaining -= (intmax_t)size;
1457 		return 0;
1458 	}
1459 
1460 	if (src->remaining > INTMAX_MIN + (intmax_t)size) {
1461 		src->remaining -= (intmax_t)size;
1462 	} else {
1463 		pldm__msgbuf_ro_invalidate(src);
1464 	}
1465 
1466 	if (dst->remaining > INTMAX_MIN + (intmax_t)size) {
1467 		dst->remaining -= (intmax_t)size;
1468 	} else {
1469 		pldm__msgbuf_rw_invalidate(dst);
1470 	}
1471 
1472 	return -EOVERFLOW;
1473 }
1474 
1475 LIBPLDM_CC_NONNULL
1476 LIBPLDM_CC_WARN_UNUSED_RESULT
1477 LIBPLDM_CC_ALWAYS_INLINE int
pldm_msgbuf_copy_string_ascii(struct pldm_msgbuf_rw * dst,struct pldm_msgbuf_ro * src)1478 pldm_msgbuf_copy_string_ascii(struct pldm_msgbuf_rw *dst,
1479 			      struct pldm_msgbuf_ro *src)
1480 {
1481 	const void *ascii = NULL;
1482 	size_t len = 0;
1483 	int rc;
1484 
1485 	rc = pldm_msgbuf_ro_span_string_ascii(src, &ascii, &len);
1486 	if (rc < 0) {
1487 		return rc;
1488 	}
1489 
1490 	return pldm__msgbuf_insert_array_void(dst, len, ascii, len);
1491 }
1492 
1493 LIBPLDM_CC_NONNULL
1494 LIBPLDM_CC_WARN_UNUSED_RESULT
1495 LIBPLDM_CC_ALWAYS_INLINE int
pldm_msgbuf_copy_string_utf16(struct pldm_msgbuf_rw * dst,struct pldm_msgbuf_ro * src)1496 pldm_msgbuf_copy_string_utf16(struct pldm_msgbuf_rw *dst,
1497 			      struct pldm_msgbuf_ro *src)
1498 {
1499 	const void *utf16 = NULL;
1500 	size_t len = 0;
1501 	int rc;
1502 
1503 	rc = pldm_msgbuf_ro_span_string_utf16(src, &utf16, &len);
1504 	if (rc < 0) {
1505 		return rc;
1506 	}
1507 
1508 	return pldm__msgbuf_insert_array_void(dst, len, utf16, len);
1509 }
1510 
1511 /**
1512  * @brief pldm_msgbuf uint8_t extractor for a size_t
1513  *
1514  * @param[in,out] ctx - pldm_msgbuf context for extractor
1515  * @param[out] dst - destination of extracted value
1516  *
1517  * @return 0 if buffer accesses were in-bounds,
1518  * -EINVAL if dst pointer is invalid,
1519  * -EOVERFLOW is the buffer was out of bound.
1520  */
1521 #define pldm_msgbuf_extract_uint8_to_size(ctx, dst)                            \
1522 	pldm__msgbuf_extract_uint8_to_size(ctx, &(dst))
1523 LIBPLDM_CC_NONNULL
1524 LIBPLDM_CC_ALWAYS_INLINE int
1525 // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm__msgbuf_extract_uint8_to_size(struct pldm_msgbuf_ro * ctx,size_t * dst)1526 pldm__msgbuf_extract_uint8_to_size(struct pldm_msgbuf_ro *ctx, size_t *dst)
1527 {
1528 	uint8_t value = 0;
1529 	int rc;
1530 
1531 	rc = pldm__msgbuf_extract_uint8(ctx, &value);
1532 	if (rc) {
1533 		return rc;
1534 	}
1535 
1536 	static_assert(SIZE_MAX >= UINT8_MAX, "Invalid promotion");
1537 
1538 	*dst = value;
1539 	return 0;
1540 }
1541 
1542 /**
1543  * @brief pldm_msgbuf uint16_t extractor for a size_t
1544  *
1545  * @param[in,out] ctx - pldm_msgbuf context for extractor
1546  * @param[out] dst - destination of extracted value
1547  *
1548  * @return 0 if buffer accesses were in-bounds,
1549  * -EINVAL if dst pointer is invalid,
1550  * -EOVERFLOW is the buffer was out of bound.
1551  */
1552 #define pldm_msgbuf_extract_uint16_to_size(ctx, dst)                           \
1553 	pldm__msgbuf_extract_uint16_to_size(ctx, &(dst))
1554 LIBPLDM_CC_NONNULL
1555 LIBPLDM_CC_ALWAYS_INLINE int
1556 // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm__msgbuf_extract_uint16_to_size(struct pldm_msgbuf_ro * ctx,size_t * dst)1557 pldm__msgbuf_extract_uint16_to_size(struct pldm_msgbuf_ro *ctx, size_t *dst)
1558 {
1559 	uint16_t value = 0;
1560 	int rc;
1561 
1562 	rc = pldm__msgbuf_extract_uint16(ctx, &value);
1563 	if (rc) {
1564 		return rc;
1565 	}
1566 
1567 	static_assert(SIZE_MAX >= UINT16_MAX, "Invalid promotion");
1568 
1569 	*dst = value;
1570 	return 0;
1571 }
1572 
1573 /**
1574  * @brief pldm_msgbuf uint32_t extractor for a size_t
1575  *
1576  * @param[in,out] ctx - pldm_msgbuf context for extractor
1577  * @param[out] dst - destination of extracted value
1578  *
1579  * @return 0 if buffer accesses were in-bounds,
1580  * -EINVAL if dst pointer is invalid,
1581  * -EOVERFLOW is the buffer was out of bound.
1582  */
1583 #define pldm_msgbuf_extract_uint32_to_size(ctx, dst)                           \
1584 	pldm__msgbuf_extract_uint32_to_size(ctx, &(dst))
1585 LIBPLDM_CC_NONNULL
1586 LIBPLDM_CC_ALWAYS_INLINE int
1587 // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm__msgbuf_extract_uint32_to_size(struct pldm_msgbuf_ro * ctx,size_t * dst)1588 pldm__msgbuf_extract_uint32_to_size(struct pldm_msgbuf_ro *ctx, size_t *dst)
1589 {
1590 	uint32_t value = 0;
1591 	int rc;
1592 
1593 	rc = pldm__msgbuf_extract_uint32(ctx, &value);
1594 	if (rc) {
1595 		return rc;
1596 	}
1597 
1598 	static_assert(SIZE_MAX >= UINT32_MAX, "Invalid promotion");
1599 
1600 	*dst = value;
1601 	return 0;
1602 }
1603 
1604 #ifdef __cplusplus
1605 }
1606 #endif
1607 
1608 #endif
1609