msgbuf: Remove use of ssize_t for overflow tracking

There are a few concerns with the use of ssize_t in this context:

1. It's defined by POSIX and not C, and I'd prefer we not require POSIX
   concepts where we can avoid it
2. ssize_t is defined over [-1, SSIZE_MAX] - it is not defined to have
   the range of a regular signed type.

The source of both these statements is The Open Group Base
Specifications Issue 7, 2018 edition. IEEE Std 1003.1-2017 (Revision of
IEEE Std 1003.1-2008)

The second point directly contradicts how I was trying to use ssize_t in
the msgbuf implementation. As a result, switch the type of `remaining`
to intmax_t. Usually intmax_t is a problem child, but it's not used in
any public API, and it has the semantics I wanted by contrast to the
definition of ssize_t.

Note that we add assert() calls where we know the value of remaining
must be negative. Without the addition of the `assert()` calls in the
underflow checks, clang-analyzer gets tripped up by not being able to
prove `INTMAX_MIN + (intmax_t)sizeof(uint16_t) < 0`:

```
../src/platform.c:17:18: error: The left operand of '+' is a garbage value [clang-analyzer-core.UndefinedBinaryOperatorResult,-warnings-as-errors]
   17 |         if (ctx->length + sizeof(*ctx) < lower) {
      |                         ^
../src/platform.c:2445:6: note: 'rc' is 0
 2445 |         if (rc) {
      |             ^~
../src/platform.c:2445:2: note: Taking false branch
 2445 |         if (rc) {
      |         ^
../src/platform.c:2449:7: note: Calling 'pldm_msgbuf_extract_value_pdr_hdr'
 2449 |         rc = pldm_msgbuf_extract_value_pdr_hdr(buf, &hdr);
      |              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../src/msgbuf/platform.h:17:2: note: Calling 'pldm__msgbuf_extract_uint16'
   17 |         pldm_msgbuf_extract(ctx, hdr->length);
      |         ^
../src/msgbuf/../msgbuf.h:517:2: note: expanded from macro 'pldm_msgbuf_extract'
  517 |         _Generic((dst),                                                        \
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  518 |                 uint8_t: pldm__msgbuf_extract_uint8,                           \
      |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  519 |                 int8_t: pldm__msgbuf_extract_int8,                             \
      |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  520 |                 uint16_t: pldm__msgbuf_extract_uint16,                         \
      |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  521 |                 int16_t: pldm__msgbuf_extract_int16,                           \
      |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  522 |                 uint32_t: pldm__msgbuf_extract_uint32,                         \
      |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  523 |                 int32_t: pldm__msgbuf_extract_int32,                           \
      |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  524 |                 real32_t: pldm__msgbuf_extract_real32)(ctx, (void *)&(dst))
      |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../src/msgbuf/../msgbuf.h:341:7: note: 'ctx' is non-null
  341 |         if (!ctx || !ctx->cursor || !dst) {
      |              ^~~
../src/msgbuf/../msgbuf.h:341:6: note: Left side of '||' is false
  341 |         if (!ctx || !ctx->cursor || !dst) {
      |             ^
../src/msgbuf/../msgbuf.h:341:20: note: Field 'cursor' is non-null
  341 |         if (!ctx || !ctx->cursor || !dst) {
      |                           ^
../src/msgbuf/../msgbuf.h:341:6: note: Left side of '||' is false
  341 |         if (!ctx || !ctx->cursor || !dst) {
      |             ^
../src/msgbuf/../msgbuf.h:341:31: note: 'dst' is non-null
  341 |         if (!ctx || !ctx->cursor || !dst) {
      |                                      ^~~
../src/msgbuf/../msgbuf.h:341:2: note: Taking false branch
  341 |         if (!ctx || !ctx->cursor || !dst) {
      |         ^
../src/msgbuf/../msgbuf.h:347:2: note: Taking true branch
  347 |         if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
      |         ^
../src/msgbuf/../msgbuf.h:348:3: note: Returning without writing to '*dst'
  348 |                 return PLDM_ERROR_INVALID_LENGTH;
      |                 ^
../src/msgbuf/platform.h:17:2: note: Returning from 'pldm__msgbuf_extract_uint16'
   17 |         pldm_msgbuf_extract(ctx, hdr->length);
      |         ^
../src/msgbuf/../msgbuf.h:517:2: note: expanded from macro 'pldm_msgbuf_extract'
  517 |         _Generic((dst),                                                        \
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  518 |                 uint8_t: pldm__msgbuf_extract_uint8,                           \
      |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  519 |                 int8_t: pldm__msgbuf_extract_int8,                             \
      |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  520 |                 uint16_t: pldm__msgbuf_extract_uint16,                         \
      |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  521 |                 int16_t: pldm__msgbuf_extract_int16,                           \
      |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  522 |                 uint32_t: pldm__msgbuf_extract_uint32,                         \
      |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  523 |                 int32_t: pldm__msgbuf_extract_int32,                           \
      |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  524 |                 real32_t: pldm__msgbuf_extract_real32)(ctx, (void *)&(dst))
      |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../src/msgbuf/platform.h:19:2: note: Returning without writing to 'hdr->length'
   19 |         return pldm_msgbuf_validate(ctx);
      |         ^
../src/platform.c:2449:7: note: Returning from 'pldm_msgbuf_extract_value_pdr_hdr'
 2449 |         rc = pldm_msgbuf_extract_value_pdr_hdr(buf, &hdr);
      |              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../src/platform.c:2450:6: note: 'rc' is 0
 2450 |         if (rc) {
      |             ^~
../src/platform.c:2450:2: note: Taking false branch
 2450 |         if (rc) {
      |         ^
../src/platform.c:2454:7: note: Calling 'pldm_platform_pdr_hdr_validate'
 2454 |         rc = pldm_platform_pdr_hdr_validate(
      |              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 2455 |                 &hdr, PLDM_PDR_NUMERIC_EFFECTER_PDR_MIN_LENGTH,
      |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 2456 |                 pdr_data_length);
      |                 ~~~~~~~~~~~~~~~~
../src/platform.c:17:18: note: The left operand of '+' is a garbage value
   17 |         if (ctx->length + sizeof(*ctx) < lower) {
      |             ~~~~~~~~~~~ ^
```

Change-Id: Idbe5a14455ad677a39c8f535eddd9c2ce471c783
Signed-off-by: Andrew Jeffery <andrew@codeconstruct.com.au>
diff --git a/src/msgbuf.h b/src/msgbuf.h
index 691d9a6..f81eb13 100644
--- a/src/msgbuf.h
+++ b/src/msgbuf.h
@@ -52,9 +52,24 @@
 #include <string.h>
 #include <sys/types.h>
 
+/*
+ * We can't use static_assert() outside of some other C construct. Deal
+ * with high-level global assertions by burying them in an unused struct
+ * declaration, that has a sole member for compliance with the requirement that
+ * types must have a size.
+*/
+static struct {
+	static_assert(
+		INTMAX_MAX != SIZE_MAX,
+		"Extraction and insertion value comparisons may be broken");
+	static_assert(INTMAX_MIN + INTMAX_MAX <= 0,
+		      "Extraction and insertion arithmetic may be broken");
+	int compliance;
+} build_assertions __attribute__((unused));
+
 struct pldm_msgbuf {
 	uint8_t *cursor;
-	ssize_t remaining;
+	intmax_t remaining;
 };
 
 /**
@@ -76,16 +91,22 @@
 		return PLDM_ERROR_INVALID_DATA;
 	}
 
-	if ((minsize > len) || (len > SSIZE_MAX)) {
+	if ((minsize > len)) {
 		return PLDM_ERROR_INVALID_LENGTH;
 	}
 
+#if INTMAX_MAX < SIZE_MAX
+	if (len > INTMAX_MAX) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+#endif
+
 	if ((uintptr_t)buf + len < len) {
 		return PLDM_ERROR_INVALID_LENGTH;
 	}
 
 	ctx->cursor = (uint8_t *)buf;
-	ctx->remaining = (ssize_t)len;
+	ctx->remaining = (intmax_t)len;
 
 	return PLDM_SUCCESS;
 }
@@ -290,6 +311,10 @@
 		return PLDM_ERROR_INVALID_DATA;
 	}
 
+	if (ctx->remaining == INTMAX_MIN) {
+		assert(ctx->remaining < 0);
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
 	ctx->remaining -= sizeof(uint8_t);
 	assert(ctx->remaining >= 0);
 	if (ctx->remaining < 0) {
@@ -312,6 +337,10 @@
 		return PLDM_ERROR_INVALID_DATA;
 	}
 
+	if (ctx->remaining == INTMAX_MIN) {
+		assert(ctx->remaining < 0);
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
 	ctx->remaining -= sizeof(int8_t);
 	assert(ctx->remaining >= 0);
 	if (ctx->remaining < 0) {
@@ -336,6 +365,16 @@
 		return PLDM_ERROR_INVALID_DATA;
 	}
 
+	// Check for underflow while tracking the magnitude of the buffer overflow
+	static_assert(
+		// NOLINTNEXTLINE(bugprone-sizeof-expression)
+		sizeof(ldst) < INTMAX_MAX,
+		"The following addition may not uphold the runtime assertion");
+	if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
+		assert(ctx->remaining < 0);
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
 	// Check for buffer overflow. If we overflow, account for the request as
 	// negative values in ctx->remaining. This way we can debug how far
 	// we've overflowed.
@@ -376,6 +415,14 @@
 		return PLDM_ERROR_INVALID_DATA;
 	}
 
+	static_assert(
+		// NOLINTNEXTLINE(bugprone-sizeof-expression)
+		sizeof(ldst) < INTMAX_MAX,
+		"The following addition may not uphold the runtime assertion");
+	if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
+		assert(ctx->remaining < 0);
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
 	ctx->remaining -= sizeof(ldst);
 	assert(ctx->remaining >= 0);
 	if (ctx->remaining < 0) {
@@ -404,6 +451,14 @@
 		return PLDM_ERROR_INVALID_DATA;
 	}
 
+	static_assert(
+		// NOLINTNEXTLINE(bugprone-sizeof-expression)
+		sizeof(ldst) < INTMAX_MAX,
+		"The following addition may not uphold the runtime assertion");
+	if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
+		assert(ctx->remaining < 0);
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
 	ctx->remaining -= sizeof(ldst);
 	assert(ctx->remaining >= 0);
 	if (ctx->remaining < 0) {
@@ -431,6 +486,14 @@
 		return PLDM_ERROR_INVALID_DATA;
 	}
 
+	static_assert(
+		// NOLINTNEXTLINE(bugprone-sizeof-expression)
+		sizeof(ldst) < INTMAX_MAX,
+		"The following addition may not uphold the runtime assertion");
+	if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
+		assert(ctx->remaining < 0);
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
 	ctx->remaining -= sizeof(ldst);
 	assert(ctx->remaining >= 0);
 	if (ctx->remaining < 0) {
@@ -462,6 +525,14 @@
 		return PLDM_ERROR_INVALID_DATA;
 	}
 
+	static_assert(
+		// NOLINTNEXTLINE(bugprone-sizeof-expression)
+		sizeof(ldst) < INTMAX_MAX,
+		"The following addition may not uphold the runtime assertion");
+	if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(ldst)) {
+		assert(ctx->remaining < 0);
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
 	ctx->remaining -= sizeof(ldst);
 	assert(ctx->remaining >= 0);
 	if (ctx->remaining < 0) {
@@ -525,11 +596,16 @@
 		return PLDM_SUCCESS;
 	}
 
-	if (count >= SSIZE_MAX) {
+#if INTMAX_MAX < SIZE_MAX
+	if (count > INTMAX_MAX) {
 		return PLDM_ERROR_INVALID_LENGTH;
 	}
+#endif
 
-	ctx->remaining -= (ssize_t)count;
+	if (ctx->remaining < INTMAX_MIN + (intmax_t)count) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+	ctx->remaining -= (intmax_t)count;
 	assert(ctx->remaining >= 0);
 	if (ctx->remaining < 0) {
 		return PLDM_ERROR_INVALID_LENGTH;
@@ -554,6 +630,14 @@
 		return PLDM_ERROR_INVALID_DATA;
 	}
 
+	static_assert(
+		// NOLINTNEXTLINE(bugprone-sizeof-expression)
+		sizeof(src) < INTMAX_MAX,
+		"The following addition may not uphold the runtime assertion");
+	if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
+		assert(ctx->remaining < 0);
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
 	ctx->remaining -= sizeof(src);
 	assert(ctx->remaining >= 0);
 	if (ctx->remaining < 0) {
@@ -575,6 +659,14 @@
 		return PLDM_ERROR_INVALID_DATA;
 	}
 
+	static_assert(
+		// NOLINTNEXTLINE(bugprone-sizeof-expression)
+		sizeof(src) < INTMAX_MAX,
+		"The following addition may not uphold the runtime assertion");
+	if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
+		assert(ctx->remaining < 0);
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
 	ctx->remaining -= sizeof(src);
 	assert(ctx->remaining >= 0);
 	if (ctx->remaining < 0) {
@@ -594,6 +686,14 @@
 		return PLDM_ERROR_INVALID_DATA;
 	}
 
+	static_assert(
+		// NOLINTNEXTLINE(bugprone-sizeof-expression)
+		sizeof(src) < INTMAX_MAX,
+		"The following addition may not uphold the runtime assertion");
+	if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
+		assert(ctx->remaining < 0);
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
 	ctx->remaining -= sizeof(src);
 	assert(ctx->remaining >= 0);
 	if (ctx->remaining < 0) {
@@ -615,6 +715,14 @@
 		return PLDM_ERROR_INVALID_DATA;
 	}
 
+	static_assert(
+		// NOLINTNEXTLINE(bugprone-sizeof-expression)
+		sizeof(src) < INTMAX_MAX,
+		"The following addition may not uphold the runtime assertion");
+	if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
+		assert(ctx->remaining < 0);
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
 	ctx->remaining -= sizeof(src);
 	assert(ctx->remaining >= 0);
 	if (ctx->remaining < 0) {
@@ -636,6 +744,14 @@
 		return PLDM_ERROR_INVALID_DATA;
 	}
 
+	static_assert(
+		// NOLINTNEXTLINE(bugprone-sizeof-expression)
+		sizeof(src) < INTMAX_MAX,
+		"The following addition may not uphold the runtime assertion");
+	if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
+		assert(ctx->remaining < 0);
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
 	ctx->remaining -= sizeof(src);
 	assert(ctx->remaining >= 0);
 	if (ctx->remaining < 0) {
@@ -655,6 +771,14 @@
 		return PLDM_ERROR_INVALID_DATA;
 	}
 
+	static_assert(
+		// NOLINTNEXTLINE(bugprone-sizeof-expression)
+		sizeof(src) < INTMAX_MAX,
+		"The following addition may not uphold the runtime assertion");
+	if (ctx->remaining < INTMAX_MIN + (intmax_t)sizeof(src)) {
+		assert(ctx->remaining < 0);
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
 	ctx->remaining -= sizeof(src);
 	assert(ctx->remaining >= 0);
 	if (ctx->remaining < 0) {
@@ -688,11 +812,16 @@
 		return PLDM_SUCCESS;
 	}
 
-	if (count >= SSIZE_MAX) {
+#if INTMAX_MAX < SIZE_MAX
+	if (count > INTMAX_MAX) {
 		return PLDM_ERROR_INVALID_LENGTH;
 	}
+#endif
 
-	ctx->remaining -= (ssize_t)count;
+	if (ctx->remaining < INTMAX_MIN + (intmax_t)count) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+	ctx->remaining -= (intmax_t)count;
 	assert(ctx->remaining >= 0);
 	if (ctx->remaining < 0) {
 		return PLDM_ERROR_INVALID_LENGTH;
@@ -715,11 +844,16 @@
 		return PLDM_ERROR_INVALID_DATA;
 	}
 
-	if (required > SSIZE_MAX) {
+#if INTMAX_MAX < SIZE_MAX
+	if (required > INTMAX_MAX) {
 		return PLDM_ERROR_INVALID_LENGTH;
 	}
+#endif
 
-	ctx->remaining -= (ssize_t)required;
+	if (ctx->remaining < INTMAX_MIN + (intmax_t)required) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+	ctx->remaining -= (intmax_t)required;
 	assert(ctx->remaining >= 0);
 	if (ctx->remaining < 0) {
 		return PLDM_ERROR_INVALID_LENGTH;
diff --git a/tests/msgbuf.cpp b/tests/msgbuf.cpp
index 15b0265..fecf514 100644
--- a/tests/msgbuf.cpp
+++ b/tests/msgbuf.cpp
@@ -143,6 +143,20 @@
     EXPECT_EQ(pldm_msgbuf_destroy(ctx), PLDM_ERROR_INVALID_LENGTH);
 }
 
+TEST(msgbuf, extract_under_uint8)
+{
+    struct pldm_msgbuf _ctx;
+    struct pldm_msgbuf* ctx = &_ctx;
+
+    uint8_t buf[1] = {};
+    uint8_t val;
+
+    ASSERT_EQ(pldm_msgbuf_init(ctx, 0, buf, 0), PLDM_SUCCESS);
+    ctx->remaining = INTMAX_MIN;
+    EXPECT_NE(pldm_msgbuf_extract_uint8(ctx, &val), PLDM_SUCCESS);
+    EXPECT_EQ(pldm_msgbuf_destroy(ctx), PLDM_ERROR_INVALID_LENGTH);
+}
+
 TEST(msgbuf, extract_one_int8)
 {
     struct pldm_msgbuf _ctx;
@@ -169,6 +183,20 @@
     EXPECT_EQ(pldm_msgbuf_destroy(ctx), PLDM_ERROR_INVALID_LENGTH);
 }
 
+TEST(msgbuf, extract_under_int8)
+{
+    struct pldm_msgbuf _ctx;
+    struct pldm_msgbuf* ctx = &_ctx;
+
+    uint8_t buf[1] = {};
+    int8_t val;
+
+    ASSERT_EQ(pldm_msgbuf_init(ctx, 0, buf, 0), PLDM_SUCCESS);
+    ctx->remaining = INTMAX_MIN;
+    EXPECT_NE(pldm_msgbuf_extract_int8(ctx, &val), PLDM_SUCCESS);
+    EXPECT_EQ(pldm_msgbuf_destroy(ctx), PLDM_ERROR_INVALID_LENGTH);
+}
+
 TEST(msgbuf, extract_one_uint16)
 {
     struct pldm_msgbuf _ctx;
@@ -183,6 +211,20 @@
     EXPECT_EQ(pldm_msgbuf_destroy(ctx), PLDM_SUCCESS);
 }
 
+TEST(msgbuf, extract_under_uint16)
+{
+    struct pldm_msgbuf _ctx;
+    struct pldm_msgbuf* ctx = &_ctx;
+
+    uint16_t buf[1] = {};
+    uint16_t val;
+
+    ASSERT_EQ(pldm_msgbuf_init(ctx, 0, buf, 0), PLDM_SUCCESS);
+    ctx->remaining = INTMAX_MIN + sizeof(val) - 1;
+    EXPECT_NE(pldm_msgbuf_extract_uint16(ctx, &val), PLDM_SUCCESS);
+    EXPECT_EQ(pldm_msgbuf_destroy(ctx), PLDM_ERROR_INVALID_LENGTH);
+}
+
 TEST(msgbuf, extract_over_uint16)
 {
     struct pldm_msgbuf _ctx;
@@ -221,6 +263,20 @@
     EXPECT_EQ(pldm_msgbuf_destroy(ctx), PLDM_ERROR_INVALID_LENGTH);
 }
 
+TEST(msgbuf, extract_under_int16)
+{
+    struct pldm_msgbuf _ctx;
+    struct pldm_msgbuf* ctx = &_ctx;
+
+    int16_t buf[1] = {};
+    int16_t val;
+
+    ASSERT_EQ(pldm_msgbuf_init(ctx, 0, buf, 0), PLDM_SUCCESS);
+    ctx->remaining = INTMAX_MIN + sizeof(val) - 1;
+    EXPECT_NE(pldm_msgbuf_extract_int16(ctx, &val), PLDM_SUCCESS);
+    EXPECT_EQ(pldm_msgbuf_destroy(ctx), PLDM_ERROR_INVALID_LENGTH);
+}
+
 TEST(msgbuf, extract_one_uint32)
 {
     struct pldm_msgbuf _ctx;
@@ -247,6 +303,20 @@
     EXPECT_EQ(pldm_msgbuf_destroy(ctx), PLDM_ERROR_INVALID_LENGTH);
 }
 
+TEST(msgbuf, extract_under_uint32)
+{
+    struct pldm_msgbuf _ctx;
+    struct pldm_msgbuf* ctx = &_ctx;
+
+    uint32_t buf[1] = {};
+    uint32_t val;
+
+    ASSERT_EQ(pldm_msgbuf_init(ctx, 0, buf, 0), PLDM_SUCCESS);
+    ctx->remaining = INTMAX_MIN + sizeof(val) - 1;
+    EXPECT_NE(pldm_msgbuf_extract_uint32(ctx, &val), PLDM_SUCCESS);
+    EXPECT_EQ(pldm_msgbuf_destroy(ctx), PLDM_ERROR_INVALID_LENGTH);
+}
+
 TEST(msgbuf, extract_one_int32)
 {
     struct pldm_msgbuf _ctx;
@@ -273,6 +343,20 @@
     EXPECT_EQ(pldm_msgbuf_destroy(ctx), PLDM_ERROR_INVALID_LENGTH);
 }
 
+TEST(msgbuf, extract_under_int32)
+{
+    struct pldm_msgbuf _ctx;
+    struct pldm_msgbuf* ctx = &_ctx;
+
+    int32_t buf[1] = {};
+    int32_t val;
+
+    ASSERT_EQ(pldm_msgbuf_init(ctx, 0, buf, 0), PLDM_SUCCESS);
+    ctx->remaining = INTMAX_MIN + sizeof(val) - 1;
+    EXPECT_NE(pldm_msgbuf_extract_int32(ctx, &val), PLDM_SUCCESS);
+    EXPECT_EQ(pldm_msgbuf_destroy(ctx), PLDM_ERROR_INVALID_LENGTH);
+}
+
 TEST(msgbuf, extract_one_real32)
 {
     struct pldm_msgbuf _ctx;
@@ -305,6 +389,20 @@
     EXPECT_EQ(pldm_msgbuf_destroy(ctx), PLDM_ERROR_INVALID_LENGTH);
 }
 
+TEST(msgbuf, extract_under_real32)
+{
+    struct pldm_msgbuf _ctx;
+    struct pldm_msgbuf* ctx = &_ctx;
+
+    real32_t buf[1] = {};
+    real32_t val;
+
+    ASSERT_EQ(pldm_msgbuf_init(ctx, 0, buf, 0), PLDM_SUCCESS);
+    ctx->remaining = INTMAX_MIN + sizeof(val) - 1;
+    EXPECT_NE(pldm_msgbuf_extract_real32(ctx, &val), PLDM_SUCCESS);
+    EXPECT_EQ(pldm_msgbuf_destroy(ctx), PLDM_ERROR_INVALID_LENGTH);
+}
+
 TEST(msgbuf, extract_array_uint8_buf0_req0)
 {
     struct pldm_msgbuf _ctx;
@@ -344,6 +442,19 @@
     ASSERT_EQ(pldm_msgbuf_destroy(ctx), PLDM_ERROR_INVALID_LENGTH);
 }
 
+TEST(msgbuf, extract_under_array_uint8)
+{
+    struct pldm_msgbuf _ctx;
+    struct pldm_msgbuf* ctx = &_ctx;
+    uint8_t buf[1] = {};
+    uint8_t arr[1];
+
+    ASSERT_EQ(pldm_msgbuf_init(ctx, 0, buf, 0), PLDM_SUCCESS);
+    ctx->remaining = INTMAX_MIN;
+    EXPECT_NE(pldm_msgbuf_extract_array_uint8(ctx, arr, 1), PLDM_SUCCESS);
+    ASSERT_EQ(pldm_msgbuf_destroy(ctx), PLDM_ERROR_INVALID_LENGTH);
+}
+
 TEST(msgbuf, consumed_under)
 {
     struct pldm_msgbuf _ctx;
@@ -410,6 +521,20 @@
     EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
 }
 
+TEST(msgbuf, insert_under_int32)
+{
+    struct pldm_msgbuf _ctx;
+    struct pldm_msgbuf* ctx = &_ctx;
+
+    int32_t buf[1] = {};
+    int32_t val = 0;
+
+    ASSERT_EQ(pldm_msgbuf_init(ctx, 0, buf, 0), PLDM_SUCCESS);
+    ctx->remaining = INTMAX_MIN + sizeof(val) - 1;
+    EXPECT_NE(pldm_msgbuf_insert_int32(ctx, val), PLDM_SUCCESS);
+    EXPECT_EQ(pldm_msgbuf_destroy(ctx), PLDM_ERROR_INVALID_LENGTH);
+}
+
 TEST(msgbuf, pldm_msgbuf_insert_uint32_good)
 {
     struct pldm_msgbuf _ctx;
@@ -441,6 +566,20 @@
     EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
 }
 
+TEST(msgbuf, insert_under_uint32)
+{
+    struct pldm_msgbuf _ctx;
+    struct pldm_msgbuf* ctx = &_ctx;
+
+    uint32_t buf[1] = {};
+    uint32_t val = 0;
+
+    ASSERT_EQ(pldm_msgbuf_init(ctx, 0, buf, 0), PLDM_SUCCESS);
+    ctx->remaining = INTMAX_MIN + sizeof(val) - 1;
+    EXPECT_NE(pldm_msgbuf_insert_uint32(ctx, val), PLDM_SUCCESS);
+    EXPECT_EQ(pldm_msgbuf_destroy(ctx), PLDM_ERROR_INVALID_LENGTH);
+}
+
 TEST(msgbuf, pldm_msgbuf_insert_uint16_good)
 {
     struct pldm_msgbuf _ctx;
@@ -472,6 +611,20 @@
     EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
 }
 
+TEST(msgbuf, insert_under_uint16)
+{
+    struct pldm_msgbuf _ctx;
+    struct pldm_msgbuf* ctx = &_ctx;
+
+    uint16_t buf[1] = {};
+    uint16_t val = 0;
+
+    ASSERT_EQ(pldm_msgbuf_init(ctx, 0, buf, 0), PLDM_SUCCESS);
+    ctx->remaining = INTMAX_MIN + sizeof(val) - 1;
+    EXPECT_NE(pldm_msgbuf_insert_uint16(ctx, val), PLDM_SUCCESS);
+    EXPECT_EQ(pldm_msgbuf_destroy(ctx), PLDM_ERROR_INVALID_LENGTH);
+}
+
 TEST(msgbuf, pldm_msgbuf_insert_int16_good)
 {
     struct pldm_msgbuf _ctx;
@@ -503,6 +656,20 @@
     EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
 }
 
+TEST(msgbuf, insert_under_int16)
+{
+    struct pldm_msgbuf _ctx;
+    struct pldm_msgbuf* ctx = &_ctx;
+
+    int16_t buf[1] = {};
+    int16_t val = 0;
+
+    ASSERT_EQ(pldm_msgbuf_init(ctx, 0, buf, 0), PLDM_SUCCESS);
+    ctx->remaining = INTMAX_MIN + sizeof(val) - 1;
+    EXPECT_NE(pldm_msgbuf_insert_int16(ctx, val), PLDM_SUCCESS);
+    EXPECT_EQ(pldm_msgbuf_destroy(ctx), PLDM_ERROR_INVALID_LENGTH);
+}
+
 TEST(msgbuf, pldm_msgbuf_insert_uint8_good)
 {
     struct pldm_msgbuf _ctx;
@@ -534,6 +701,20 @@
     EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
 }
 
+TEST(msgbuf, insert_under_uint8)
+{
+    struct pldm_msgbuf _ctx;
+    struct pldm_msgbuf* ctx = &_ctx;
+
+    uint8_t buf[1] = {};
+    uint8_t val = 0;
+
+    ASSERT_EQ(pldm_msgbuf_init(ctx, 0, buf, 0), PLDM_SUCCESS);
+    ctx->remaining = INTMAX_MIN + sizeof(val) - 1;
+    EXPECT_NE(pldm_msgbuf_insert_uint8(ctx, val), PLDM_SUCCESS);
+    EXPECT_EQ(pldm_msgbuf_destroy(ctx), PLDM_ERROR_INVALID_LENGTH);
+}
+
 TEST(msgbuf, pldm_msgbuf_insert_int8_good)
 {
     struct pldm_msgbuf _ctx;
@@ -565,6 +746,20 @@
     EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
 }
 
+TEST(msgbuf, insert_under_int8)
+{
+    struct pldm_msgbuf _ctx;
+    struct pldm_msgbuf* ctx = &_ctx;
+
+    int8_t buf[1] = {};
+    int8_t val = 0;
+
+    ASSERT_EQ(pldm_msgbuf_init(ctx, 0, buf, 0), PLDM_SUCCESS);
+    ctx->remaining = INTMAX_MIN + sizeof(val) - 1;
+    EXPECT_NE(pldm_msgbuf_insert_int8(ctx, val), PLDM_SUCCESS);
+    EXPECT_EQ(pldm_msgbuf_destroy(ctx), PLDM_ERROR_INVALID_LENGTH);
+}
+
 TEST(msgbuf, pldm_msgbuf_insert_array_uint8_good)
 {
     struct pldm_msgbuf _ctx;
@@ -605,6 +800,21 @@
     EXPECT_EQ(pldm_msgbuf_destroy(ctx), PLDM_SUCCESS);
 }
 
+TEST(msgbuf, insert_under_array_uint8)
+{
+    struct pldm_msgbuf _ctx;
+    struct pldm_msgbuf* ctx = &_ctx;
+
+    uint8_t buf[1] = {};
+    uint8_t val[1] = {0};
+
+    ASSERT_EQ(pldm_msgbuf_init(ctx, 0, buf, 0), PLDM_SUCCESS);
+    ctx->remaining = INTMAX_MIN + sizeof(val) - 1;
+    EXPECT_NE(pldm_msgbuf_insert_array_uint8(ctx, val, sizeof(val)),
+              PLDM_SUCCESS);
+    EXPECT_EQ(pldm_msgbuf_destroy(ctx), PLDM_ERROR_INVALID_LENGTH);
+}
+
 TEST(msgbuf, pldm_msgbuf_span_required_good)
 {
     struct pldm_msgbuf _ctx;
@@ -661,6 +871,20 @@
     EXPECT_EQ(pldm_msgbuf_destroy(ctx), PLDM_SUCCESS);
 }
 
+TEST(msgbuf, span_required_under)
+{
+    struct pldm_msgbuf _ctx;
+    struct pldm_msgbuf* ctx = &_ctx;
+
+    uint8_t buf[1] = {};
+    void* cursor = nullptr;
+
+    ASSERT_EQ(pldm_msgbuf_init(ctx, 0, buf, 0), PLDM_SUCCESS);
+    ctx->remaining = INTMAX_MIN;
+    EXPECT_NE(pldm_msgbuf_span_required(ctx, 1, &cursor), PLDM_SUCCESS);
+    EXPECT_EQ(pldm_msgbuf_destroy(ctx), PLDM_ERROR_INVALID_LENGTH);
+}
+
 TEST(msgbuf, pldm_msgbuf_span_remaining_good)
 {
     struct pldm_msgbuf _ctx;