← board

StrToFloat returns 0 for garbage, and rejects trailing whitespace

Measured — pxx vs FPC 3.2.2

1. Malformed input silently returns 0

before FPC
StrToInt('nope') raises raises
StrToInt64('nope') raises raises
StrToQWord('nope') raises raises
StrToBool('nope') raises raises
StrToFloat('nope') 0 EConvertError
StrToFloat('') 0 EConvertError
StrToFloat('1.2.3') 0 EConvertError
StrToFloat('1e') 0 EConvertError
StrToCurr('nope') 0 EConvertError

Every integer arm was already right; every float arm was wrong. 0 is the dangerous answer — a plausible number the caller carries on with, the same shape as Floor(1e30) = 0 in [[bug-b-floor-of-an-out-of-range-double-returns-0-where-fpc-raises]].

FPC's message is "%s" is an invalid float, and it is the same for StrToCurr — verified rather than assumed, since callers match on message text.

2. Valid input wrongly rejected

The parser skipped leading ' ' and nothing else:

input before FPC
' 1.5' 1.5 1.5
'1.5 ' rejected 1.5
' 1.5 ' rejected 1.5
#9'1.5' rejected 1.5
'1.5'#9 rejected 1.5
' 1.5e2 ' rejected 150
'1. 5', '1.5x', 'x1.5', ' ', '' rejected rejected

FPC's whitespace is any char <= ' ', measured rather than guessed: #0, #1, #11 and #12 around a float are all accepted there. That is exactly Trim's rule, which this RTL already implements FPC-compatibly.

The two halves interact: with StrToFloat returning the default silently, a rejected-but-valid '1.5 ' also came back as 0 rather than as an error.

Fix

TryStrToFloat and StrToFloatDef keep their non-raising contract, and pick up the whitespace fix — which is what callers wanting the old leniency should use.

Callers checked

lib/rtl/json.pas (a number the JSON parser already validated), lib/rtl/ast.pas (a lexed float literal) and test/lib_floattostr.pas (round-trips of generated text) all pass well-formed input, so the raise cannot fire for them. For json.pas the raise is strictly better than a silent 0.

Gate

All five probe programs identical to FPC — the conversion family (14 rows), the whitespace grammar (17 rows), the control-character cases (6 rows), the message text (4 rows) and the exception surface (16 rows) — plus make lib-test green.

Log