msgbuf: Rework error handling to improve soundness
Design the implementation to uphold the invariant that a non-negative
remaining value implies the cursor pointer is valid, and that under
other conditions error values must be observed by the msgbuf user. The
former is tested with assertions in the implementation. The latter is
enforced by construction.
With this change, all msgbuf instances for which
pldm_msgbuf_init_errno() succeeds must be either completed or discarded
by calls to the pldm_msgbuf_complete*() or pldm_msgbuf_discard() APIs
respectively.
We then build on the properties that:
- pldm_msgbuf_init_errno() is marked with the warn_unused_result
function attribute
- pldm_msgbuf_init_errno() returns errors for invalid buffer
configurations
- The complete and discard APIs are marked with the warn_unused_result
function attribute
- The complete APIs test for negative remaining values and return an
error if encountered.
- The discard API propagates the provided error code
Together these provide the foundation to ensure that buffer access
errors are (eventually) detected.
A msgbuf object is always in one of the uninitialized, valid, invalid,
or completed states. The states are defined as follows:
- Uninitialized: Undefined values for remaining and cursor
- Valid: cursor points to a valid object, remaining is both non-negative
and describes a range contained within the object pointed to
by cursor
- Invalid: The value of remaining is negative. The value of cursor is
unspecified.
- Completed: the value of remaining is INTMAX_MIN and cursor is NULL
msgbuf instances must always be in the completed state by the time
their storage is reclaimed. To enforce this, PLDM_MSGBUF_DEFINE_P()
is introduced both to simplify definition of related variables, and
to exploit the compiler's 'cleanup' attribute. The cleanup function
associated with the msgbuf object asserts that the referenced object is
in the completed state.
From there, update the implementations of the msgbuf APIs such that
exceeding implementation type limits forces the msgbuf object to the
invalid state (in addition to returning an error value) to relieve the
caller from testing the result of all API invocations.
Change-Id: I4d78ddc5f567d4148f2f6d8f3e7570e97c316bbb
Signed-off-by: Andrew Jeffery <andrew@codeconstruct.com.au>
diff --git a/src/msgbuf.h b/src/msgbuf.h
index cf30bad..d33d8e9 100644
--- a/src/msgbuf.h
+++ b/src/msgbuf.h
@@ -76,6 +76,37 @@
intmax_t remaining;
};
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE
+// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
+void pldm__msgbuf_cleanup(struct pldm_msgbuf *ctx LIBPLDM_CC_UNUSED)
+{
+ assert(ctx->cursor == NULL && ctx->remaining == INTMAX_MIN);
+}
+
+#ifdef __cplusplus
+// NOLINTBEGIN(bugprone-macro-parentheses)
+#define PLDM_MSGBUF_DEFINE_P(name) \
+ struct pldm_msgbuf _##name LIBPLDM_CC_CLEANUP( \
+ pldm__msgbuf_cleanup) = { NULL, INTMAX_MIN }; \
+ auto *name = &(_##name)
+// NOLINTEND(bugprone-macro-parentheses)
+#else
+#define PLDM_MSGBUF_DEFINE_P(name) \
+ struct pldm_msgbuf _##name LIBPLDM_CC_CLEANUP( \
+ pldm__msgbuf_cleanup) = { NULL, INTMAX_MIN }; \
+ struct pldm_msgbuf *(name) = &(_##name)
+#endif
+
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE
+// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
+int pldm__msgbuf_invalidate(struct pldm_msgbuf *ctx)
+{
+ ctx->remaining = INTMAX_MIN;
+ return -EOVERFLOW;
+}
+
/**
* @brief Initialize pldm buf struct for buf extractor
*
@@ -95,18 +126,20 @@
pldm_msgbuf_init_errno(struct pldm_msgbuf *ctx, size_t minsize, const void *buf,
size_t len)
{
+ ctx->cursor = NULL;
+
if ((minsize > len)) {
- return -EOVERFLOW;
+ return pldm__msgbuf_invalidate(ctx);
}
#if INTMAX_MAX < SIZE_MAX
if (len > INTMAX_MAX) {
- return -EOVERFLOW;
+ return pldm__msgbuf_invalidate(ctx);
}
#endif
if (UINTPTR_MAX - (uintptr_t)buf < len) {
- return -EOVERFLOW;
+ return pldm__msgbuf_invalidate(ctx);
}
ctx->cursor = (uint8_t *)buf;
@@ -165,6 +198,29 @@
}
/**
+ * @brief End use of a msgbuf under error conditions
+ *
+ * @param[in] ctx - The msgbuf instance to discard
+ * @param[in] error - The error value to propagate
+ *
+ * Under normal conditions use of a msgbuf instance must be ended using @ref
+ * pldm_msgbuf_complete or one of its related APIs. Under error conditions, @ref
+ * pldm_msgbuf_discard should be used instead, as it makes it straight-forward
+ * to finalise the msgbuf while propagating the existing error code.
+ *
+ * @return The value provided in @param error
+ */
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE
+LIBPLDM_CC_WARN_UNUSED_RESULT
+int pldm_msgbuf_discard(struct pldm_msgbuf *ctx, int error)
+{
+ ctx->cursor = NULL;
+ pldm__msgbuf_invalidate(ctx);
+ return error;
+}
+
+/**
* @brief Complete the pldm_msgbuf instance
*
* @param[in] ctx - pldm_msgbuf context for extractor
@@ -176,14 +232,7 @@
LIBPLDM_CC_WARN_UNUSED_RESULT
int pldm_msgbuf_complete(struct pldm_msgbuf *ctx)
{
- int valid;
-
- valid = pldm_msgbuf_validate(ctx);
-
- ctx->cursor = NULL;
- ctx->remaining = 0;
-
- return valid;
+ return pldm_msgbuf_discard(ctx, pldm_msgbuf_validate(ctx));
}
/**
@@ -202,14 +251,7 @@
LIBPLDM_CC_WARN_UNUSED_RESULT
int pldm_msgbuf_complete_consumed(struct pldm_msgbuf *ctx)
{
- int consumed;
-
- consumed = pldm_msgbuf_consumed(ctx);
-
- ctx->cursor = NULL;
- ctx->remaining = 0;
-
- return consumed;
+ return pldm_msgbuf_discard(ctx, pldm_msgbuf_consumed(ctx));
}
/*
@@ -317,22 +359,20 @@
// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm__msgbuf_extract_uint8(struct pldm_msgbuf *ctx, void *dst)
{
- if (!ctx->cursor) {
- return -EINVAL;
- }
-
if (ctx->remaining >= (intmax_t)sizeof(uint8_t)) {
+ assert(ctx->cursor);
memcpy(dst, ctx->cursor, sizeof(uint8_t));
ctx->cursor++;
ctx->remaining -= sizeof(uint8_t);
return 0;
}
- if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(uint8_t)) {
+ if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(uint8_t)) {
ctx->remaining -= sizeof(uint8_t);
+ return -EOVERFLOW;
}
- return -EOVERFLOW;
+ return pldm__msgbuf_invalidate(ctx);
}
#define pldm_msgbuf_extract_int8(ctx, dst) \
@@ -343,22 +383,20 @@
// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
pldm__msgbuf_extract_int8(struct pldm_msgbuf *ctx, void *dst)
{
- if (!ctx->cursor) {
- return -EINVAL;
- }
-
if (ctx->remaining >= (intmax_t)sizeof(int8_t)) {
+ assert(ctx->cursor);
memcpy(dst, ctx->cursor, sizeof(int8_t));
ctx->cursor++;
ctx->remaining -= sizeof(int8_t);
return 0;
}
- if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(int8_t)) {
+ if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(int8_t)) {
ctx->remaining -= sizeof(int8_t);
+ return -EOVERFLOW;
}
- return -EOVERFLOW;
+ return pldm__msgbuf_invalidate(ctx);
}
#define pldm_msgbuf_extract_uint16(ctx, dst) \
@@ -371,10 +409,6 @@
{
uint16_t ldst;
- if (!ctx->cursor) {
- return -EINVAL;
- }
-
// Check for underflow while tracking the magnitude of the buffer overflow
static_assert(
// NOLINTNEXTLINE(bugprone-sizeof-expression)
@@ -382,6 +416,8 @@
"The following addition may not uphold the runtime assertion");
if (ctx->remaining >= (intmax_t)sizeof(ldst)) {
+ assert(ctx->cursor);
+
// Use memcpy() to have the compiler deal with any alignment
// issues on the target architecture
memcpy(&ldst, ctx->cursor, sizeof(ldst));
@@ -397,11 +433,12 @@
return 0;
}
- if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(ldst)) {
+ if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(ldst)) {
ctx->remaining -= sizeof(ldst);
+ return -EOVERFLOW;
}
- return -EOVERFLOW;
+ return pldm__msgbuf_invalidate(ctx);
}
#define pldm_msgbuf_extract_int16(ctx, dst) \
@@ -414,16 +451,13 @@
{
int16_t ldst;
- if (!ctx->cursor) {
- return -EINVAL;
- }
-
static_assert(
// NOLINTNEXTLINE(bugprone-sizeof-expression)
sizeof(ldst) < INTMAX_MAX,
"The following addition may not uphold the runtime assertion");
if (ctx->remaining >= (intmax_t)sizeof(ldst)) {
+ assert(ctx->cursor);
memcpy(&ldst, ctx->cursor, sizeof(ldst));
ldst = le16toh(ldst);
memcpy(dst, &ldst, sizeof(ldst));
@@ -432,11 +466,12 @@
return 0;
}
- if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(ldst)) {
+ if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(ldst)) {
ctx->remaining -= sizeof(ldst);
+ return -EOVERFLOW;
}
- return -EOVERFLOW;
+ return pldm__msgbuf_invalidate(ctx);
}
#define pldm_msgbuf_extract_uint32(ctx, dst) \
@@ -449,16 +484,13 @@
{
uint32_t ldst;
- if (!ctx->cursor) {
- return -EINVAL;
- }
-
static_assert(
// NOLINTNEXTLINE(bugprone-sizeof-expression)
sizeof(ldst) < INTMAX_MAX,
"The following addition may not uphold the runtime assertion");
if (ctx->remaining >= (intmax_t)sizeof(ldst)) {
+ assert(ctx->cursor);
memcpy(&ldst, ctx->cursor, sizeof(ldst));
ldst = le32toh(ldst);
memcpy(dst, &ldst, sizeof(ldst));
@@ -467,11 +499,12 @@
return 0;
}
- if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(ldst)) {
+ if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(ldst)) {
ctx->remaining -= sizeof(ldst);
+ return -EOVERFLOW;
}
- return -EOVERFLOW;
+ return pldm__msgbuf_invalidate(ctx);
}
#define pldm_msgbuf_extract_int32(ctx, dst) \
@@ -484,16 +517,13 @@
{
int32_t ldst;
- if (!ctx->cursor) {
- return -EINVAL;
- }
-
static_assert(
// NOLINTNEXTLINE(bugprone-sizeof-expression)
sizeof(ldst) < INTMAX_MAX,
"The following addition may not uphold the runtime assertion");
if (ctx->remaining >= (intmax_t)sizeof(ldst)) {
+ assert(ctx->cursor);
memcpy(&ldst, ctx->cursor, sizeof(ldst));
ldst = le32toh(ldst);
memcpy(dst, &ldst, sizeof(ldst));
@@ -502,11 +532,12 @@
return 0;
}
- if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(ldst)) {
+ if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(ldst)) {
ctx->remaining -= sizeof(ldst);
+ return -EOVERFLOW;
}
- return -EOVERFLOW;
+ return pldm__msgbuf_invalidate(ctx);
}
#define pldm_msgbuf_extract_real32(ctx, dst) \
@@ -522,16 +553,13 @@
static_assert(sizeof(real32_t) == sizeof(ldst),
"Mismatched type sizes for dst and ldst");
- if (!ctx->cursor) {
- return -EINVAL;
- }
-
static_assert(
// NOLINTNEXTLINE(bugprone-sizeof-expression)
sizeof(ldst) < INTMAX_MAX,
"The following addition may not uphold the runtime assertion");
if (ctx->remaining >= (intmax_t)sizeof(ldst)) {
+ assert(ctx->cursor);
memcpy(&ldst, ctx->cursor, sizeof(ldst));
ldst = le32toh(ldst);
memcpy(dst, &ldst, sizeof(ldst));
@@ -540,11 +568,12 @@
return 0;
}
- if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(ldst)) {
+ if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(ldst)) {
ctx->remaining -= sizeof(ldst);
+ return -EOVERFLOW;
}
- return -EOVERFLOW;
+ return pldm__msgbuf_invalidate(ctx);
}
/**
@@ -595,7 +624,7 @@
pldm__msgbuf_extract_array_void(struct pldm_msgbuf *ctx, size_t count,
void *dst, size_t dst_count)
{
- if (!ctx->cursor || count > dst_count) {
+ if (count > dst_count) {
return -EINVAL;
}
@@ -605,22 +634,24 @@
#if INTMAX_MAX < SIZE_MAX
if (count > INTMAX_MAX) {
- return -EOVERFLOW;
+ return pldm__msgbuf_invalidate(ctx);
}
#endif
if (ctx->remaining >= (intmax_t)count) {
+ assert(ctx->cursor);
memcpy(dst, ctx->cursor, count);
ctx->cursor += count;
ctx->remaining -= (intmax_t)count;
return 0;
}
- if (ctx->remaining >= INTMAX_MIN + (intmax_t)count) {
+ if (ctx->remaining > INTMAX_MIN + (intmax_t)count) {
ctx->remaining -= (intmax_t)count;
+ return -EOVERFLOW;
}
- return -EOVERFLOW;
+ return pldm__msgbuf_invalidate(ctx);
}
/**
@@ -672,27 +703,25 @@
{
uint64_t val = htole64(src);
- if (!ctx->cursor) {
- return -EINVAL;
- }
-
static_assert(
// NOLINTNEXTLINE(bugprone-sizeof-expression)
sizeof(src) < INTMAX_MAX,
"The following addition may not uphold the runtime assertion");
if (ctx->remaining >= (intmax_t)sizeof(src)) {
+ assert(ctx->cursor);
memcpy(ctx->cursor, &val, sizeof(val));
ctx->cursor += sizeof(src);
ctx->remaining -= sizeof(src);
return 0;
}
- if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(src)) {
+ if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(src)) {
ctx->remaining -= sizeof(src);
+ return -EOVERFLOW;
}
- return -EOVERFLOW;
+ return pldm__msgbuf_invalidate(ctx);
}
LIBPLDM_CC_NONNULL
@@ -701,27 +730,25 @@
{
uint32_t val = htole32(src);
- if (!ctx->cursor) {
- return -EINVAL;
- }
-
static_assert(
// NOLINTNEXTLINE(bugprone-sizeof-expression)
sizeof(src) < INTMAX_MAX,
"The following addition may not uphold the runtime assertion");
if (ctx->remaining >= (intmax_t)sizeof(src)) {
+ assert(ctx->cursor);
memcpy(ctx->cursor, &val, sizeof(val));
ctx->cursor += sizeof(src);
ctx->remaining -= sizeof(src);
return 0;
}
- if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(src)) {
+ if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(src)) {
ctx->remaining -= sizeof(src);
+ return -EOVERFLOW;
}
- return -EOVERFLOW;
+ return pldm__msgbuf_invalidate(ctx);
}
LIBPLDM_CC_NONNULL
@@ -730,54 +757,50 @@
{
uint16_t val = htole16(src);
- if (!ctx->cursor) {
- return -EINVAL;
- }
-
static_assert(
// NOLINTNEXTLINE(bugprone-sizeof-expression)
sizeof(src) < INTMAX_MAX,
"The following addition may not uphold the runtime assertion");
if (ctx->remaining >= (intmax_t)sizeof(src)) {
+ assert(ctx->cursor);
memcpy(ctx->cursor, &val, sizeof(val));
ctx->cursor += sizeof(src);
ctx->remaining -= sizeof(src);
return 0;
}
- if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(src)) {
+ if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(src)) {
ctx->remaining -= sizeof(src);
+ return -EOVERFLOW;
}
- return -EOVERFLOW;
+ return pldm__msgbuf_invalidate(ctx);
}
LIBPLDM_CC_NONNULL
LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_uint8(struct pldm_msgbuf *ctx,
const uint8_t src)
{
- if (!ctx->cursor) {
- return -EINVAL;
- }
-
static_assert(
// NOLINTNEXTLINE(bugprone-sizeof-expression)
sizeof(src) < INTMAX_MAX,
"The following addition may not uphold the runtime assertion");
if (ctx->remaining >= (intmax_t)sizeof(src)) {
+ assert(ctx->cursor);
memcpy(ctx->cursor, &src, sizeof(src));
ctx->cursor += sizeof(src);
ctx->remaining -= sizeof(src);
return 0;
}
- if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(src)) {
+ if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(src)) {
ctx->remaining -= sizeof(src);
+ return -EOVERFLOW;
}
- return -EOVERFLOW;
+ return pldm__msgbuf_invalidate(ctx);
}
LIBPLDM_CC_NONNULL
@@ -786,27 +809,25 @@
{
int32_t val = htole32(src);
- if (!ctx->cursor) {
- return -EINVAL;
- }
-
static_assert(
// NOLINTNEXTLINE(bugprone-sizeof-expression)
sizeof(src) < INTMAX_MAX,
"The following addition may not uphold the runtime assertion");
if (ctx->remaining >= (intmax_t)sizeof(src)) {
+ assert(ctx->cursor);
memcpy(ctx->cursor, &val, sizeof(val));
ctx->cursor += sizeof(src);
ctx->remaining -= sizeof(src);
return 0;
}
- if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(src)) {
+ if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(src)) {
ctx->remaining -= sizeof(src);
+ return -EOVERFLOW;
}
- return -EOVERFLOW;
+ return pldm__msgbuf_invalidate(ctx);
}
LIBPLDM_CC_NONNULL
@@ -815,54 +836,50 @@
{
int16_t val = htole16(src);
- if (!ctx->cursor) {
- return -EINVAL;
- }
-
static_assert(
// NOLINTNEXTLINE(bugprone-sizeof-expression)
sizeof(src) < INTMAX_MAX,
"The following addition may not uphold the runtime assertion");
if (ctx->remaining >= (intmax_t)sizeof(src)) {
+ assert(ctx->cursor);
memcpy(ctx->cursor, &val, sizeof(val));
ctx->cursor += sizeof(src);
ctx->remaining -= sizeof(src);
return 0;
}
- if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(src)) {
+ if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(src)) {
ctx->remaining -= sizeof(src);
+ return -EOVERFLOW;
}
- return -EOVERFLOW;
+ return pldm__msgbuf_invalidate(ctx);
}
LIBPLDM_CC_NONNULL
LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_int8(struct pldm_msgbuf *ctx,
const int8_t src)
{
- if (!ctx->cursor) {
- return -EINVAL;
- }
-
static_assert(
// NOLINTNEXTLINE(bugprone-sizeof-expression)
sizeof(src) < INTMAX_MAX,
"The following addition may not uphold the runtime assertion");
if (ctx->remaining >= (intmax_t)sizeof(src)) {
+ assert(ctx->cursor);
memcpy(ctx->cursor, &src, sizeof(src));
ctx->cursor += sizeof(src);
ctx->remaining -= sizeof(src);
return 0;
}
- if (ctx->remaining >= INTMAX_MIN + (intmax_t)sizeof(src)) {
+ if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(src)) {
ctx->remaining -= sizeof(src);
+ return -EOVERFLOW;
}
- return -EOVERFLOW;
+ return pldm__msgbuf_invalidate(ctx);
}
#define pldm_msgbuf_insert(dst, src) \
@@ -885,7 +902,7 @@
pldm__msgbuf_insert_array_void(struct pldm_msgbuf *ctx, size_t count,
const void *src, size_t src_count)
{
- if (!ctx->cursor || count > src_count) {
+ if (count > src_count) {
return -EINVAL;
}
@@ -895,22 +912,24 @@
#if INTMAX_MAX < SIZE_MAX
if (count > INTMAX_MAX) {
- return -EOVERFLOW;
+ return pldm__msgbuf_invalidate(ctx);
}
#endif
if (ctx->remaining >= (intmax_t)count) {
+ assert(ctx->cursor);
memcpy(ctx->cursor, src, count);
ctx->cursor += count;
ctx->remaining -= (intmax_t)count;
return 0;
}
- if (ctx->remaining >= INTMAX_MIN + (intmax_t)count) {
+ if (ctx->remaining > INTMAX_MIN + (intmax_t)count) {
ctx->remaining -= (intmax_t)count;
+ return -EOVERFLOW;
}
- return -EOVERFLOW;
+ return pldm__msgbuf_invalidate(ctx);
}
/**
@@ -962,17 +981,14 @@
size_t required,
void **cursor)
{
- if (!ctx->cursor) {
- return -EINVAL;
- }
-
#if INTMAX_MAX < SIZE_MAX
if (required > INTMAX_MAX) {
- return -EOVERFLOW;
+ return pldm__msgbuf_invalidate(ctx);
}
#endif
if (ctx->remaining >= (intmax_t)required) {
+ assert(ctx->cursor);
if (cursor) {
*cursor = ctx->cursor;
}
@@ -981,11 +997,12 @@
return 0;
}
- if (ctx->remaining >= INTMAX_MIN + (intmax_t)required) {
+ if (ctx->remaining > INTMAX_MIN + (intmax_t)required) {
ctx->remaining -= (intmax_t)required;
+ return -EOVERFLOW;
}
- return -EOVERFLOW;
+ return pldm__msgbuf_invalidate(ctx);
}
LIBPLDM_CC_NONNULL_ARGS(1)
@@ -995,31 +1012,21 @@
{
intmax_t measured;
- if (!ctx->cursor) {
- return -EINVAL;
- }
-
if (ctx->remaining < 0) {
- /* Tracking the amount of overflow gets disturbed here */
- return -EOVERFLOW;
+ return pldm__msgbuf_invalidate(ctx);
}
+ assert(ctx->cursor);
measured = (intmax_t)strnlen((const char *)ctx->cursor, ctx->remaining);
if (measured == ctx->remaining) {
- /*
- * We have hit the end of the buffer prior to the NUL terminator.
- * Optimistically, the NUL terminator was one-beyond-the-end. Setting
- * ctx->remaining negative ensures the `pldm_msgbuf_complete*()` APIs also
- * return an error.
- */
- ctx->remaining = -1;
- return -EOVERFLOW;
+ return pldm__msgbuf_invalidate(ctx);
}
/* Include the NUL terminator in the span length, as spans are opaque */
measured++;
if (ctx->remaining >= measured) {
+ assert(ctx->cursor);
if (cursor) {
*cursor = ctx->cursor;
}
@@ -1034,11 +1041,12 @@
return 0;
}
- if (ctx->remaining >= INTMAX_MIN + measured) {
+ if (ctx->remaining > INTMAX_MIN + measured) {
ctx->remaining -= measured;
+ return -EOVERFLOW;
}
- return -EOVERFLOW;
+ return pldm__msgbuf_invalidate(ctx);
}
LIBPLDM_CC_NONNULL_ARGS(1)
@@ -1050,14 +1058,10 @@
ptrdiff_t measured;
void *end;
- if (!ctx->cursor) {
- return -EINVAL;
- }
-
if (ctx->remaining < 0) {
- /* Tracking the amount of overflow gets disturbed here */
- return -EOVERFLOW;
+ return pldm__msgbuf_invalidate(ctx);
}
+ assert(ctx->cursor);
/*
* Avoid tripping up on UTF16-LE: We may have consecutive NUL _bytes_ that do
@@ -1084,8 +1088,7 @@
* the buffer. Setting ctx->remaining negative ensures the
* `pldm_msgbuf_complete*()` APIs also return an error.
*/
- ctx->remaining = -1;
- return -EOVERFLOW;
+ return pldm__msgbuf_invalidate(ctx);
}
end = (char *)end + sizeof(char16_t);
@@ -1093,11 +1096,12 @@
#if INTMAX_MAX < PTRDIFF_MAX
if (measured >= INTMAX_MAX) {
- return pldm_msgbuf_status(ctx, EOVERFLOW);
+ return pldm__msgbuf_invalidate(ctx);
}
#endif
if (ctx->remaining >= (intmax_t)measured) {
+ assert(ctx->cursor);
if (cursor) {
*cursor = ctx->cursor;
}
@@ -1112,25 +1116,23 @@
return 0;
}
- if (ctx->remaining >= INTMAX_MIN + (intmax_t)measured) {
+ if (ctx->remaining > INTMAX_MIN + (intmax_t)measured) {
ctx->remaining -= (intmax_t)measured;
+ return -EOVERFLOW;
}
- return -EOVERFLOW;
+ return pldm__msgbuf_invalidate(ctx);
}
LIBPLDM_CC_NONNULL
LIBPLDM_CC_ALWAYS_INLINE int
pldm_msgbuf_span_remaining(struct pldm_msgbuf *ctx, void **cursor, size_t *len)
{
- if (!ctx->cursor) {
- return -EINVAL;
- }
-
if (ctx->remaining < 0) {
return -EOVERFLOW;
}
+ assert(ctx->cursor);
*cursor = ctx->cursor;
ctx->cursor += ctx->remaining;
*len = ctx->remaining;
@@ -1143,14 +1145,11 @@
LIBPLDM_CC_ALWAYS_INLINE int
pldm_msgbuf_peek_remaining(struct pldm_msgbuf *ctx, void **cursor, size_t *len)
{
- if (!ctx->cursor) {
- return -EINVAL;
- }
-
if (ctx->remaining < 0) {
return -EOVERFLOW;
}
+ assert(ctx->cursor);
*cursor = ctx->cursor;
*len = ctx->remaining;
@@ -1161,27 +1160,25 @@
LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_skip(struct pldm_msgbuf *ctx,
size_t count)
{
- if (!ctx->cursor) {
- return -EINVAL;
- }
-
#if INTMAX_MAX < SIZE_MAX
if (count > INTMAX_MAX) {
- return -EOVERFLOW;
+ return pldm__msgbuf_invalidate(ctx);
}
#endif
if (ctx->remaining >= (intmax_t)count) {
+ assert(ctx->cursor);
ctx->cursor += count;
ctx->remaining -= (intmax_t)count;
return 0;
}
- if (ctx->remaining >= INTMAX_MIN + (intmax_t)count) {
+ if (ctx->remaining > INTMAX_MIN + (intmax_t)count) {
ctx->remaining -= (intmax_t)count;
+ return -EOVERFLOW;
}
- return -EOVERFLOW;
+ return pldm__msgbuf_invalidate(ctx);
}
/**
@@ -1207,17 +1204,20 @@
{
int rc;
+ ctx->cursor = NULL;
rc = pldm_msgbuf_validate(ctx);
if (rc) {
+ pldm__msgbuf_invalidate(ctx);
return rc;
}
if ((size_t)ctx->remaining > orig_len) {
/* Caller passed incorrect orig_len */
- return -EOVERFLOW;
+ return pldm__msgbuf_invalidate(ctx);
}
*ret_used_len = orig_len - ctx->remaining;
+ pldm__msgbuf_invalidate(ctx);
return 0;
}
@@ -1241,18 +1241,17 @@
pldm__msgbuf_copy(struct pldm_msgbuf *dst, struct pldm_msgbuf *src, size_t size,
const char *description LIBPLDM_CC_UNUSED)
{
- if (!src->cursor || !dst->cursor) {
- return -EINVAL;
- }
-
#if INTMAX_MAX < SIZE_MAX
if (size > INTMAX_MAX) {
+ pldm__msgbuf_invalidate(src);
+ pldm__msgbuf_invalidate(dst);
return -EOVERFLOW;
}
#endif
if (src->remaining >= (intmax_t)size &&
dst->remaining >= (intmax_t)size) {
+ assert(src->cursor && dst->cursor);
memcpy(dst->cursor, src->cursor, size);
src->cursor += size;
src->remaining -= (intmax_t)size;
@@ -1261,12 +1260,16 @@
return 0;
}
- if (src->remaining >= INTMAX_MIN + (intmax_t)size) {
+ if (src->remaining > INTMAX_MIN + (intmax_t)size) {
src->remaining -= (intmax_t)size;
+ } else {
+ pldm__msgbuf_invalidate(src);
}
- if (dst->remaining >= INTMAX_MIN + (intmax_t)size) {
+ if (dst->remaining > INTMAX_MIN + (intmax_t)size) {
dst->remaining -= (intmax_t)size;
+ } else {
+ pldm__msgbuf_invalidate(dst);
}
return -EOVERFLOW;