Encode/UB test coverage 100%; fix bugs in UsefulOutBuf_Compare and sorting

UsefulBuf test coverage back up to 100% (filled out coverage for new v2 features)

UsefulOutBuf_Compare() bugs for unequal length comparisons and comparisons off the end of the buffer

Improve UsefulOutBuf magic number check

UsefulOutBuf_OutSubString renamed to UsefulOutBuf_SubString for consistency. Old name still supported.



* Useful test coverage; UsefulOutBuf_Compare fixes

* Improve sort error handling; encode test coverage 100%

* Fix ifdef test fan out

* revert error codes

* Add diverse labels test

---------

Co-authored-by: Laurence Lundblade <lgl@securitytheory.com>
diff --git a/src/UsefulBuf.c b/src/UsefulBuf.c
index 46b66c6..6e99c43 100644
--- a/src/UsefulBuf.c
+++ b/src/UsefulBuf.c
@@ -1,6 +1,6 @@
 /*==============================================================================
  * Copyright (c) 2016-2018, The Linux Foundation.
- * Copyright (c) 2018-2024, Laurence Lundblade.
+ * Copyright (c) 2018-2025, Laurence Lundblade.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -44,6 +44,9 @@
 
  when        who          what, where, why
  --------    ----         ---------------------------------------------------
+ 02/21/2025  llundblade   Improve magic number to detect lack of initialization.
+ 02/21/2025  llundblade   Bug fixes to UsefulOutBuf_Compare().
+ 02/21/2025  llundblade   Rename to UsefulOutBuf_OutSubString().
  08/08/2024  llundblade   Add UsefulOutBuf_SubString().
  21/05/2024  llundblade   Comment formatting and some code tidiness.
  1/7/2024    llundblade   Add UsefulInputBuf_Compare().
@@ -246,11 +249,6 @@
  */
 void UsefulOutBuf_InsertUsefulBuf(UsefulOutBuf *pMe, UsefulBufC NewData, size_t uInsertionPos)
 {
-   if(pMe->err) {
-      /* Already in error state. */
-      return;
-   }
-
    /* 0. Sanity check the UsefulOutBuf structure
     * A "counter measure". If magic number is not the right number it
     * probably means pMe was not initialized or it was corrupted. Attackers
@@ -262,6 +260,11 @@
       return;  /* Magic number is wrong due to uninitalization or corrption */
    }
 
+   if(pMe->err) {
+      /* Already in error state. */
+      return;
+   }
+
    /* Make sure valid data is less than buffer size. This would only occur
     * if there was corruption of me, but it is also part of the checks to
     * be sure there is no pointer arithmatic under/overflow.
@@ -358,11 +361,6 @@
     * rarely used.
     */
 
-   if(pMe->err) {
-      /* Already in error state. */
-      return;
-   }
-
    /* 0. Sanity check the UsefulOutBuf structure
     *
     * A "counter measure". If magic number is not the right number it
@@ -375,6 +373,11 @@
       return;  /* Magic number is wrong due to uninitalization or corrption */
    }
 
+   if(pMe->err) {
+      /* Already in error state. */
+      return;
+   }
+
    /* Make sure valid data is less than buffer size. This would only
     * occur if there was corruption of me, but it is also part of the
     * checks to be sure there is no pointer arithmatic
@@ -409,12 +412,12 @@
  */
 UsefulBufC UsefulOutBuf_OutUBuf(UsefulOutBuf *pMe)
 {
-   if(pMe->err) {
+   if(pMe->magic != USEFUL_OUT_BUF_MAGIC) {
+      pMe->err = 1;
       return NULLUsefulBufC;
    }
 
-   if(pMe->magic != USEFUL_OUT_BUF_MAGIC) {
-      pMe->err = 1;
+   if(pMe->err) {
       return NULLUsefulBufC;
    }
 
@@ -442,9 +445,9 @@
  *
  * Code Reviewers: THIS FUNCTION DOES POINTER MATH
  */
-UsefulBufC UsefulOutBuf_SubString(UsefulOutBuf *pMe,
-                                  const size_t  uStart,
-                                  const size_t  uLen)
+UsefulBufC UsefulOutBuf_OutSubString(UsefulOutBuf *pMe,
+                                     const size_t  uStart,
+                                     const size_t  uLen)
 {
    const UsefulBufC Tmp = UsefulOutBuf_OutUBuf(pMe);
 
@@ -544,34 +547,53 @@
    const uint8_t *pEnd;
    const uint8_t *p1;
    const uint8_t *p2;
+   const uint8_t *p1Start;
+   const uint8_t *p2Start;
    const uint8_t *p1End;
    const uint8_t *p2End;
    int            uComparison;
+   size_t         uComparedLen1;
+   size_t         uComparedLen2;
 
-   pBase = pMe->UB.ptr;
-   pEnd = (const uint8_t *)pBase + pMe->data_len;
-   p1   = pBase + uStart1;
-   p2   = pBase + uStart2;
-   p1End = p1 + uLen1;
-   p2End = p2 + uLen2;
+   pBase   = pMe->UB.ptr;
+   pEnd    = (const uint8_t *)pBase + pMe->data_len;
+   p1Start = pBase + uStart1;
+   p2Start = pBase + uStart2;
+   p1End   = p1Start + uLen1;
+   p2End   = p2Start + uLen2;
 
    uComparison = 0;
-   while(p1 < pEnd && p2 < pEnd && p1 < p1End && p2 < p2End) {
+   for(p1 = p1Start, p2 = p2Start;
+       p1 < pEnd && p2 < pEnd && p1 < p1End && p2 < p2End;
+       p1++, p2++) {
       uComparison = *p2 - *p1;
       if(uComparison != 0) {
-         break;;
+         break;
       }
-      p1++;
-      p2++;
    }
 
-   if(uComparison == 0 && p1 != p1End && p2 != p2End) {
-      if(uLen1 > uLen2) {
+   /* Loop might have terminated because strings were off
+    * the end of the buffer. Compute actual lengths compared.
+    */
+   uComparedLen1 = uLen1;
+   if(p1 >= pEnd) {
+      uComparedLen1 = (size_t)(p1 - p1Start);
+   }
+   uComparedLen2 = uLen2;
+   if(p2 >= pEnd) {
+      uComparedLen2 = (size_t)(p2 - p2Start);
+   }
+
+   if(uComparison == 0) {
+      /* All bytes were equal, now check the lengths */
+      if(uComparedLen2 > uComparedLen1) {
+         /* string 1 is a substring of string 2 */
          uComparison = 1;
-      } else if(uLen2 < uLen1){
+      } else if(uComparedLen1 > uComparedLen2) {
+         /* string 2 is a substring of string 1 */
          uComparison = -1;
-      } else  {
-         return 0;
+      } else {
+         /* do nothing, uComparison already is 0 */
       }
    }