diff options
| author | Leah Rowe <leah@libreboot.org> | 2026-03-30 02:34:30 +0100 |
|---|---|---|
| committer | Leah Rowe <leah@libreboot.org> | 2026-03-30 03:03:14 +0100 |
| commit | b96708bd3abc3cca7894b96a22caf6291b0748b0 (patch) | |
| tree | c09e9ff1532a814dbd44a961655a09e48caebd72 | |
| parent | 9d4302deb237d0b65696ded4924206626e4dd997 (diff) | |
lbutils: strict string functions - abort on err
on the conditions where these functions encounter
an unexpected error, we currently return -1
this means that the caller must check. which means
the caller won't check. nobody does. i often forget.
force the caller (me) to be correct, instead.
the current calling convention is that the real
return value is stored in a pointer, provided inside
the function signature, on a given string function,
and the function's return value is merely an indicator.
this calling convention is retained for now; the next
patch will change it, such that the real value is also
the function's return value. this is more flexible.
Signed-off-by: Leah Rowe <leah@libreboot.org>
| -rw-r--r-- | util/libreboot-utils/lib/string.c | 135 |
1 files changed, 89 insertions, 46 deletions
diff --git a/util/libreboot-utils/lib/string.c b/util/libreboot-utils/lib/string.c index f56a4e55..7f336eb6 100644 --- a/util/libreboot-utils/lib/string.c +++ b/util/libreboot-utils/lib/string.c @@ -24,17 +24,25 @@ */ #define ff ((size_t)-1 / 0xFF) #define high ((ff) * 0x80) +/* NOTE: + * do not assume that a match means + * both words have null at the same + * location. see how this is handled + * e.g. in scmp. + */ #define zeroes(x) (((x) - (ff)) & ~(x) & (high)) size_t page_remain(const void *p) { + /* calling sysconf repeatedly + * is folly. cache it (static) + */ static size_t pagesz = 0; if (!pagesz) - pagesz = pagesize(), - pagesz -= ((uintptr_t)p & (pagesz - 1)); + pagesz = (size_t)pagesize(); - return pagesz; + return pagesz - ((uintptr_t)p & (pagesz - 1)); } long @@ -122,49 +130,56 @@ scmp(const char *a, size_t j; size_t wa; size_t wb; + int saved_errno = errno; - if (a == NULL || - b == NULL || - rval == NULL) { - errno = EFAULT; + if (if_err(a == NULL || b == NULL || rval == NULL, EFAULT)) goto err; - } for ( ; ((uintptr_t)(a + i) % sizeof(size_t)) != 0; i++) { - if (i >= maxlen) + if (if_err(i >= maxlen, EOVERFLOW)) goto err; else if (!ccmp(a, b, i, rval)) - return 0; + goto out; } for ( ; i + sizeof(size_t) <= maxlen; i += sizeof(size_t)) { + /* prevent crossing page boundary on word check */ + if (page_remain(a + i) < sizeof(size_t) || + page_remain(b + i) < sizeof(size_t)) + break; + memcpy(&wa, a + i, sizeof(size_t)); memcpy(&wb, b + i, sizeof(size_t)); if (wa != wb) for (j = 0; j < sizeof(size_t); j++) if (!ccmp(a, b, i + j, rval)) - return 0; + goto out; if (!zeroes(wa)) continue; *rval = 0; - return 0; + goto out; } for ( ; i < maxlen; i++) if (!ccmp(a, b, i, rval)) - return 0; + goto out; err: - errno = EFAULT; + (void) set_errno(saved_errno, EFAULT); if (rval != NULL) *rval = -1; + + err_exit(errno, "scmp"); return -1; +out: + errno = saved_errno; + return 0; } int ccmp(const char *a, const char *b, @@ -173,9 +188,8 @@ int ccmp(const char *a, const char *b, unsigned char ac; unsigned char bc; - if (if_err(a == NULL || b == NULL, EFAULT) || - rval == NULL) - return -1; + if (if_err(a == NULL || b == NULL || rval == NULL, EFAULT)) + err_exit(errno, "ccmp"); ac = (unsigned char)a[i]; bc = (unsigned char)b[i]; @@ -197,15 +211,13 @@ slen(const char *s, size_t maxlen, size_t *rval) { + int saved_errno = errno; size_t i = 0; size_t w; size_t j; - if (s == NULL || - rval == NULL) { - errno = EFAULT; + if (if_err(s == NULL || rval == NULL, EFAULT)) goto err; - } for ( ; ((uintptr_t)(s + i) % sizeof(size_t)) != 0; i++) { @@ -213,7 +225,7 @@ slen(const char *s, goto err; if (s[i] == '\0') { *rval = i; - return 0; + goto out; } } @@ -221,14 +233,13 @@ slen(const char *s, i += sizeof(size_t)) { memcpy(&w, s + i, sizeof(size_t)); - if (!zeroes(w)) continue; for (j = 0; j < sizeof(size_t); j++) { if (s[i + j] == '\0') { *rval = i + j; - return 0; + goto out; } } } @@ -236,15 +247,20 @@ slen(const char *s, for ( ; i < maxlen; i++) { if (s[i] == '\0') { *rval = i; - return 0; + goto out; } } err: - errno = EFAULT; + (void) set_errno(saved_errno, EFAULT); if (rval != NULL) *rval = 0; + + err_exit(errno, "slen"); return -1; +out: + errno = saved_errno; + return 0; } /* strict word-based strdup */ @@ -256,21 +272,22 @@ sdup(const char *s, size_t w; size_t i = 0; char *out = NULL; + int saved_errno = errno; - if (dest == NULL || *dest != NULL || s == NULL) + if (if_err(dest == NULL || *dest != NULL || s == NULL, EFAULT)) goto err; out = smalloc(dest, max); for ( ; ((uintptr_t)(s + i) % sizeof(size_t)) != 0; i++) { - if (i >= max) + if (if_err(i >= max, EOVERFLOW)) goto err; out[i] = s[i]; if (s[i] == '\0') { *dest = out; - return 0; + goto out; } } @@ -290,7 +307,7 @@ sdup(const char *s, out[i + j] = s[i + j]; if (s[i + j] == '\0') { *dest = out; - return 0; + goto out; } } } @@ -300,7 +317,7 @@ sdup(const char *s, out[i] = s[i]; if (s[i] == '\0') { *dest = out; - return 0; + goto out; } } @@ -308,8 +325,14 @@ err: free_and_set_null(&out); if (dest != NULL) *dest = NULL; - errno = EFAULT; + + (void) set_errno(saved_errno, EFAULT); + err_exit(errno, "sdup"); + return -1; +out: + errno = saved_errno; + return 0; } /* concatenate N number of strings */ @@ -347,6 +370,7 @@ scatn(ssize_t sc, const char **sv, rtmp = NULL; } + errno = saved_errno; *rval = final; return 0; err: @@ -354,7 +378,10 @@ err: free_and_set_null(&rtmp); free_and_set_null(&final); - return set_errno(saved_errno, EFAULT); + (void) set_errno(saved_errno, EFAULT); + + err_exit(errno, "scatn"); + return -1; } /* strict strcat */ @@ -365,16 +392,16 @@ scat(const char *s1, const char *s2, size_t size1; size_t size2; char *rval = NULL; + int saved_errno = errno; - if (if_err(dest == NULL || *dest != NULL, EFAULT) || - slen(s1, n, &size1) < 0 || - slen(s2, n, &size2) < 0 || - if_err(size1 > SIZE_MAX - size2 - 1, EOVERFLOW)) { + if (if_err(dest == NULL || *dest != NULL, EFAULT)) + goto err; - if (dest != NULL) - *dest = NULL; - return -1; - } + slen(s1, n, &size1); + slen(s2, n, &size2); + + if (if_err(size1 > SIZE_MAX - size2 - 1, EOVERFLOW)) + goto err; memcpy(smalloc(&rval, size1 + size2 + 1), s1, size1); @@ -382,7 +409,15 @@ scat(const char *s1, const char *s2, *(rval + size1 + size2) = '\0'; *dest = rval; + errno = saved_errno; return 0; +err: + (void) set_errno(saved_errno, EINVAL); + if (dest != NULL) + *dest = NULL; + err_exit(errno, "scat"); + + return -1; } /* strict split/de-cat - off is where @@ -395,14 +430,16 @@ dcat(const char *s, size_t n, size_t size; char *rval1 = NULL; char *rval2 = NULL; + int saved_errno = errno; + + if (if_err(dest1 == NULL || dest2 == NULL, EFAULT)) + goto err; - if (dest1 == NULL || dest2 == NULL || - slen(s, n, &size) < 0 || - if_err(size == SIZE_MAX, EOVERFLOW) || - if_err(off >= size, EOVERFLOW)) { + slen(s, n, &size); + if (if_err(size >= SIZE_MAX - 1, EOVERFLOW) || + if_err(off >= size, EOVERFLOW)) goto err; - } memcpy(smalloc(&rval1, off + 1), s, off); @@ -415,6 +452,7 @@ dcat(const char *s, size_t n, *dest1 = rval1; *dest2 = rval2; + errno = saved_errno; return 0; err: @@ -423,6 +461,9 @@ err: free_and_set_null(&rval1); free_and_set_null(&rval2); + (void) set_errno(saved_errno, EINVAL); + err_exit(errno, "dcat"); + return -1; } @@ -433,6 +474,7 @@ err: int vcmp(const void *s1, const void *s2, size_t n) { + int saved_errno = errno; size_t i = 0; size_t a; size_t b; @@ -459,6 +501,7 @@ vcmp(const void *s1, const void *s2, size_t n) if (x[i] != y[i]) return (int)x[i] - (int)y[i]; + errno = saved_errno; return 0; } |
