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