* 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);
OldSigInt:={$ifdef havelinuxrtl10}Signal{$else}{$ifdef Unix}fpSignal{$else}Signal{$endif}{$endif} (SIGINT,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,83 +356,80 @@ 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 }
InitCompiler(cmd);
try
try
{ Initialize the compiler }
InitCompiler(cmd);
{ 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);
Message1(general_t_exepath,exepath);
WritePathList(general_t_unitpath,unitsearchpath);
WritePathList(general_t_includepath,includesearchpath);
WritePathList(general_t_librarypath,librarysearchpath);
WritePathList(general_t_objectpath,objectsearchpath);
{ 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);
Message1(general_t_exepath,exepath);
WritePathList(general_t_unitpath,unitsearchpath);
WritePathList(general_t_includepath,includesearchpath);
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}
if parapreprocess then
parser.preprocess(inputdir+inputfile+inputextension)
else
{$endif PREPROCWRITE}
parser.compile(inputdir+inputfile+inputextension);
if status.errorcount=0 then
begin
starttime:=getrealtime-starttime;
if starttime<0 then
starttime:=starttime+3600.0*24.0;
Message2(general_i_abslines_compiled,tostr(status.compiledlines),tostr(trunc(starttime))+
'.'+tostr(trunc(frac(starttime)*10)));
end;
{$ifdef USEEXCEPT}
end;
{$endif USEEXCEPT}
starttime:=getrealtime;
{ 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 !! }
DoneCompiler;
{ Compile the program }
{$ifdef PREPROCWRITE}
if parapreprocess then
parser.preprocess(inputdir+inputfile+inputextension)
else
{$endif PREPROCWRITE}
parser.compile(inputdir+inputfile+inputextension);
{ Set the return value if an error has occurred }
if status.errorcount=0 then
Compile:=0
else
Compile:=1;
{ Show statistics }
if status.errorcount=0 then
begin
starttime:=getrealtime-starttime;
if starttime<0 then
starttime:=starttime+3600.0*24.0;
Message2(general_i_abslines_compiled,tostr(status.compiledlines),tostr(trunc(starttime))+
'.'+tostr(trunc(frac(starttime)*10)));
end;
finally
{ no message possible after this !! }
DoneCompiler;
end;
except
DoneVerbose;
Message(general_e_compilation_aborted);
DoneVerbose;
Raise;
end;
{$ifdef SHOWUSEDMEM}
{$ifdef HASGETHEAPSTATUS}
GetHeapStatus(hstatus);
Writeln('Max Memory used/heapsize: ',DStr(hstatus.MaxHeapUsed shr 10),'/',DStr(hstatus.MaxHeapSize shr 10),' Kb');
GetHeapStatus(hstatus);
Writeln('Max Memory used/heapsize: ',DStr(hstatus.MaxHeapUsed shr 10),'/',DStr(hstatus.MaxHeapSize shr 10),' Kb');
{$else HASGETHEAPSTATUS}
Writeln('Memory used (heapsize): ',DStr(system.Heapsize shr 10),' Kb');
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
@ -2315,7 +2318,7 @@ S*2Tlinux_Linux
**2*_l : Show linenumbers r : Rhide/GCC compatibility mode
**2*_a : Show everything x : Executable info (Win32 only)
**2*_v : write fpcdebug.txt with p : Write tree.log with parse tree
**2*_ lots of debugging info
**2*_ lots of debugging info
3*1W<x>_Win32-like target options
3*2WB<x>_Set Image base to Hexadecimal <x> value
3*2WC_Specify console type application

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,24 +319,81 @@ implementation
lv := lv * tpointerdef(right.resulttype.def).pointertype.def.size;
case nodetype of
addn :
if (lt <> pointerconstn) then
t := genintconstnode(lv+rv)
else
t := cpointerconstnode.create(lv+rv,left.resulttype);
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 :
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)
else if (lt <> pointerconstn) or (rt = pointerconstn) then
t := genintconstnode(lv-rv)
else
t := cpointerconstnode.create(lv-rv,left.resulttype);
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)
else if (lt <> pointerconstn) or (rt = 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;
muln :
if (torddef(ld).typ <> u64bit) or
(torddef(rd).typ <> u64bit) then
t:=genintconstnode(lv*rv)
else
t:=genintconstnode(int64(qword(lv)*qword(rv)));
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,191 +509,161 @@ 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}
if (token=_UNIT) or (compile_level>1) then
begin
current_module.is_unit:=true;
proc_unit;
end
else
proc_program(token=_LIBRARY);
{$ifdef USEEXCEPT}
recoverpospointer:=oldrecoverpos;
end
else
begin
recoverpospointer:=oldrecoverpos;
longjump_used:=true;
end;
{$endif USEEXCEPT}
{ restore old state }
done_module;
if assigned(current_module) then
begin
{ module is now compiled }
tppumodule(current_module).state:=ms_compiled;
{ free ppu }
if assigned(tppumodule(current_module).ppufile) then
try
if (token=_UNIT) or (compile_level>1) then
begin
tppumodule(current_module).ppufile.free;
tppumodule(current_module).ppufile:=nil;
end;
current_module.is_unit:=true;
proc_unit;
end
else
proc_program(token=_LIBRARY);
finally
{ restore old state }
done_module;
{ free scanner }
if assigned(current_module.scanner) then
begin
if current_scanner=tscannerfile(current_module.scanner) then
current_scanner:=nil;
tscannerfile(current_module.scanner).free;
current_module.scanner:=nil;
end;
end;
if assigned(current_module) then
begin
{ module is now compiled }
tppumodule(current_module).state:=ms_compiled;
if (compile_level>1) then
begin
with olddata^ do
{ free ppu }
if assigned(tppumodule(current_module).ppufile) then
begin
{ restore scanner }
c:=oldc;
pattern:=oldpattern;
orgpattern:=oldorgpattern;
token:=oldtoken;
idtoken:=oldidtoken;
akttokenpos:=oldtokenpos;
block_type:=old_block_type;
{ restore cg }
parse_only:=oldparse_only;
{ restore asmlists }
exprasmlist:=oldexprasmlist;
datasegment:=olddatasegment;
bsssegment:=oldbsssegment;
codesegment:=oldcodesegment;
consts:=oldconsts;
debuglist:=olddebuglist;
withdebuglist:=oldwithdebuglist;
importssection:=oldimports;
exportssection:=oldexports;
resourcesection:=oldresource;
rttilist:=oldrttilist;
picdata:=oldpicdata;
resourcestringlist:=oldresourcestringlist;
{ object data }
ResourceStrings:=OldResourceStrings;
objectlibrary:=oldobjectlibrary;
{ restore previous scanner }
if assigned(old_compiled_module) then
current_scanner:=tscannerfile(old_compiled_module.scanner)
else
current_scanner:=nil;
if assigned(current_scanner) then
parser_current_file:=current_scanner.inputfile.name^;
{ restore symtable state }
refsymtable:=oldrefsymtable;
symtablestack:=oldsymtablestack;
macrosymtablestack:=oldmacrosymtablestack;
defaultsymtablestack:=olddefaultsymtablestack;
defaultmacrosymtablestack:=olddefaultmacrosymtablestack;
aktdefproccall:=oldaktdefproccall;
current_procinfo:=oldcurrent_procinfo;
aktsourcecodepage:=oldsourcecodepage;
aktlocalswitches:=oldaktlocalswitches;
aktmoduleswitches:=oldaktmoduleswitches;
aktalignment:=oldaktalignment;
aktpackenum:=oldaktpackenum;
aktpackrecords:=oldaktpackrecords;
aktmaxfpuregisters:=oldaktmaxfpuregisters;
aktoutputformat:=oldaktoutputformat;
set_target_asm(aktoutputformat);
aktoptprocessor:=oldaktoptprocessor;
aktspecificoptprocessor:=oldaktspecificoptprocessor;
aktfputype:=oldaktfputype;
aktasmmode:=oldaktasmmode;
aktinterfacetype:=oldaktinterfacetype;
aktfilepos:=oldaktfilepos;
aktmodeswitches:=oldaktmodeswitches;
aktexceptblock:=0;
exceptblockcounter:=0;
{$ifdef GDB}
dbx_counter:=store_dbx;
{$endif GDB}
tppumodule(current_module).ppufile.free;
tppumodule(current_module).ppufile:=nil;
end;
end
else
begin
parser_current_file:='';
{ Shut down things when the last file is compiled }
if (compile_level=1) then
begin
{ Close script }
if (not AsmRes.Empty) then
begin
Message1(exec_i_closing_script,AsmRes.Fn);
AsmRes.WriteToDisk;
end;
{$ifdef USEEXCEPT}
if not longjump_used then
{$endif USEEXCEPT}
{ free scanner }
if assigned(current_module.scanner) then
begin
if current_scanner=tscannerfile(current_module.scanner) then
current_scanner:=nil;
tscannerfile(current_module.scanner).free;
current_module.scanner:=nil;
end;
end;
if (compile_level>1) then
begin
with olddata^ do
begin
{ do not create browsers on errors !! }
if status.errorcount=0 then
begin
{ restore scanner }
c:=oldc;
pattern:=oldpattern;
orgpattern:=oldorgpattern;
token:=oldtoken;
idtoken:=oldidtoken;
akttokenpos:=oldtokenpos;
block_type:=old_block_type;
{ restore cg }
parse_only:=oldparse_only;
{ restore asmlists }
exprasmlist:=oldexprasmlist;
datasegment:=olddatasegment;
bsssegment:=oldbsssegment;
codesegment:=oldcodesegment;
consts:=oldconsts;
debuglist:=olddebuglist;
withdebuglist:=oldwithdebuglist;
importssection:=oldimports;
exportssection:=oldexports;
resourcesection:=oldresource;
rttilist:=oldrttilist;
picdata:=oldpicdata;
resourcestringlist:=oldresourcestringlist;
{ object data }
ResourceStrings:=OldResourceStrings;
objectlibrary:=oldobjectlibrary;
{ restore previous scanner }
if assigned(old_compiled_module) then
current_scanner:=tscannerfile(old_compiled_module.scanner)
else
current_scanner:=nil;
if assigned(current_scanner) then
parser_current_file:=current_scanner.inputfile.name^;
{ restore symtable state }
refsymtable:=oldrefsymtable;
symtablestack:=oldsymtablestack;
macrosymtablestack:=oldmacrosymtablestack;
defaultsymtablestack:=olddefaultsymtablestack;
defaultmacrosymtablestack:=olddefaultmacrosymtablestack;
aktdefproccall:=oldaktdefproccall;
current_procinfo:=oldcurrent_procinfo;
aktsourcecodepage:=oldsourcecodepage;
aktlocalswitches:=oldaktlocalswitches;
aktmoduleswitches:=oldaktmoduleswitches;
aktalignment:=oldaktalignment;
aktpackenum:=oldaktpackenum;
aktpackrecords:=oldaktpackrecords;
aktmaxfpuregisters:=oldaktmaxfpuregisters;
aktoutputformat:=oldaktoutputformat;
set_target_asm(aktoutputformat);
aktoptprocessor:=oldaktoptprocessor;
aktspecificoptprocessor:=oldaktspecificoptprocessor;
aktfputype:=oldaktfputype;
aktasmmode:=oldaktasmmode;
aktinterfacetype:=oldaktinterfacetype;
aktfilepos:=oldaktfilepos;
aktmodeswitches:=oldaktmodeswitches;
aktexceptblock:=0;
exceptblockcounter:=0;
{$ifdef GDB}
dbx_counter:=store_dbx;
{$endif GDB}
end;
end
else
begin
{ 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
Message1(exec_i_closing_script,AsmRes.Fn);
AsmRes.WriteToDisk;
end;
{ do not create browsers on errors !! }
if status.errorcount=0 then
begin
{$ifdef BrowserLog}
{ Write Browser Log }
if (cs_browser_log in aktglobalswitches) and
(cs_browser in aktmoduleswitches) then
begin
if browserlog.elements_to_list.empty then
begin
Message1(parser_i_writing_browser_log,browserlog.Fname);
WriteBrowserLog;
end
else
browserlog.list_elements;
end;
{ Write Browser Log }
if (cs_browser_log in aktglobalswitches) and
(cs_browser in aktmoduleswitches) then
begin
if browserlog.elements_to_list.empty then
begin
Message1(parser_i_writing_browser_log,browserlog.Fname);
WriteBrowserLog;
end
else
browserlog.list_elements;
end;
{ Write Browser Collections }
do_extractsymbolinfo{$ifdef FPC}(){$endif};
{$endif BrowserLog}
end;
end;
end;
{ Write Browser Collections }
do_extractsymbolinfo{$ifdef FPC}(){$endif};
end;
end;
dec(compile_level);
compiled_module:=olddata^.old_compiled_module;
{$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;
dispose(olddata);
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
}