Skip to content

Decimal literals depend on LC_NUMERIC via strtod after setlocale #142

Description

@kavyabhand

Summary

At pin 4a7456e2, next_token enters the number branch when the next byte is a digit or '.', then calls strtod (tinyexpr.c:250-252). strtod honours LC_NUMERIC. After setlocale to a comma-decimal locale, expressions that are valid in the C locale fail to parse.

This is a correctness bug for any host that calls setlocale. It is not a hang/DoS in our measurements: parse returns an error. Env-only LC_ALL=de_DE.UTF-8 without setlocale does not trigger it, because the process stays in the C locale (the upstream smoke suite never calls setlocale either).

Observed behaviour

macOS 15.1.1 / Apple clang 16 and Ubuntu 24.04 aarch64 / gcc 13.3, after setlocale(LC_ALL, "de_DE.UTF-8") (or fr_FR.UTF-8):

Expression err notes
1.5 1 nan; valid in C locale
.5 1 completes; no hang within the run
1,5 0 value 1.5 (comma accepted)
2.25+3.5 1 fails

Under setlocale(LC_ALL, "C"), 1.5 and 2.25+3.5 succeed.

Expected behaviour

For a math expression library, decimal-point tokenization should follow a fixed convention (typically C-locale '.'), or the docs should state that callers must keep LC_NUMERIC at "C".

Root cause

if ((s->next[0] >= '0' && s->next[0] <= '9') || s->next[0] == '.') {
    s->value = strtod(s->next, (char**)&s->next);
    s->type = TOK_NUMBER;
}

The '.' trigger is locale-independent; strtod is not.

Minimal reproducer

#include <locale.h>
#include <stdio.h>
#include "tinyexpr.h"
int main(void) {
    setlocale(LC_ALL, "de_DE.UTF-8");
    int err = 0;
    double v = te_interp("1.5", &err);
    printf("err=%d value=%.17g\n", err, v);
    return 0;
}

Note on hang hypothesis

We also checked whether a non-advancing strtod on ".5" under a comma locale could loop forever. On the platforms above, te_interp(".5") returned err=1 and completed. So we are filing a locale correctness issue, not a DoS.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions