Welcome to little lamb

Code » limb » commit 8c6f6b9

uint64_{,un}pack_trim: Add length argument

author Olivier Brunel
2023-04-30 13:51:43 UTC
committer Olivier Brunel
2023-05-20 18:06:39 UTC
parent 8dbc05d787cb50330dd32cd0267a3ba43d1193f7

uint64_{,un}pack_trim: Add length argument

We used to assume we could always read/write up to 9 bytes if needed.
Instead we take a limit/length argument, returning -1 on error.

src/doc/u64.h/u64_pack.3.md +8 -5
src/doc/uint64.h/uint64_pack_trim.3.md +15 -11
src/liblimb/include/limb/u64.h +2 -2
src/liblimb/include/limb/uint64.h +2 -2
src/liblimb/saencdata.h/saencdata.c +2 -2
src/liblimb/uint64.h/uint64_pack_trim.c +8 -6
src/liblimb/uint64.h/uint64_unpack_trim.c +14 -8

diff --git a/src/doc/u64.h/u64_pack.3.md b/src/doc/u64.h/u64_pack.3.md
index 539f84b..a95089e 100644
--- a/src/doc/u64.h/u64_pack.3.md
+++ b/src/doc/u64.h/u64_pack.3.md
@@ -17,8 +17,8 @@ void u64_pack(void *<em>dst</em>, u64 <em>val</em>)
 void u64_unpack(u64 *<em>val</em>, const void *<em>sce</em>)
 void u64_pack_big(void *<em>dst</em>, u64 <em>val</em>)
 void u64_unpack_big(u64 *<em>val</em>, const void *<em>sce</em>)
-int u64_pack_trim(void *<em>dst</em>, u64 <em>val</em>)
-int u64_unpack_trim(u64 *<em>val</em>, const void *<em>sce</em>)
+int u64_pack_trim(void *<em>dst</em>, size_t <em>dlen</em>, u64 <em>val</em>)
+int u64_unpack_trim(u64 *<em>val</em>, const void *<em>sce</em>, size_t <em>slen</em>)
 ```
 
 # DESCRIPTION
@@ -31,11 +31,13 @@ The `u64_pack`() function packs `val` into 8 bytes encoded as little endian,
 the `u64_pack_big`() function does the same encoded as big endian, and the
 `u64_pack_trim`() function pack in a little endian mode but /trimming/ the
 "unneeded" bits, i.e. all most significant bits set to zero need not be
-included. It will therefore pack into from 1 to 9 bytes, depending on the value.
+included. It will therefore need to pack into from 1 to 9 bytes, depending on
+the value. It will never write more than `dlen` bytes though.
 See [uint64_pack_trim](3) for more.
 
 The `u64_unpack` family does the same, only unpacking from the byte array `sce`
-into `val`
+into `val`. Similarly, the `u64_unpack_trim`() function will never read more
+than `slen` bytes.
 
 These are actually macros to the relevant `uint64_*` functions, offering a
 slightly different interface.
@@ -43,4 +45,5 @@ slightly different interface.
 # RETURN VALUE
 
 Only `u64_pack_trim`() and `u64_unpack_trim`() have a return value, that of the
-number of bytes written to `dst` or read from `sce`, respectively.
+number of bytes written to `dst` or read from `sce`, respectively, on success.
+Otherwise - not enough byte could be written/read - they will return -1 
diff --git a/src/doc/uint64.h/uint64_pack_trim.3.md b/src/doc/uint64.h/uint64_pack_trim.3.md
index 380312a..f40c99e 100644
--- a/src/doc/uint64.h/uint64_pack_trim.3.md
+++ b/src/doc/uint64.h/uint64_pack_trim.3.md
@@ -13,31 +13,35 @@ into\/from a byte array
     #include <limb/uint64.h>
 
 ```pre hl
-int uint64_pack_trim(char *<em>dst</em>, uint64_t <em>val</em>)
-int uint64_unpack_trim(const char *<em>sce</em>, uint64_t *<em>val</em>)
+int uint64_pack_trim(char *<em>dst</em>, size_t <em>dlen</em>, uint64_t <em>val</em>)
+int uint64_unpack_trim(const char *<em>sce</em>, size_t <em>slen</em>, uint64_t *<em>val</em>)
 ```
 
 # DESCRIPTION
 
-The `uint64_pack_trim`() function will store the number `val` into `dst`
-/trimming/ the "unneeded" bits, i.e. all most significant bits set to zero need
-not be included.
+The `uint64_pack_trim`() function will store the number `val` into the byte
+array pointed by `dst` of length `dlen`, /trimming/ the "unneeded" bits, i.e.
+all most significant bits set to zero need not be included.
 
 In other words, it will only use as many bytes as necessary: The value is
 stored in little-endian mode using only 7 bits per byte, with the last (most
 significant) bit used as indicator whether or not an additional byte is
 required.
 
-Therefore the encoded number will take from only 1 up to 9 bytes; As such the
-specified buffer `dst` should be able to hold at least 9 bytes.
+Therefore the encoded number will take from only 1 up to 9 bytes.
 
-The `uint64_unpack_trim`() function will read at least 1 byte from `sce`, and up
-to 9, in order to decode the stored value and place it into `val`.
+The `uint64_unpack_trim`() function performs the reverse, reading bytes from the
+memory pointed by `sce` to get the encoded value, which will be placed into the
+memory pointed by `val`.
+It will therefore read from 1 up to 9 bytes, depending on the actual value.
+However it will only ever read up to `slen` bytes.
 
 # RETURN VALUE
 
 `uint64_pack_trim`() returns the number of bytes written to into `dst` to pack
-`val`
+`val` on success. Otherwise - i.e. more than `dlen` bytes are necessary - it
+returns -1.
 
 `uint64_unpack_trim`() returns the number of bytes read from `sce` to unpack
-`val`
+`val` on success. Otherwise - i.e. more than `slen` bytes needed to be read -
+it returns -1.
diff --git a/src/liblimb/include/limb/u64.h b/src/liblimb/include/limb/u64.h
index b220c39..f2d369a 100644
--- a/src/liblimb/include/limb/u64.h
+++ b/src/liblimb/include/limb/u64.h
@@ -19,8 +19,8 @@
 #define u64_unpack(val,sce)         uint64_unpack((const char *) (sce), val)
 #define u64_pack_big(dst,val)       uint64_pack_big((char *) (dst), val)
 #define u64_unpack_big(val,sce)     uint64_unpack_big((const char *) (sce), val)
-#define u64_pack_trim(dst,val)      uint64_pack_trim((char *) (dst), val)
-#define u64_unpack_trim(val,sce)    uint64_unpack_trim((const char *) (sce), val)
+#define u64_pack_trim(dst,dl,val)   uint64_pack_trim((char *) (dst), dl, val)
+#define u64_unpack_trim(val,sce,sl) uint64_unpack_trim((const char *) (sce), sl, val)
 
 extern size_t u64_fmt_generic(char *s, u64 u, u8 base, u8 grp, const char sep);
 extern size_t u640_fmt_generic(char *s, u64 u, u8 base, size_t min, const char fill,
diff --git a/src/liblimb/include/limb/uint64.h b/src/liblimb/include/limb/uint64.h
index 77ae892..bb1d8cb 100644
--- a/src/liblimb/include/limb/uint64.h
+++ b/src/liblimb/include/limb/uint64.h
@@ -9,7 +9,7 @@
 
 extern int msb64(uint64_t val);
 
-extern int uint64_pack_trim(char *dst, uint64_t val);
-extern int uint64_unpack_trim(const char *sce, uint64_t *val);
+extern int uint64_pack_trim(char *dst, size_t dlen, uint64_t val);
+extern int uint64_unpack_trim(const char *sce, size_t slen, uint64_t *val);
 
 #endif /* LIMB_UINT64_H */
diff --git a/src/liblimb/saencdata.h/saencdata.c b/src/liblimb/saencdata.h/saencdata.c
index 243048c..2e95486 100644
--- a/src/liblimb/saencdata.h/saencdata.c
+++ b/src/liblimb/saencdata.h/saencdata.c
@@ -18,11 +18,11 @@ saencdata(stralloc *sa, const u16 id, const void *val, const size_t size)
     sa->len += 2;
 
     if (is_blob) {
-        sa->len += u64_pack_trim(sa->s + sa->len, (u64) size);
+        sa->len += u64_pack_trim(sa->s + sa->len, 9, (u64) size);
         if (!stralloc_catb(sa, * (char **) val, size))
             goto err;
     } else {
-        sa->len += u64_pack_trim(sa->s + sa->len, * (u64 *) val);
+        sa->len += u64_pack_trim(sa->s + sa->len, 9, * (u64 *) val);
     }
 
     return 1;
diff --git a/src/liblimb/uint64.h/uint64_pack_trim.c b/src/liblimb/uint64.h/uint64_pack_trim.c
index 995187e..b4252c1 100644
--- a/src/liblimb/uint64.h/uint64_pack_trim.c
+++ b/src/liblimb/uint64.h/uint64_pack_trim.c
@@ -5,17 +5,19 @@
 #include <limb/uint64.h>
 
 int
-uint64_pack_trim(char *dst_, uint64_t val)
+uint64_pack_trim(char *dst_, size_t dlen, uint64_t val)
 {
     uint8_t *dst = (uint8_t *) dst_;
-    int bits = msb64(val);
-    int b;
+    unsigned int bits = msb64(val);
+    unsigned int b = 0;
 
     /* ensure little endianness */
     uint64_littlep(&val);
 
-    for (b = 0; b < 8; ++b) {
+    for (;;) {
         int n = bits > 7 ? 7 : bits;
+        /* enough room? */
+        if (b >= dlen) return -1;
         /* store the 7 low bits */
         dst[b] = val & 127;
         /* and shift them out */
@@ -24,8 +26,8 @@ uint64_pack_trim(char *dst_, uint64_t val)
         if (!bits)
             break;
         /* add our flag: one more byte */
-        dst[b] |= 128;
+        dst[b++] |= 128;
     }
-    return b + 1;
 
+    return b + 1;
 }
diff --git a/src/liblimb/uint64.h/uint64_unpack_trim.c b/src/liblimb/uint64.h/uint64_unpack_trim.c
index a7bd314..dbece48 100644
--- a/src/liblimb/uint64.h/uint64_unpack_trim.c
+++ b/src/liblimb/uint64.h/uint64_unpack_trim.c
@@ -4,23 +4,29 @@
 #include <limb/uint64.h>
 
 int
-uint64_unpack_trim(const char *sce_, uint64_t *val)
+uint64_unpack_trim(const char *sce_, size_t slen, uint64_t *val)
 {
     const uint8_t *sce = (const uint8_t *) sce_;
-    int b;
+    unsigned int b = 0;
 
     *val = 0;
-    for (b = 0; b < 9; ++b) {
+    for (;;) {
+        /* is there a(nother) byte to read? */
+        if (b >= slen) return -1;
+
         uint8_t byte = sce[b];
+        /* if we're on the last byte, add the last 8 bits and be done */
+        if (b == 8) {
+            *val |= (uint64_t) byte << (7 * 8);
+            break;
+        }
         /* extract the last 7 bits from byte and add them into our val */
-        *val |= (byte & 127) << (7 * b);
-        /* is there another byte to read? */
+        *val |= (uint64_t) (byte & 127) << (7 * b);
+        /* are we done? */
         if (!(byte & 128))
             break;
+        ++b;
     }
-    /* if needed, add the last bit from the last byte */
-    if (b == 8 && sce[b] & 128)
-        *val |= 1ULL << 63;
 
     return b + 1;
 }