Browse Source

pastojs: range check of proc argument integer

git-svn-id: trunk@38016 -
Mattias Gaertner 7 years ago
parent
commit
b4d8ea7477
2 changed files with 106 additions and 54 deletions
  1. 101 50
      packages/pastojs/src/fppas2js.pp
  2. 5 4
      packages/pastojs/tests/tcmodules.pas

+ 101 - 50
packages/pastojs/src/fppas2js.pp

@@ -269,12 +269,21 @@ Works:
 - Assert(bool[,string])
 - Assert(bool[,string])
   - without sysutils: if(bool) throw string
   - without sysutils: if(bool) throw string
   - with sysutils: if(bool) throw pas.sysutils.EAssertionFailed.$create("Create",[string])
   - with sysutils: if(bool) throw pas.sysutils.EAssertionFailed.$create("Create",[string])
-- $Objectchecks:
+- Object checks:
   - Method call EInvalidCast, rtl.checkMethodCall
   - Method call EInvalidCast, rtl.checkMethodCall
   - type cast to class-type and class-of-type, rtl.asExt, EInvalidCast
   - type cast to class-type and class-of-type, rtl.asExt, EInvalidCast
--
+- Range checks:
+  - assign int:=, int+=
+  - procedure argument int
 
 
 ToDos:
 ToDos:
+- range checks:
+  - proc args
+  - assign enum:=, enum+=
+  - prop:=
+  - string[index]
+  - array[index]
+  - prop[index]
 - typecast longint(highprecint) -> value & $ffffffff
 - typecast longint(highprecint) -> value & $ffffffff
 - static arrays
 - static arrays
   - a[] of record
   - a[] of record
@@ -1257,6 +1266,8 @@ type
       AContext: TConvertContext): TJSElement; virtual;
       AContext: TConvertContext): TJSElement; virtual;
     Function CreateProcCallArgRef(El: TPasExpr; ResolvedEl: TPasResolverResult;
     Function CreateProcCallArgRef(El: TPasExpr; ResolvedEl: TPasResolverResult;
       TargetArg: TPasArgument;  AContext: TConvertContext): TJSElement; virtual;
       TargetArg: TPasArgument;  AContext: TConvertContext): TJSElement; virtual;
+    Function CreateArgumentAccess(Arg: TPasArgument; AContext: TConvertContext;
+      PosEl: TPasElement): TJSElement; virtual;
     Function CreateUnary(Members: array of string; E: TJSElement): TJSUnary;
     Function CreateUnary(Members: array of string; E: TJSElement): TJSUnary;
     Function CreateMemberExpression(Members: array of string): TJSDotMemberExpression;
     Function CreateMemberExpression(Members: array of string): TJSDotMemberExpression;
     Function CreateCallExpression(El: TPasElement): TJSCallExpression;
     Function CreateCallExpression(El: TPasElement): TJSCallExpression;
@@ -4809,8 +4820,6 @@ var
   Prop: TPasProperty;
   Prop: TPasProperty;
   ImplicitCall: Boolean;
   ImplicitCall: Boolean;
   AssignContext: TAssignContext;
   AssignContext: TAssignContext;
-  Arg: TPasArgument;
-  ParamContext: TParamContext;
   ResolvedEl: TPasResolverResult;
   ResolvedEl: TPasResolverResult;
   ProcType, TargetProcType: TPasProcedureType;
   ProcType, TargetProcType: TPasProcedureType;
   ArrLit: TJSArrayLiteral;
   ArrLit: TJSArrayLiteral;
@@ -4917,49 +4926,8 @@ begin
     end
     end
   else if Decl.ClassType=TPasArgument then
   else if Decl.ClassType=TPasArgument then
     begin
     begin
-    Arg:=TPasArgument(Decl);
-    if Arg.Access in [argVar,argOut] then
-      begin
-      // Arg is a reference object
-      case AContext.Access of
-        caRead:
-          begin
-          // create arg.get()
-          Call:=CreateCallExpression(El);
-          Call.Expr:=CreateDotExpression(El,
-            CreateIdentifierExpr(Arg.Name,Arg,AContext),
-            CreatePrimitiveDotExpr(TempRefObjGetterName,El));
-          Result:=Call;
-          exit;
-          end;
-        caAssign:
-          begin
-          // create arg.set(RHS)
-          AssignContext:=AContext.AccessContext as TAssignContext;
-          if AssignContext.Call<>nil then
-            RaiseNotSupported(El,AContext,20170214120606);
-          Call:=CreateCallExpression(El);
-          AssignContext.Call:=Call;
-          Call.Expr:=CreateDotExpression(El,
-                        CreateIdentifierExpr(Arg.Name,Arg,AContext),
-                        CreatePrimitiveDotExpr(TempRefObjSetterName,El));
-          Call.AddArg(AssignContext.RightSide);
-          AssignContext.RightSide:=nil;
-          Result:=Call;
-          exit;
-          end;
-        caByReference:
-          begin
-          // simply pass the reference
-          ParamContext:=AContext.AccessContext as TParamContext;
-          ParamContext.ReusingReference:=true;
-          Result:=CreateIdentifierExpr(Arg.Name,Arg,AContext);
-          exit;
-          end;
-        else
-          RaiseNotSupported(El,AContext,20170214120739);
-      end;
-      end;
+    Result:=CreateArgumentAccess(TPasArgument(Decl),AContext,El);
+    exit;
     end
     end
   else if Decl.ClassType=TPasResString then
   else if Decl.ClassType=TPasResString then
     begin
     begin
@@ -9207,7 +9175,7 @@ var
 Var
 Var
   FS : TJSFunctionDeclarationStatement;
   FS : TJSFunctionDeclarationStatement;
   FD : TJSFuncDef;
   FD : TJSFuncDef;
-  n:Integer;
+  n, i:Integer;
   AssignSt: TJSSimpleAssignStatement;
   AssignSt: TJSSimpleAssignStatement;
   FuncContext: TFunctionContext;
   FuncContext: TFunctionContext;
   ProcScope, ImplProcScope: TPasProcedureScope;
   ProcScope, ImplProcScope: TPasProcedureScope;
@@ -9218,6 +9186,8 @@ Var
   PosEl: TPasElement;
   PosEl: TPasElement;
   Call: TJSCallExpression;
   Call: TJSCallExpression;
   ClassPath: String;
   ClassPath: String;
+  ArgResolved: TPasResolverResult;
+  MinVal, MaxVal: MaxPrecInt;
 begin
 begin
   Result:=nil;
   Result:=nil;
 
 
@@ -9262,7 +9232,7 @@ begin
     end;
     end;
 
 
   BodyPas:=ImplProc.Body;
   BodyPas:=ImplProc.Body;
-  if (BodyPas<>nil) or (bsObjectChecks in ImplProcScope.ScannerBoolSwitches) then
+  if BodyPas<>nil then
     begin
     begin
     PosEl:=BodyPas;
     PosEl:=BodyPas;
     if PosEl=nil then
     if PosEl=nil then
@@ -9273,6 +9243,31 @@ begin
       FuncContext.ScannerBoolSwitches:=ImplProcScope.ScannerBoolSwitches;
       FuncContext.ScannerBoolSwitches:=ImplProcScope.ScannerBoolSwitches;
       FirstSt:=nil;
       FirstSt:=nil;
       LastSt:=nil;
       LastSt:=nil;
+
+      if (bsRangeChecks in ImplProcScope.ScannerBoolSwitches)
+          and (AContext.Resolver<>nil) then
+        for i:=0 to El.ProcType.Args.Count-1 do
+          begin
+          Arg:=TPasArgument(El.ProcType.Args[i]);
+          if Arg.ArgType=nil then continue;
+          AContext.Resolver.ComputeElement(Arg,ArgResolved,[rcType]);
+          if ArgResolved.BaseType in btAllJSInteger then
+            begin
+            if AContext.Resolver.ResolveAliasType(ArgResolved.TypeEl) is TPasUnresolvedSymbolRef then
+              begin
+              if not AContext.Resolver.GetIntegerRange(ArgResolved.BaseType,MinVal,MaxVal) then
+                RaiseNotSupported(Arg,AContext,20180119192608);
+              // use Arg as PosEl, so that user knows which Arg is out of range
+              Call:=CreateCallExpression(Arg);
+              Call.Expr:=CreatePrimitiveDotExpr(FBuiltInNames[pbivnRTL]+'.'+FBuiltInNames[pbifnRangeCheckInt],El);
+              AddBodyStatement(Call,Arg);
+              Call.AddArg(CreateArgumentAccess(Arg,AContext,Arg));
+              Call.AddArg(CreateLiteralNumber(Arg,MinVal));
+              Call.AddArg(CreateLiteralNumber(Arg,MaxVal));
+              end;
+            end;
+          end;
+
       if ProcScope.ClassScope<>nil then
       if ProcScope.ClassScope<>nil then
         begin
         begin
         // method or class method
         // method or class method
@@ -10872,7 +10867,7 @@ begin
         begin
         begin
         if AssignContext.LeftResolved.BaseType in btAllJSInteger then
         if AssignContext.LeftResolved.BaseType in btAllJSInteger then
           begin
           begin
-          if AssignContext.LeftResolved.TypeEl is TPasUnresolvedSymbolRef then
+          if AContext.Resolver.ResolveAliasType(AssignContext.LeftResolved.TypeEl) is TPasUnresolvedSymbolRef then
             begin
             begin
             if not AContext.Resolver.GetIntegerRange(AssignContext.LeftResolved.BaseType,MinVal,MaxVal) then
             if not AContext.Resolver.GetIntegerRange(AssignContext.LeftResolved.BaseType,MinVal,MaxVal) then
               RaiseNotSupported(El.left,AContext,20180119154120);
               RaiseNotSupported(El.left,AContext,20180119154120);
@@ -13115,6 +13110,62 @@ begin
   end;
   end;
 end;
 end;
 
 
+function TPasToJSConverter.CreateArgumentAccess(Arg: TPasArgument;
+  AContext: TConvertContext; PosEl: TPasElement): TJSElement;
+var
+  Call: TJSCallExpression;
+  AssignContext: TAssignContext;
+  ParamContext: TParamContext;
+  Name: String;
+begin
+  if Arg.Access in [argVar,argOut] then
+    begin
+    // Arg is a reference object
+    case AContext.Access of
+      caRead:
+        begin
+        // create arg.get()
+        Call:=CreateCallExpression(PosEl);
+        Call.Expr:=CreateDotExpression(PosEl,
+          CreateIdentifierExpr(Arg.Name,PosEl,AContext),
+          CreatePrimitiveDotExpr(TempRefObjGetterName,PosEl));
+        Result:=Call;
+        exit;
+        end;
+      caAssign:
+        begin
+        // create arg.set(RHS)
+        AssignContext:=AContext.AccessContext as TAssignContext;
+        if AssignContext.Call<>nil then
+          RaiseNotSupported(Arg,AContext,20170214120606);
+        Call:=CreateCallExpression(PosEl);
+        AssignContext.Call:=Call;
+        Call.Expr:=CreateDotExpression(PosEl,
+                      CreateIdentifierExpr(Arg.Name,PosEl,AContext),
+                      CreatePrimitiveDotExpr(TempRefObjSetterName,PosEl));
+        Call.AddArg(AssignContext.RightSide);
+        AssignContext.RightSide:=nil;
+        Result:=Call;
+        exit;
+        end;
+      caByReference:
+        begin
+        // simply pass the reference
+        ParamContext:=AContext.AccessContext as TParamContext;
+        ParamContext.ReusingReference:=true;
+        Result:=CreateIdentifierExpr(Arg.Name,PosEl,AContext);
+        exit;
+        end;
+      else
+        RaiseNotSupported(Arg,AContext,20170214120739);
+    end;
+    end;
+  Name:=Arg.Name;
+  if (CompareText(Name,'Self')=0) and (AContext.GetSelfContext<>nil) then
+    Name:=AContext.GetLocalName(Arg);
+  Result:=CreatePrimitiveDotExpr(Name,PosEl);
+end;
+
 function TPasToJSConverter.ConvertExceptOn(El: TPasImplExceptOn;
 function TPasToJSConverter.ConvertExceptOn(El: TPasImplExceptOn;
   AContext: TConvertContext): TJSElement;
   AContext: TConvertContext): TJSElement;
 // convert "on T do ;" to "if(T.isPrototypeOf(exceptObject)){}"
 // convert "on T do ;" to "if(T.isPrototypeOf(exceptObject)){}"

+ 5 - 4
packages/pastojs/tests/tcmodules.pas

@@ -15980,14 +15980,14 @@ begin
   'var',
   'var',
   '  b: byte;',
   '  b: byte;',
   '  w: word;',
   '  w: word;',
-  'procedure DoIt;',
+  'procedure DoIt(p: byte);',
   'begin',
   'begin',
   '  b:=w;',
   '  b:=w;',
   '  b+=w;',
   '  b+=w;',
   'end;',
   'end;',
   '{$R-}',
   '{$R-}',
   'begin',
   'begin',
-  '  DoIt;',
+  '  DoIt(w);',
   '  b:=w;',
   '  b:=w;',
   '{$R+}',
   '{$R+}',
   '']);
   '']);
@@ -15996,13 +15996,14 @@ begin
     LinesToStr([ // statements
     LinesToStr([ // statements
     'this.b = 0;',
     'this.b = 0;',
     'this.w = 0;',
     'this.w = 0;',
-    'this.DoIt = function () {',
+    'this.DoIt = function (p) {',
+    '  rtl.rc(p, 0, 255);',
     '  $mod.b = rtl.rc($mod.w,0,255);',
     '  $mod.b = rtl.rc($mod.w,0,255);',
     '  rtl.rc($mod.b += $mod.w, 0, 255);',
     '  rtl.rc($mod.b += $mod.w, 0, 255);',
     '};',
     '};',
     '']),
     '']),
     LinesToStr([ // $mod.$main
     LinesToStr([ // $mod.$main
-    '$mod.DoIt();',
+    '$mod.DoIt($mod.w);',
     '$mod.b = rtl.rc($mod.w,0,255);',
     '$mod.b = rtl.rc($mod.w,0,255);',
     '']));
     '']));
 end;
 end;