* detect arithmetic overflows for constants at compile time

* use try..except instead of setjmp
This commit is contained in:
peter 2005-01-26 16:23:28 +00:00
parent b989cd1d4e
commit d3b559cfcc
8 changed files with 610 additions and 884 deletions

View File

@ -25,14 +25,6 @@ Unit catch;
{$i fpcdefs.inc}
{$ifdef go32v2}
{ go32v2 stack check goes nuts if ss is not the data selector (PM) }
{$S-}
{$endif}
{$ifdef watcom} // wiktor: pewnei nie potrzeba
{$S-}
{$endif}
{$ifdef DEBUG}
{$define NOCATCH}
{$endif DEBUG}
@ -61,14 +53,17 @@ uses
{$ifdef has_signal}
Var
NewSignal,OldSigSegm,
OldSigInt,OldSigFPE : SignalHandler;
NewSignal,
OldSigInt : SignalHandler;
{$endif}
Const in_const_evaluation : boolean = false;
Implementation
uses
sysutils;
{$ifdef has_signal}
{$ifdef unix}
Procedure CatchSignal(Sig : Longint);cdecl;
@ -77,22 +72,8 @@ Function CatchSignal(Sig : longint):longint;
{$endif}
begin
case Sig of
SIGSEGV : begin
{ Temporary message - until we get an error number... }
writeln ('Panic : Internal compiler error, exiting.');
internalerror(9999);
end;
SIGFPE : begin
If in_const_evaluation then
Writeln('FPE error computing constant expression')
else
Writeln('FPE error inside compiler');
Stop(1);
end;
SIGINT : begin
WriteLn('Ctrl-C Signaled!');
Stop(1);
end;
SIGINT :
raise Exception.Create('Ctrl-C Signaled!');
end;
{$ifndef unix}
CatchSignal:=0;
@ -104,18 +85,18 @@ begin
{$ifndef nocatch}
{$ifdef has_signal}
NewSignal:=SignalHandler(@CatchSignal);
{$ifndef sunos}
OldSigSegm:={$ifdef havelinuxrtl10}Signal{$else}{$ifdef Unix}fpSignal{$else}Signal{$endif}{$endif} (SIGSEGV,NewSignal);
{$endif} // lxrun on solaris hooks this for handling linux-calls!
OldSigInt:={$ifdef havelinuxrtl10}Signal{$else}{$ifdef Unix}fpSignal{$else}Signal{$endif}{$endif} (SIGINT,NewSignal);
OldSigFPE:={$ifdef havelinuxrtl10}Signal{$else}{$ifdef Unix}fpSignal{$else}Signal{$endif}{$endif} (SIGFPE,NewSignal);
{$endif}
{$endif nocatch}
end.
{
$Log$
Revision 1.20 2004-10-15 09:14:16 mazen
Revision 1.21 2005-01-26 16:23:28 peter
* detect arithmetic overflows for constants at compile time
* use try..except instead of setjmp
Revision 1.20 2004/10/15 09:14:16 mazen
- remove $IFDEF DELPHI and related code
- remove $IFDEF FPCPROCVAR and related code

View File

@ -122,9 +122,6 @@ uses
{ dpmiexcp, }
{$endif WATCOM}
{$endif}
{$ifdef USEEXCEPT}
tpexcept,
{$endif USEEXCEPT}
{$ifdef BrowserLog}
browlog,
{$endif BrowserLog}
@ -132,6 +129,7 @@ uses
{$ELSE USE_SYSUTILS}
dos,
{$ENDIF USE_SYSUTILS}
sysutils,
verbose,comphook,systems,
cutils,cclasses,globals,options,fmodule,parser,symtable,
assemble,link,import,export,tokens,pass_1
@ -245,16 +243,6 @@ var
CompilerInited : boolean;
olddo_stop : tstopprocedure;
{$ifdef USEEXCEPT}
procedure RecoverStop(err:longint);
begin
if recoverpospointer<>nil then
LongJmp(recoverpospointer^,1)
else
Stop(err);
end;
{$endif USEEXCEPT}
{****************************************************************************
Compiler
@ -286,10 +274,6 @@ begin
DoneSymtable;
DoneGlobals;
donetokens;
{$ifdef USEEXCEPT}
recoverpospointer:=nil;
longjump_used:=false;
{$endif USEEXCEPT}
end;
@ -372,19 +356,16 @@ function Compile(const cmd:string):longint;
var
starttime : real;
{$ifdef USEEXCEPT}
recoverpos : jmp_buf;
{$endif}
{$ifdef HASGETHEAPSTATUS}
hstatus : THeapStatus;
{$endif HASGETHEAPSTATUS}
begin
olddo_stop:=do_stop;
do_stop:=@minimal_stop;
{ Initialize the compiler }
try
try
{ Initialize the compiler }
InitCompiler(cmd);
{ show some info }
{ show some info }
Message1(general_t_compilername,FixFileName(system.paramstr(0)));
Message1(general_d_sourceos,source_info.name);
Message1(general_i_targetos,target_info.name);
@ -394,19 +375,17 @@ begin
WritePathList(general_t_librarypath,librarysearchpath);
WritePathList(general_t_objectpath,objectsearchpath);
{$ifdef USEEXCEPT}
if setjmp(recoverpos)=0 then
begin
recoverpospointer:=@recoverpos;
do_stop:=@recoverstop;
{$endif USEEXCEPT}
starttime:=getrealtime;
{$ifdef PREPROCWRITE}
{ Compile the program }
{$ifdef PREPROCWRITE}
if parapreprocess then
parser.preprocess(inputdir+inputfile+inputextension)
else
{$endif PREPROCWRITE}
{$endif PREPROCWRITE}
parser.compile(inputdir+inputfile+inputextension);
{ Show statistics }
if status.errorcount=0 then
begin
starttime:=getrealtime-starttime;
@ -415,23 +394,18 @@ begin
Message2(general_i_abslines_compiled,tostr(status.compiledlines),tostr(trunc(starttime))+
'.'+tostr(trunc(frac(starttime)*10)));
end;
{$ifdef USEEXCEPT}
end;
{$endif USEEXCEPT}
{ Stop is always called, so we come here when a program is compiled or not }
do_stop:=olddo_stop;
{ Stop the compiler, frees also memory }
{ no message possible after this !! }
finally
{ no message possible after this !! }
DoneCompiler;
end;
except
{ Set the return value if an error has occurred }
if status.errorcount=0 then
Compile:=0
else
Compile:=1;
Message(general_e_compilation_aborted);
DoneVerbose;
Raise;
end;
{$ifdef SHOWUSEDMEM}
{$ifdef HASGETHEAPSTATUS}
GetHeapStatus(hstatus);
@ -440,15 +414,22 @@ begin
Writeln('Memory used (heapsize): ',DStr(system.Heapsize shr 10),' Kb');
{$endif HASGETHEAPSTATUS}
{$endif SHOWUSEDMEM}
{$ifdef fixLeaksOnError}
do_stop;
{$endif fixLeaksOnError}
{ Set the return value if an error has occurred }
if status.errorcount=0 then
result:=0
else
result:=1;
end;
end.
{
$Log$
Revision 1.51 2005-01-09 20:24:43 olle
Revision 1.52 2005-01-26 16:23:28 peter
* detect arithmetic overflows for constants at compile time
* use try..except instead of setjmp
Revision 1.51 2005/01/09 20:24:43 olle
* rework of macro subsystem
+ exportable macros for mode macpas

View File

@ -112,6 +112,7 @@ general_i_hint=01016_I_Hint:
% Prefix for Hints
general_e_path_does_not_exist=01017_E_Path "$1" does not exist
% The specified path does not exist.
general_e_compilation_aborted=01018_E_Compilation aborted
% \end{description}
#
# Scanner
@ -996,6 +997,8 @@ parser_w_implicit_uses_of_variants_unit=03211_W_Implicit uses of Variants unit
parser_e_no_static_method_in_interfaces=03212_E_Class and static methods can't be used in INTERFACES
% The specifier \var{class} and directive \var{static} can't be used in interfaces
% because all methods of an interfaces must be public.
parser_e_arithmetic_operation_overflow=03213_E_Overflow in arithmetic operation
% An operation on two integers values produced an overflow
% \end{description}
#
# Type Checking

View File

@ -17,6 +17,7 @@ const
general_i_note=01015;
general_i_hint=01016;
general_e_path_does_not_exist=01017;
general_e_compilation_aborted=01018;
scan_f_end_of_file=02000;
scan_f_string_exceeds_line=02001;
scan_f_illegal_char=02002;
@ -277,6 +278,7 @@ const
parser_e_proc_already_external=03210;
parser_w_implicit_uses_of_variants_unit=03211;
parser_e_no_static_method_in_interfaces=03212;
parser_e_arithmetic_operation_overflow=03213;
type_e_mismatch=04000;
type_e_incompatible_types=04001;
type_e_not_equal_types=04002;
@ -648,9 +650,9 @@ const
option_info=11024;
option_help_pages=11025;
MsgTxtSize = 37912;
MsgTxtSize = 37975;
MsgIdxMax : array[1..20] of longint=(
18,68,213,59,57,46,100,20,35,60,
19,68,214,59,57,46,100,20,35,60,
40,1,1,1,1,1,1,1,1,1
);

File diff suppressed because it is too large Load Diff

View File

@ -69,6 +69,7 @@ interface
implementation
uses
sysutils,
globtype,systems,
cutils,verbose,globals,widestr,
symconst,symtype,symdef,symsym,symtable,defutil,defcmp,
@ -265,6 +266,7 @@ implementation
((rt = pointerconstn) or (rt = niln)) and
(nodetype in [ltn,lten,gtn,gten,equaln,unequaln,subn])) then
begin
t:=nil;
{ when comparing/substracting pointers, make sure they are }
{ of the same type (JM) }
if (lt = pointerconstn) and (rt = pointerconstn) then
@ -317,11 +319,36 @@ implementation
lv := lv * tpointerdef(right.resulttype.def).pointertype.def.size;
case nodetype of
addn :
begin
{$ifopt Q-}
{$define OVERFLOW_OFF}
{$Q+}
{$endif}
try
if (lt <> pointerconstn) then
t := genintconstnode(lv+rv)
else
t := cpointerconstnode.create(lv+rv,left.resulttype);
except
on E:EIntOverflow do
begin
Message(parser_e_arithmetic_operation_overflow);
{ Recover }
t:=genintconstnode(0)
end;
end;
{$ifdef OVERFLOW_OFF}
{$Q-}
{$undef OVERFLOW_OFF}
{$endif}
end;
subn :
begin
{$ifopt Q-}
{$define OVERFLOW_OFF}
{$Q+}
{$endif}
try
if (lt=pointerconstn) and (rt=pointerconstn) and
(tpointerdef(rd).pointertype.def.size>1) then
t := genintconstnode((lv-rv) div tpointerdef(left.resulttype.def).pointertype.def.size)
@ -329,12 +356,44 @@ implementation
t := genintconstnode(lv-rv)
else
t := cpointerconstnode.create(lv-rv,left.resulttype);
except
on E:EIntOverflow do
begin
Message(parser_e_arithmetic_operation_overflow);
{ Recover }
t:=genintconstnode(0)
end;
end;
{$ifdef OVERFLOW_OFF}
{$Q-}
{$undef OVERFLOW_OFF}
{$endif}
end;
muln :
begin
{$ifopt Q-}
{$define OVERFLOW_OFF}
{$Q+}
{$endif}
try
if (torddef(ld).typ <> u64bit) or
(torddef(rd).typ <> u64bit) then
t:=genintconstnode(lv*rv)
else
t:=genintconstnode(int64(qword(lv)*qword(rv)));
except
on E:EIntOverflow do
begin
Message(parser_e_arithmetic_operation_overflow);
{ Recover }
t:=genintconstnode(0)
end;
end;
{$ifdef OVERFLOW_OFF}
{$Q-}
{$undef OVERFLOW_OFF}
{$endif}
end;
xorn :
if is_integer(ld) then
t:=genintconstnode(lv xor rv)
@ -2071,7 +2130,11 @@ begin
end.
{
$Log$
Revision 1.136 2005-01-16 11:56:37 peter
Revision 1.137 2005-01-26 16:23:28 peter
* detect arithmetic overflows for constants at compile time
* use try..except instead of setjmp
Revision 1.136 2005/01/16 11:56:37 peter
* fixed some tabs
Revision 1.135 2005/01/16 11:13:40 peter

View File

@ -46,9 +46,6 @@ implementation
{$ifdef BrowserLog}
browlog,
{$endif BrowserLog}
{$ifdef UseExcept}
tpexcept,
{$endif UseExcept}
{$ifdef GDB}
gdb,
{$endif GDB}
@ -369,10 +366,6 @@ implementation
var
olddata : polddata;
{$ifdef USEEXCEPT}
recoverpos : jmp_buf;
oldrecoverpos : pjmp_buf;
{$endif useexcept}
begin
inc(compile_level);
parser_current_file:=filename;
@ -516,13 +509,7 @@ implementation
{ If the compile level > 1 we get a nice "unit expected" error
message if we are trying to use a program as unit.}
{$ifdef USEEXCEPT}
if setjmp(recoverpos)=0 then
begin
oldrecoverpos:=recoverpospointer;
recoverpospointer:=@recoverpos;
{$endif USEEXCEPT}
try
if (token=_UNIT) or (compile_level>1) then
begin
current_module.is_unit:=true;
@ -530,16 +517,7 @@ implementation
end
else
proc_program(token=_LIBRARY);
{$ifdef USEEXCEPT}
recoverpospointer:=oldrecoverpos;
end
else
begin
recoverpospointer:=oldrecoverpos;
longjump_used:=true;
end;
{$endif USEEXCEPT}
finally
{ restore old state }
done_module;
@ -629,17 +607,18 @@ implementation
aktmodeswitches:=oldaktmodeswitches;
aktexceptblock:=0;
exceptblockcounter:=0;
{$ifdef GDB}
{$ifdef GDB}
dbx_counter:=store_dbx;
{$endif GDB}
{$endif GDB}
end;
end
else
begin
parser_current_file:='';
{ Shut down things when the last file is compiled }
if (compile_level=1) then
{ Shut down things when the last file is compiled succesfull }
if (compile_level=1) and
(status.errorcount=0) then
begin
parser_current_file:='';
{ Close script }
if (not AsmRes.Empty) then
begin
@ -647,10 +626,6 @@ implementation
AsmRes.WriteToDisk;
end;
{$ifdef USEEXCEPT}
if not longjump_used then
{$endif USEEXCEPT}
begin
{ do not create browsers on errors !! }
if status.errorcount=0 then
begin
@ -667,40 +642,28 @@ implementation
else
browserlog.list_elements;
end;
{$endif BrowserLog}
{ Write Browser Collections }
do_extractsymbolinfo{$ifdef FPC}(){$endif};
{$endif BrowserLog}
end;
end;
{$ifdef dummy}
if current_module.in_second_compile then
begin
current_module.in_second_compile:=false;
current_module.in_compile:=true;
end
else
current_module.in_compile:=false;
{$endif dummy}
end;
end;
dec(compile_level);
compiled_module:=olddata^.old_compiled_module;
dispose(olddata);
{$ifdef USEEXCEPT}
if longjump_used then
longjmp(recoverpospointer^,1);
{$endif USEEXCEPT}
end;
end;
end.
{
$Log$
Revision 1.70 2005-01-19 22:19:41 peter
Revision 1.71 2005-01-26 16:23:28 peter
* detect arithmetic overflows for constants at compile time
* use try..except instead of setjmp
Revision 1.70 2005/01/19 22:19:41 peter
* unit mapping rewrite
* new derefmap added

View File

@ -1,271 +0,0 @@
{
$Id$
Copyright (c) 1998-2002 by Florian Klaempfl
SetJmp and LongJmp implementation for recovery handling of the
compiler
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
****************************************************************************}
unit tpexcept;
{$i fpcdefs.inc}
interface
{$ifdef VER1_0}
{$define HASNOLONGJMP}
{$else}
{$ifdef DELPHI}
{$define HASNOLONGJMP}
{$endif}
{$endif}
{$ifndef UNIX}
{$S-}
{$endif}
{$ifdef HASNOLONGJMP}
type
jmp_buf = record
{$ifdef Delphi} { must preserve: ebx, esi, edi, ebp, esp, eip only }
_ebx,_esi,_edi,_ebp,_esp,_eip : longint;
{$else}
eax,ebx,ecx,edx,esi,edi,ebp,esp,eip,flags : longint;
cs,ds,es,fs,gs,ss : word;
{$endif Delphi}
end;
pjmp_buf = ^jmp_buf;
function setjmp(var rec : jmp_buf) : longint;{$ifndef ver1_0}oldfpccall;{$endif}
procedure longjmp(const rec : jmp_buf;return_value : longint);{$ifndef ver1_0}oldfpccall;{$endif}
{$endif HASNOLONGJMP}
const
recoverpospointer : pjmp_buf = nil;
longjump_used : boolean = false;
implementation
{$ifdef HASNOLONGJMP}
{*****************************************************************************
Exception Helpers
*****************************************************************************}
{$ifdef DELPHI}
{$STACKFRAMES ON}
function setjmp(var rec : jmp_buf) : longint; assembler;
{ [ebp+12]: [ebp+8]:@rec, [ebp+4]:eip', [ebp+0]:ebp' }
asm // free: eax, ecx, edx
{ push ebp; mov ebp,esp }
mov edx,rec
mov [edx].jmp_buf._ebx,ebx { ebx }
mov [edx].jmp_buf._esi,esi { esi }
mov [edx].jmp_buf._edi,edi { edi }
mov eax,[ebp] { ebp (caller stack frame) }
mov [edx].jmp_buf._ebp,eax
lea eax,[ebp+12] { esp [12]: [8]:@rec, [4]:eip, [0]:ebp }
mov [edx].jmp_buf._esp,eax
mov eax,[ebp+4]
mov [edx].jmp_buf._eip,eax
xor eax,eax
{ leave }
{ ret 4 }
end;
procedure longjmp(const rec : jmp_buf; return_value : longint);assembler;
{ [ebp+12]: return_value [ebp+8]:@rec, [ebp+4]:eip', [ebp+0]:ebp' }
asm
{ push ebp, mov ebp,esp }
mov edx,rec
mov ecx,return_value
mov ebx,[edx].jmp_buf._ebx { ebx }
mov esi,[edx].jmp_buf._esi { esi }
mov edi,[edx].jmp_buf._edi { edi }
mov ebp,[edx].jmp_buf._ebp { ebp }
mov esp,[edx].jmp_buf._esp { esp }
mov eax,[edx].jmp_buf._eip { eip }
push eax
mov eax,ecx
ret 0
end;
{$else not DELPHI}
{$asmmode ATT}
function setjmp(var rec : jmp_buf) : longint; {$ifndef ver1_0}oldfpccall;{$endif}
begin
asm
pushl %edi
movl rec,%edi
movl %eax,(%edi)
movl %ebx,4(%edi)
movl %ecx,8(%edi)
movl %edx,12(%edi)
movl %esi,16(%edi)
{ load edi }
movl -4(%ebp),%eax
{ ... and store it }
movl %eax,20(%edi)
{ ebp ... }
movl (%ebp),%eax
movl %eax,24(%edi)
{ esp ... }
leal 12(%ebp),%eax
movl %eax,28(%edi)
{ the return address }
movl 4(%ebp),%eax
movl %eax,32(%edi)
{ flags ... }
pushfl
popl 36(%edi)
{ !!!!! the segment registers, not yet needed }
{ you need them if the exception comes from
an interrupt or a seg_move }
movw %cs,40(%edi)
movw %ds,42(%edi)
movw %es,44(%edi)
movw %fs,46(%edi)
movw %gs,48(%edi)
movw %ss,50(%edi)
{ restore EDI }
pop %edi
{ we come from the initial call }
xorl %eax,%eax
leave
ret $4
end;
end;
procedure longjmp(const rec : jmp_buf;return_value : longint); {$ifndef ver1_0}oldfpccall;{$endif}
begin
asm
{ restore compiler shit }
popl %ebp
{ this is the address of rec }
movl 4(%esp),%edi
{ save return value }
movl 8(%esp),%eax
movl %eax,0(%edi)
{ !!!!! load segment registers }
movw 46(%edi),%fs
movw 48(%edi),%gs
{ ... and some other registers }
movl 4(%edi),%ebx
movl 8(%edi),%ecx
movl 12(%edi),%edx
movl 24(%edi),%ebp
{ !!!!! movw 50(%edi),%es }
movl 28(%edi),%esi
{ create a stack frame for the return }
subl $16,%esi
{
movzwl 42(%edi),%eax
!!!!! es
movl %eax,(%esi)
}
{ edi }
movl 20(%edi),%eax
{ !!!!! es }
movl %eax,(%esi)
{ esi }
movl 16(%edi),%eax
{ !!!!! es }
movl %eax,4(%esi)
{ eip }
movl 32(%edi),%eax
{ !!!!! es }
movl %eax,12(%esi)
{ !!!!! cs
movl 40(%edi),%eax
es
movl %eax,16(%esi)
}
{ load and store flags }
movl 36(%edi),%eax
{ !!!!!
es
}
movl %eax,8(%esi)
{ load return value }
movl 0(%edi),%eax
{ load old ES
!!!!! movw 44(%edi),%es
}
{ load stack
!!!!! movw 50(%edi),%ss }
movl %esi,%esp
{ !!!!
popl %ds
}
popl %edi
popl %esi
popfl
ret
end;
end;
{$endif DELPHI}
{$endif HASNOLONGJMP}
end.
{
$Log$
Revision 1.12 2004-10-15 09:14:17 mazen
- remove $IFDEF DELPHI and related code
- remove $IFDEF FPCPROCVAR and related code
Revision 1.11 2004/06/20 08:55:30 florian
* logs truncated
Revision 1.10 2004/02/12 16:00:39 peter
* don't use the local longjmp for 1.9.x
}