StrToTime gives wrong result on invalid timestring, or chokes on it
Original Reporter info from Mantis: Bart @flyingsheep
-
Reporter name: Bart Broersma
Original Reporter info from Mantis: Bart @flyingsheep
- Reporter name: Bart Broersma
Description:
The StrToTime function gives wrong results:
It will accept a string like '0a:0b:0c' and will return 0.0 where it should reaise an exception.
It will also interpret '12:00:00 px' as 12 o'clock PM, because it will only check for the first character of it, imagine your PM and Am string of your locale beginning with the same caharacter (not sure this is a real life scenario, but it could happen)
It will choke on a string like '12:00:0x' where it will go into an infinite loop.
Further more it will trash memory if you supply a string like '12:34:56:99:88 am'
Tested with the StrToTime routines from svn trunk (dati.inc from r14116)
Additional information:
From dati.inc (r14116)
function IntStrToTime(Out ErrorMsg : AnsiString; const S: PChar; Len : integer;const defs:TFormatSettings; separator : char = #0): TDateTime;
var
Current: integer; PM: integer;
function StrPas(Src : PChar; len: integer = 0) : ShortString;
var
tmp : integer;
begin
{tmp := IndexChar(Src[0], len, #0);
len :=ifthen(tmp >= 0, tmp, len);
len :=ifthen(len > 255, 255, len);}
SetLength(Result, len);
move(src[0],result[1],len);
end;
function GetElement: integer;
var
j, c: integer;
CurrentChar : Char;
begin
result := -1;
while (result = -1) and (Current < Len) do
begin
CurrentChar := S[Current];
^^ with '12:00:0x' (any non-digit as last charactre here will do) as input
^^ it will loop with:
^^ Current = 7, Len = 8, CurrentChar = 'x'
if CurrentChar in ['0'..'9'] then
begin
j := Current;
while (Current+1 < Len) and (s[Current + 1] in ['0'..'9']) do
Inc(Current);
val(StrPas(S+j, 1 + current - j), result, c);
end
else if ((defs.TimeAMString<>'') and (CurrentChar = defs.TimeAMString[1])) or (S[Current] in ['a', 'A']) then
begin
pm:=1;
Current := 1 + Len;
end
else if ((defs.TimePMString<>'') and (CurrentChar = defs.TimePMString[1])) or (S[Current] in ['p', 'P']) then
begin
Current := 1 + Len;
PM := 2;
end
else if (CurrentChar = Separator) or (CurrentChar = ' ') then
Inc(Current)
else
ErrorMsg:=Format(SErrInvalidTimeFormat,[StrPas(S)]);
end ;
end ;
var
i: integer;
TimeValues: array[0..4] of integer;
begin
if separator = #0 then
separator := defs.TimeSeparator;
Current := 0;
PM := 0;
for i:=0 to 4 do
timevalues[i]:=0;
i := 0;
TimeValues[i] := GetElement;
If ErrorMsg<>'' then
Exit;
while (i < 5) and (TimeValues[i] <> -1) do
begin
^^ with input = '12:34:56:99:88' TimeValue[4] = 88
^^ and now we will access TimeValues[5] which is invalid memory !!
i := i + 1;
Inc(Current);
TimeValues[i] := GetElement;
If ErrorMsg<>'' then
Exit;
end ;
If (i<5) and (TimeValues[I]=-1) then
TimeValues[I]:=0;
if PM=2 then
begin
if (TimeValues[0] <> 12) then
Inc(TimeValues[0], 12);
end
else
begin
if (pm=1) and ((TimeValues[0]=12)) then
TimeValues[0]:=0;
end;
^^ At this point, when any GetElements returned -1, TimeValue[x] will be 0
^^ and a call to TryEncodeTime will succeed.
^^ Any result = -1 for GetElement for any of the TimeValues should set ErrorMsg and exit ??
if not TryEncodeTime(TimeValues[0], TimeValues[1], TimeValues[2], TimeValues[3],result) Then
errormsg:='Invalid time.';
end ;
Mantis conversion info:
- Mantis ID: 15505
- OS: Suse Linux
- OS Build: 10.0
- Platform: i386
- Fixed in version: 2.4.2
- Fixed in revision: 14890 (#b708f9e3)