pastojs: range check of proc argument integer

git-svn-id: trunk@38016 -
This commit is contained in:
Mattias Gaertner 2018-01-19 18:49:05 +00:00
parent 1a301b5cce
commit b4d8ea7477
2 changed files with 106 additions and 54 deletions

View File

@ -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); Result:=CreateArgumentAccess(TPasArgument(Decl),AContext,El);
if Arg.Access in [argVar,argOut] then exit;
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;
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)){}"

View File

@ -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;