avoid UB when calling ctype functions
What changed, and why it matters
This commit fixes a low-level programming bug in four source files. The standard C library functions used to check whether a character is a digit or whitespace (like isdigit and isspace) can misbehave or crash when given a character whose numeric value is negative on systems where the char type is signed. The patch replaces those direct calls with safer project-specific wrappers that cast the value to an unsigned type first. This is a defensive hardening change rather than a fix for a known exploitable vulnerability.
Treat as a defensive hardening patch. Apply it to reduce undefined-behavior surface, especially on platforms with signed char. No immediate incident response is warranted unless additional evidence shows a reproducible crash or exploit path.
Security signals we found
Undefined-behavior mitigation in character classification
Use of project-specific ctype wrappers (cisdigit, cisspace)
Signed char promotion risk on affected platforms
Potential denial-of-service or crash vector from out-of-range ctype input
No explicit security advisory or CVE referenced in commit
Evidence from the diff
The C standard leaves the signedness of the char type implementation-defined. On platforms with signed char, passing a char value with the high bit set (e.g., 0x80-0xFF) to
Changed components
common/json_parse.ccommon/splice_script.cdb/db_sqlite3.cdevtools/onion.cInspect captured patch +4 / −4
diff --git a/common/json_parse.c b/common/json_parse.c
index 7b5c31c8..260e9e1b 100644
--- a/common/json_parse.c
+++ b/common/json_parse.c
@@ -30,7 +30,7 @@ bool json_to_millionths(const char *buffer, const jsmntok_t *tok,
*millionths = 0;
for (int i = tok->start; i < tok->end; i++) {
- if (isdigit(buffer[i])) {
+ if (cisdigit(buffer[i])) {
has_digits = true;
/* Ignore too much precision */
if (decimal_places >= 0 && ++decimal_places > 6)
diff --git a/common/splice_script.c b/common/splice_script.c
index 453bc6ca..fd07c3e2 100644
--- a/common/splice_script.c
+++ b/common/splice_script.c
@@ -503,7 +503,7 @@ char *fmt_splice_script_compiler_error(const tal_t *ctx,
static bool is_whitespace(char c)
{
- return isspace(c);
+ return cisspace(c);
}
static struct splice_script_error *clean_whitespace(const tal_t *ctx,
diff --git a/db/db_sqlite3.c b/db/db_sqlite3.c
index 07ded41f..171c0e06 100644
--- a/db/db_sqlite3.c
+++ b/db/db_sqlite3.c
@@ -418,7 +418,7 @@ static const char *find_column_name(const tal_t *ctx,
{
size_t start = 0;
- while (isspace(sqlpart[start]))
+ while (cisspace(sqlpart[start]))
start++;
*after = strspn(sqlpart + start, "abcdefghijklmnopqrstuvwxyz_0123456789") + start;
if (*after == start || !cisspace(sqlpart[*after]))
diff --git a/devtools/onion.c b/devtools/onion.c
index 0d517c15..ca723afd 100644
--- a/devtools/onion.c
+++ b/devtools/onion.c
@@ -145,7 +145,7 @@ static void do_decode(int argc, char **argv, const u8 *assocdata)
size_t hexlen = strlen(hextemp);
// trim trailing whitespace
- while (isspace(hextemp[hexlen-1]))
+ while (cisspace(hextemp[hexlen-1]))
hexlen--;
serialized = tal_hexdata(hextemp, hextemp, hexlen);
Why this scored 37/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.