Skip to content

lib: strnum - Reject empty string in str_to_float() and str_to_double() - #309

Open
Nishuuzz wants to merge 2 commits into
dovecot:mainfrom
Nishuuzz:strnum-empty-float
Open

lib: strnum - Reject empty string in str_to_float() and str_to_double()#309
Nishuuzz wants to merge 2 commits into
dovecot:mainfrom
Nishuuzz:strnum-empty-float

Conversation

@Nishuuzz

Copy link
Copy Markdown

str_to_float("") and str_to_double("") return 0 and store 0 in *num_r instead of failing.

strtof()/strtod() perform no conversion for an empty string. They return 0 and leave endp pointing at str. The check in both functions only looks at *endp, and *endp is the terminating NUL, so the empty string passes as a valid 0. Every other str_to_*() in strnum.c rejects input that isn't a number, so this one is the odd one out.

The fix is to also require that endp moved past str.

Where it shows up in tree: dict-sql's DICT_SQL_TYPE_DOUBLE case accepts an empty field value and stores 0.0 for it, while DICT_SQL_TYPE_UINT sitting right above it rejects the same value because str_to_int64() validates it. Two adjacent cases in one switch disagreeing about empty input.

How I checked it: I couldn't build Dovecot on this machine (Windows, no autotools), so I pulled str_to_float()/str_to_double() out verbatim and compiled them standalone with gcc, before and after the change. Running every string of length 0 to 3 over the characters 0 1 . - + e x space n i — 1111 inputs, covering digits, signs, exponents, hex and inf/nan prefixes and whitespace — the two versions differ on exactly one input, the empty string. Nothing else moves, which matches the reasoning above: anything strto[fd]() refuses leaves a non-NUL character behind for the *endp check to catch.

I also ran the tests[] table from test_str_to_float() against both versions. The seven existing cases pass either way; the new "" case fails before the change and passes after.

The second commit is a one-liner for test_str_to_float() calling test_begin("str_to_int"), which would have reported the new failure under the wrong test name. Happy to drop it if you'd rather keep it separate.

Introduced in e8274de.

strtof() and strtod() perform no conversion for an empty string: they
return 0 and leave endp pointing at str. The existing check only looked
at *endp, which is NUL in that case, so str_to_float("") and
str_to_double("") returned 0 and stored 0 in *num_r. Every other
str_to_*() in this file rejects input that isn't a number.

Check that endp moved past str as well.

The only caller in tree is dict-sql's DICT_SQL_TYPE_DOUBLE, which
accepted an empty field value and stored 0.0 for it. The
DICT_SQL_TYPE_UINT case next to it rejects the same input, since
str_to_int64() validates it.

Only the empty string changes behaviour; any other input that strto[fd]()
refuses already leaves a non-NUL character behind for the *endp check to
catch.

Introduced in e8274de.
test_str_to_float() called test_begin("str_to_int"), so a failure in it
was reported under the name of an unrelated test.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant