Browse Source

* Fixes from Denis Kozlov, bug ID #28951
1) Erroneously increased `pind` in `findmatch()` by the length of matched string instead of by pattern token length.
2) Erroneously increased `ind` and `pind` by 2 after processing `ampm` (localized AM/PM pattern token).
3) Not updated `pind` when doing recursive subpattern matching ("ddddd", "dddddd", "t", "tt").
4) Incorrect interpretation of "t" pattern token as `ShortDateFormat`, when it should be `ShortTimeFormat`.
5) Incorrect scanning for "y" pattern (2 digit year), max scanned digits was 1 while it should be 2.
6) Protect against buffer over-read of `p` variable in `findimatch()`.

git-svn-id: trunk@32348 -

michael 9 years ago
parent
commit
e45686f24d
1 changed files with 41 additions and 21 deletions
  1. 41 21
      packages/rtl-objpas/src/inc/dateutil.inc

+ 41 - 21
packages/rtl-objpas/src/inc/dateutil.inc

@@ -2277,13 +2277,17 @@ var
 
 function findimatch(const mnts:array of string;p:pchar):integer;
 var i : integer;
+    plen, findlen: integer;
 begin
   result:=-1;
   i:=0;
+  plen := strlen(p);
   while (i<=high(mnts)) and (result=-1) do
     begin
-      if AnsiStrLIComp(p,@mnts[i][1],length(mnts[i]))=0 then
-        result:=i;
+      findlen := length(mnts[i]);
+      if (findlen > 0) and (findlen <= plen) then // protect against buffer over-read
+        if AnsiStrLIComp(p,@(mnts[i][1]),findlen)=0 then
+          result:=i;
       inc(i);
     end;
 end;
@@ -2294,18 +2298,17 @@ begin
   raiseexception(format(SNoArrayMatch,[pind+1,ind]))
 end;
 
-function findmatch(const mnts : array of string;const s:string):integer;
-
+function scanmatch(const mnts : array of string;p:pchar; patlen: integer):integer;
 begin
-  result:=findimatch(mnts,@s[ind]);
+  result:=findimatch(mnts,p);
   if result=-1 then
     arraymatcherror
   else
-    begin
-      inc(ind,length(mnts[result])+1);
-      inc(pind,length(mnts[result])+1);
-      inc(result); // was 0 based.
-    end;
+  begin
+    inc(ind,length(mnts[result]));
+    inc(pind,patlen);
+    inc(result); // was 0 based.
+  end;
 end;
 
 var
@@ -2384,10 +2387,18 @@ begin
                        i:=scanpatlen;
                        case i of
                           1,2 : dd:=scanfixedint(2);
-                          3   : dd:=findmatch(fmt.shortDayNames,s);
-                          4   : dd:=findmatch(fmt.longDayNames,s);
-                          5   : matchpattern(fmt.shortdateformat);
-                          6   : matchpattern(fmt.longdateformat);
+                          3   : dd:=scanmatch(fmt.shortDayNames,@s[ind],i);
+                          4   : dd:=scanmatch(fmt.longDayNames,@s[ind],i);
+                          5   :
+                            begin
+                              matchpattern(fmt.shortdateformat);
+                              inc(pind, i);
+                            end;
+                          6   :
+                            begin
+                              matchpattern(fmt.longdateformat);
+                              inc(pind, i);
+                            end;
                          end;
                      end;
                'N':  timeval:=timeval+scanfixedint(2)* minfactor;
@@ -2395,7 +2406,10 @@ begin
                'Z':  timeval:=timeval+scanfixedint(3)* mssecfactor;
                'Y':  begin
                        i:=scanpatlen;
-                       yy:=scanfixedint(i);
+                       case i of
+                          1,2 : yy:=scanfixedint(2);
+                          else  yy:=scanfixedint(i);
+                       end;
                        if i<=2 then
                          begin
                            pivot:=YearOf(now)-fmt.TwoDigitYearCenturyWindow;
@@ -2408,15 +2422,23 @@ begin
                        i:=scanpatlen;
                        case i of
                           1,2: mm:=scanfixedint(2);
-                          3:   mm:=findmatch(fmt.ShortMonthNames,s);
-                          4:   mm:=findmatch(fmt.LongMonthNames,s);
+                          3:   mm:=scanmatch(fmt.ShortMonthNames,@s[ind],i);
+                          4:   mm:=scanmatch(fmt.LongMonthNames,@s[ind],i);
                           end;
                     end;
                'T' : begin
                        i:=scanpatlen;
                        case i of
-                       1: matchpattern(fmt.shortdateformat);
-                       2: matchpattern(fmt.longtimeformat);
+                       1:
+                         begin
+                           matchpattern(fmt.shorttimeformat);
+                           inc(pind, i);
+                         end;
+                       2:
+                         begin
+                           matchpattern(fmt.longtimeformat);
+                           inc(pind, i);
+                         end;
                        end;
                      end;
                'A' : begin
@@ -2455,8 +2477,6 @@ begin
                                      arraymatcherror
                                      end;
                                    inc(pind,length(AMPMformatting[2]));
-                                   inc(pind,2);
-                                   inc(ind,2);
                                  end;
                             else  // no AM/PM match. Assume 'a' is simply a char
                                 matchchar(ptrn[pind]);