Add debugging option to detect illegal use of null pointers.
This adds debugging code to detect null pointer dereferences, as well as pointer arithmetic on null pointers (which is also undefined behavior, and can lead to later dereferences of the resulting pointers). Note that ORCA/Pascal can already detect null pointer dereferences as part of its more general range-checking code. This implementation for ORCA/C will report the same error as ORCA/Pascal ("Subrange exceeded"). However, it does not include any of the other forms of range checking that ORCA/Pascal does, and (unlike in ORCA/Pascal) it is controlled by a separate flag from stack overflow checking.
This commit is contained in:
parent
a32ddedc0c
commit
a6ef872513
|
@ -196,6 +196,15 @@
|
||||||
{ a SIZE bit value. Extra bits are dropped. }
|
{ a SIZE bit value. Extra bits are dropped. }
|
||||||
{ }
|
{ }
|
||||||
{ }
|
{ }
|
||||||
|
{ pc_ckp - check for null pointer }
|
||||||
|
{ }
|
||||||
|
{ Gen0(pc_ckp) }
|
||||||
|
{ Gen0(pc_ckn) }
|
||||||
|
{ }
|
||||||
|
{ Make sure a pointer value is not null. The pc_ckp form }
|
||||||
|
{ checks the value at tos; pc_ckn checks the value at tos-1. }
|
||||||
|
{ }
|
||||||
|
{ }
|
||||||
{ pc_cop - copy to a local variable }
|
{ pc_cop - copy to a local variable }
|
||||||
{ }
|
{ }
|
||||||
{ Gen2t(pc_cop, label, disp, type) }
|
{ Gen2t(pc_cop, label, disp, type) }
|
||||||
|
|
|
@ -134,6 +134,8 @@ opt[pc_sqr] := 'sqr';
|
||||||
opt[pc_wsr] := 'wsr';
|
opt[pc_wsr] := 'wsr';
|
||||||
opt[pc_rbo] := 'rbo';
|
opt[pc_rbo] := 'rbo';
|
||||||
opt[pc_rev] := 'rev';
|
opt[pc_rev] := 'rev';
|
||||||
|
opt[pc_ckp] := 'ckp';
|
||||||
|
opt[pc_ckn] := 'ckn';
|
||||||
end; {InitWriteCode}
|
end; {InitWriteCode}
|
||||||
|
|
||||||
|
|
||||||
|
@ -281,7 +283,7 @@ with code^ do
|
||||||
pc_bnt,pc_blx,pc_bnl,pc_ngi,pc_ngl,pc_ngr,pc_ixa,pc_mdl,
|
pc_bnt,pc_blx,pc_bnl,pc_ngi,pc_ngl,pc_ngr,pc_ixa,pc_mdl,
|
||||||
pc_udi,pc_udl,pc_bqr,pc_bqx,pc_baq,pc_bnq,pc_ngq,pc_adq,pc_sbq,
|
pc_udi,pc_udl,pc_bqr,pc_bqx,pc_baq,pc_bnq,pc_ngq,pc_adq,pc_sbq,
|
||||||
pc_mpq,pc_umq,pc_dvq,pc_udq,pc_mdq,pc_uqm,pc_slq,pc_sqr,pc_wsr,
|
pc_mpq,pc_umq,pc_dvq,pc_udq,pc_mdq,pc_uqm,pc_slq,pc_sqr,pc_wsr,
|
||||||
pc_rbo,pc_sll,pc_shr,pc_usr,pc_slr,pc_vsr: ;
|
pc_rbo,pc_sll,pc_shr,pc_usr,pc_slr,pc_vsr,pc_ckp,pc_ckn: ;
|
||||||
|
|
||||||
|
|
||||||
dc_prm:
|
dc_prm:
|
||||||
|
|
5
CGI.pas
5
CGI.pas
|
@ -254,7 +254,8 @@ type
|
||||||
pc_gli,pc_gdl,pc_gld,pc_cpi,pc_tri,pc_lbu,pc_lbf,pc_sbf,pc_cbf,dc_cns,
|
pc_gli,pc_gdl,pc_gld,pc_cpi,pc_tri,pc_lbu,pc_lbf,pc_sbf,pc_cbf,dc_cns,
|
||||||
dc_prm,pc_nat,pc_bno,pc_nop,pc_psh,pc_ili,pc_iil,pc_ild,pc_idl,
|
dc_prm,pc_nat,pc_bno,pc_nop,pc_psh,pc_ili,pc_iil,pc_ild,pc_idl,
|
||||||
pc_bqr,pc_bqx,pc_baq,pc_bnq,pc_ngq,pc_adq,pc_sbq,pc_mpq,pc_umq,pc_dvq,
|
pc_bqr,pc_bqx,pc_baq,pc_bnq,pc_ngq,pc_adq,pc_sbq,pc_mpq,pc_umq,pc_dvq,
|
||||||
pc_udq,pc_mdq,pc_uqm,pc_slq,pc_sqr,pc_wsr,pc_rbo,pc_fix,pc_rev);
|
pc_udq,pc_mdq,pc_uqm,pc_slq,pc_sqr,pc_wsr,pc_rbo,pc_fix,pc_rev,pc_ckp,
|
||||||
|
pc_ckn);
|
||||||
|
|
||||||
{intermediate code}
|
{intermediate code}
|
||||||
{-----------------}
|
{-----------------}
|
||||||
|
@ -333,6 +334,7 @@ var
|
||||||
{quality or characteristics of }
|
{quality or characteristics of }
|
||||||
{code }
|
{code }
|
||||||
{------------------------------}
|
{------------------------------}
|
||||||
|
checkNullPointers: boolean; {check for null pointer dereferences?}
|
||||||
checkStack: boolean; {check stack for stack errors?}
|
checkStack: boolean; {check stack for stack errors?}
|
||||||
cLineOptimize: boolean; {+o flag set?}
|
cLineOptimize: boolean; {+o flag set?}
|
||||||
code: icptr; {current intermediate code record}
|
code: icptr; {current intermediate code record}
|
||||||
|
@ -843,6 +845,7 @@ profileFlag := false; {don't generate profiling code}
|
||||||
debugFlag := false; {don't generate debug code}
|
debugFlag := false; {don't generate debug code}
|
||||||
debugStrFlag := false; {don't generate gsbug debug strings}
|
debugStrFlag := false; {don't generate gsbug debug strings}
|
||||||
traceBack := false; {don't generate traceback code}
|
traceBack := false; {don't generate traceback code}
|
||||||
|
checkNullPointers := false; {don't check null pointers}
|
||||||
volatile := false; {no volatile qualifiers found}
|
volatile := false; {no volatile qualifiers found}
|
||||||
|
|
||||||
registers := cLineOptimize; {don't do register optimizations}
|
registers := cLineOptimize; {don't do register optimizations}
|
||||||
|
|
15
DAG.pas
15
DAG.pas
|
@ -502,7 +502,7 @@ var
|
||||||
[pc_mov,pc_cbf,pc_cop,pc_cpi,pc_cpo,pc_gil,pc_gli,pc_gdl,
|
[pc_mov,pc_cbf,pc_cop,pc_cpi,pc_cpo,pc_gil,pc_gli,pc_gdl,
|
||||||
pc_gld,pc_iil,pc_ili,pc_idl,pc_ild,pc_lil,pc_lli,pc_ldl,
|
pc_gld,pc_iil,pc_ili,pc_idl,pc_ild,pc_lil,pc_lli,pc_ldl,
|
||||||
pc_lld,pc_sbf,pc_sro,pc_sto,pc_str,pc_cui,pc_cup,pc_tl1,
|
pc_lld,pc_sbf,pc_sro,pc_sto,pc_str,pc_cui,pc_cup,pc_tl1,
|
||||||
pc_fix] then
|
pc_fix,pc_ckp] then
|
||||||
SideEffects := true
|
SideEffects := true
|
||||||
else if op^.opcode = pc_ldc then
|
else if op^.opcode = pc_ldc then
|
||||||
SideEffects := false
|
SideEffects := false
|
||||||
|
@ -2817,7 +2817,7 @@ case op^.opcode of
|
||||||
pc_cnn, pc_cnv:
|
pc_cnn, pc_cnv:
|
||||||
TypeOf := baseTypeEnum(op^.q & $000F);
|
TypeOf := baseTypeEnum(op^.q & $000F);
|
||||||
|
|
||||||
pc_stk:
|
pc_stk, pc_ckp:
|
||||||
TypeOf := TypeOf(op^.left);
|
TypeOf := TypeOf(op^.left);
|
||||||
|
|
||||||
pc_bno:
|
pc_bno:
|
||||||
|
@ -5479,7 +5479,7 @@ case code^.opcode of
|
||||||
pc_bnt, pc_bnl, pc_cnv, pc_dec, pc_inc, pc_ind, pc_lbf, pc_lbu,
|
pc_bnt, pc_bnl, pc_cnv, pc_dec, pc_inc, pc_ind, pc_lbf, pc_lbu,
|
||||||
pc_ngi, pc_ngl, pc_ngr, pc_not, pc_stk, pc_cop, pc_cpo, pc_tl1,
|
pc_ngi, pc_ngl, pc_ngr, pc_not, pc_stk, pc_cop, pc_cpo, pc_tl1,
|
||||||
pc_sro, pc_str, pc_fjp, pc_tjp, pc_xjp, pc_cup, pc_pop, pc_iil,
|
pc_sro, pc_str, pc_fjp, pc_tjp, pc_xjp, pc_cup, pc_pop, pc_iil,
|
||||||
pc_ili, pc_idl, pc_ild, pc_bnq, pc_ngq, pc_rbo, pc_rev:
|
pc_ili, pc_idl, pc_ild, pc_bnq, pc_ngq, pc_rbo, pc_rev, pc_ckp:
|
||||||
begin
|
begin
|
||||||
code^.left := Pop;
|
code^.left := Pop;
|
||||||
Push(code);
|
Push(code);
|
||||||
|
@ -5514,6 +5514,15 @@ case code^.opcode of
|
||||||
Push(code);
|
Push(code);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
pc_ckn:
|
||||||
|
begin
|
||||||
|
code^.opcode := pc_ckp;
|
||||||
|
temp := Pop;
|
||||||
|
code^.left := Pop;
|
||||||
|
Push(code);
|
||||||
|
Push(temp);
|
||||||
|
end;
|
||||||
|
|
||||||
pc_cnn:
|
pc_cnn:
|
||||||
begin
|
begin
|
||||||
code^.opcode := pc_cnv;
|
code^.opcode := pc_cnv;
|
||||||
|
|
|
@ -2811,6 +2811,8 @@ procedure ChangePointer (op: pcodes; size: longint; tp: baseTypeEnum);
|
||||||
begin {ChangePointer}
|
begin {ChangePointer}
|
||||||
if size = 0 then
|
if size = 0 then
|
||||||
Error(122);
|
Error(122);
|
||||||
|
if checkNullPointers then
|
||||||
|
Gen0(pc_ckn);
|
||||||
case tp of
|
case tp of
|
||||||
cgByte,cgUByte,cgWord,cgUWord: begin
|
cgByte,cgUByte,cgWord,cgUWord: begin
|
||||||
if (size = long(size).lsw) and (op = pc_adl)
|
if (size = long(size).lsw) and (op = pc_adl)
|
||||||
|
@ -2937,7 +2939,7 @@ var
|
||||||
end; {ExpressionKind}
|
end; {ExpressionKind}
|
||||||
|
|
||||||
|
|
||||||
procedure LoadAddress (tree: tokenPtr);
|
procedure LoadAddress (tree: tokenPtr; nullCheck: boolean);
|
||||||
|
|
||||||
{ load the address of an l-value }
|
{ load the address of an l-value }
|
||||||
{ }
|
{ }
|
||||||
|
@ -2994,7 +2996,7 @@ var
|
||||||
{evaluate a compound literal and load its address}
|
{evaluate a compound literal and load its address}
|
||||||
AutoInit(tree^.id, 0, true);
|
AutoInit(tree^.id, 0, true);
|
||||||
tree^.token.kind := ident;
|
tree^.token.kind := ident;
|
||||||
LoadAddress(tree);
|
LoadAddress(tree, false);
|
||||||
tree^.token.kind := compoundliteral;
|
tree^.token.kind := compoundliteral;
|
||||||
Gen0t(pc_bno, cgULong);
|
Gen0t(pc_bno, cgULong);
|
||||||
end {if}
|
end {if}
|
||||||
|
@ -3002,6 +3004,8 @@ var
|
||||||
|
|
||||||
{load the address of the item pointed to by the pointer}
|
{load the address of the item pointed to by the pointer}
|
||||||
GenerateCode(tree^.left);
|
GenerateCode(tree^.left);
|
||||||
|
if nullCheck then
|
||||||
|
Gen0(pc_ckp);
|
||||||
isBitField := false;
|
isBitField := false;
|
||||||
if not (expressionType^.kind in [pointerType,arrayType,functionType]) then
|
if not (expressionType^.kind in [pointerType,arrayType,functionType]) then
|
||||||
Error(79);
|
Error(79);
|
||||||
|
@ -3009,7 +3013,7 @@ var
|
||||||
else if tree^.token.kind = dotch then begin
|
else if tree^.token.kind = dotch then begin
|
||||||
|
|
||||||
{load the address of a field of a record}
|
{load the address of a field of a record}
|
||||||
LoadAddress(tree^.left);
|
LoadAddress(tree^.left, nullCheck);
|
||||||
eType := expressionType;
|
eType := expressionType;
|
||||||
if eType^.kind in [arrayType,pointerType] then begin
|
if eType^.kind in [arrayType,pointerType] then begin
|
||||||
if eType^.kind = arrayType then
|
if eType^.kind = arrayType then
|
||||||
|
@ -3032,15 +3036,18 @@ var
|
||||||
else if tree^.token.kind = castoper then begin
|
else if tree^.token.kind = castoper then begin
|
||||||
|
|
||||||
{load the address of a field of a record}
|
{load the address of a field of a record}
|
||||||
LoadAddress(tree^.left);
|
LoadAddress(tree^.left, nullCheck);
|
||||||
expressionType := tree^.castType;
|
expressionType := tree^.castType;
|
||||||
if expressionType^.kind <> arrayType then
|
if expressionType^.kind <> arrayType then
|
||||||
expressionType := MakePointerTo(expressionType);
|
expressionType := MakePointerTo(expressionType);
|
||||||
end {else if}
|
end {else if}
|
||||||
|
|
||||||
else if ExpressionKind(tree) in [arrayType,pointerType,structType,unionType]
|
else if ExpressionKind(tree) in [arrayType,pointerType,structType,unionType]
|
||||||
then
|
then begin
|
||||||
GenerateCode(tree)
|
GenerateCode(tree);
|
||||||
|
if nullCheck then
|
||||||
|
Gen0(pc_ckp);
|
||||||
|
end {else if}
|
||||||
else begin
|
else begin
|
||||||
expressionType := intPtr; {set default type in case of error}
|
expressionType := intPtr; {set default type in case of error}
|
||||||
if doDispose then {prevent spurious errors}
|
if doDispose then {prevent spurious errors}
|
||||||
|
@ -3123,6 +3130,8 @@ var
|
||||||
end; {case}
|
end; {case}
|
||||||
|
|
||||||
pointerType,arrayType: begin
|
pointerType,arrayType: begin
|
||||||
|
if checkNullPointers then
|
||||||
|
Gen0(pc_ckp);
|
||||||
GenldcLong(expressionType^.pType^.size);
|
GenldcLong(expressionType^.pType^.size);
|
||||||
if inc then
|
if inc then
|
||||||
Gen0(pc_adl)
|
Gen0(pc_adl)
|
||||||
|
@ -3201,10 +3210,12 @@ var
|
||||||
lSize := iType^.pType^.size;
|
lSize := iType^.pType^.size;
|
||||||
if lSize = 0 then
|
if lSize = 0 then
|
||||||
Error(122);
|
Error(122);
|
||||||
if long(lSize).msw <> 0 then begin
|
if (long(lSize).msw <> 0) or checkNullPointers then begin
|
||||||
|
|
||||||
{handle inc/dec of >64K}
|
{handle inc/dec of >64K or with null pointer check}
|
||||||
LoadScalar(tree^.id);
|
LoadScalar(tree^.id);
|
||||||
|
if checkNullPointers then
|
||||||
|
Gen0(pc_ckp);
|
||||||
GenLdcLong(lSize);
|
GenLdcLong(lSize);
|
||||||
if pc_l in [pc_lli,pc_lil] then
|
if pc_l in [pc_lli,pc_lil] then
|
||||||
Gen0(pc_adl)
|
Gen0(pc_adl)
|
||||||
|
@ -3242,7 +3253,7 @@ var
|
||||||
else begin
|
else begin
|
||||||
|
|
||||||
{do an indirect ++ or --}
|
{do an indirect ++ or --}
|
||||||
LoadAddress(tree); {get the address to save to}
|
LoadAddress(tree, checkNullPointers); {get the address to save to}
|
||||||
if expressionType^.kind = arrayType then
|
if expressionType^.kind = arrayType then
|
||||||
expressionType := expressionType^.aType
|
expressionType := expressionType^.aType
|
||||||
else if expressionType^.kind = pointerType then
|
else if expressionType^.kind = pointerType then
|
||||||
|
@ -3508,7 +3519,9 @@ var
|
||||||
if (ftype^.toolNum = 0) and (ftype^.dispatcher = 0) then begin
|
if (ftype^.toolNum = 0) and (ftype^.dispatcher = 0) then begin
|
||||||
if indirect then begin
|
if indirect then begin
|
||||||
fntype := expressionType;
|
fntype := expressionType;
|
||||||
GenerateCode(ftree);
|
GenerateCode(ftree);
|
||||||
|
if checkNullPointers then
|
||||||
|
Gen0(pc_ckp);
|
||||||
expressionType := fntype;
|
expressionType := fntype;
|
||||||
Gen1t(pc_cui, ord(hasVarargs and strictVararg),
|
Gen1t(pc_cui, ord(hasVarargs and strictVararg),
|
||||||
UsualUnaryConversions);
|
UsualUnaryConversions);
|
||||||
|
@ -3683,15 +3696,15 @@ case tree^.token.kind of
|
||||||
|
|
||||||
|
|
||||||
arrayType: begin
|
arrayType: begin
|
||||||
LoadAddress(tree);
|
LoadAddress(tree, false);
|
||||||
expressionType := expressionType^.ptype;
|
expressionType := expressionType^.ptype;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
functionType:
|
functionType:
|
||||||
LoadAddress(tree);
|
LoadAddress(tree, false);
|
||||||
|
|
||||||
structType, unionType: begin
|
structType, unionType: begin
|
||||||
LoadAddress(tree);
|
LoadAddress(tree, false);
|
||||||
if expressionType^.kind = pointerType then
|
if expressionType^.kind = pointerType then
|
||||||
expressionType := expressionType^.ptype;
|
expressionType := expressionType^.ptype;
|
||||||
CheckForIncompleteStructType;
|
CheckForIncompleteStructType;
|
||||||
|
@ -3817,7 +3830,7 @@ case tree^.token.kind of
|
||||||
end; {with}
|
end; {with}
|
||||||
end {if}
|
end {if}
|
||||||
else begin
|
else begin
|
||||||
LoadAddress(tree^.left);
|
LoadAddress(tree^.left, checkNullPointers);
|
||||||
lType := expressionType;
|
lType := expressionType;
|
||||||
lisBitField := isBitField;
|
lisBitField := isBitField;
|
||||||
lbitDisp := bitDisp;
|
lbitDisp := bitDisp;
|
||||||
|
@ -3874,7 +3887,7 @@ case tree^.token.kind of
|
||||||
end {if}
|
end {if}
|
||||||
else begin
|
else begin
|
||||||
doingScalar := false;
|
doingScalar := false;
|
||||||
LoadAddress(tree^.left);
|
LoadAddress(tree^.left, checkNullPointers);
|
||||||
lisBitField := isBitField;
|
lisBitField := isBitField;
|
||||||
lbitDisp := bitDisp;
|
lbitDisp := bitDisp;
|
||||||
lbitSize := bitSize;
|
lbitSize := bitSize;
|
||||||
|
@ -4388,6 +4401,10 @@ case tree^.token.kind of
|
||||||
{NOTE: assumes aType & pType overlap in typeRecord}
|
{NOTE: assumes aType & pType overlap in typeRecord}
|
||||||
else if not CompTypes(lType^.aType, expressionType^.aType) then
|
else if not CompTypes(lType^.aType, expressionType^.aType) then
|
||||||
Error(47);
|
Error(47);
|
||||||
|
if checkNullPointers then begin
|
||||||
|
Gen0(pc_ckn);
|
||||||
|
Gen0(pc_ckp);
|
||||||
|
end; {if}
|
||||||
Gen0(pc_sbl);
|
Gen0(pc_sbl);
|
||||||
if size <> 1 then begin
|
if size <> 1 then begin
|
||||||
GenLdcLong(size);
|
GenLdcLong(size);
|
||||||
|
@ -4629,7 +4646,7 @@ case tree^.token.kind of
|
||||||
if not (tree^.left^.token.kind in
|
if not (tree^.left^.token.kind in
|
||||||
[ident,compoundliteral,stringconst,uasterisk]) then
|
[ident,compoundliteral,stringconst,uasterisk]) then
|
||||||
L_Value(tree^.left);
|
L_Value(tree^.left);
|
||||||
LoadAddress(tree^.left);
|
LoadAddress(tree^.left, false);
|
||||||
if tree^.left^.token.kind = stringconst then begin
|
if tree^.left^.token.kind = stringconst then begin
|
||||||
{build pointer-to-array type for address of string constant}
|
{build pointer-to-array type for address of string constant}
|
||||||
tType := pointer(Malloc(sizeof(typeRecord)));
|
tType := pointer(Malloc(sizeof(typeRecord)));
|
||||||
|
@ -4653,6 +4670,9 @@ case tree^.token.kind of
|
||||||
lType := lType^.pType;
|
lType := lType^.pType;
|
||||||
expressionType := lType;
|
expressionType := lType;
|
||||||
isVolatile := tqVolatile in lType^.qualifiers;
|
isVolatile := tqVolatile in lType^.qualifiers;
|
||||||
|
if checkNullPointers then
|
||||||
|
if lType^.kind <> functionType then
|
||||||
|
Gen0(pc_ckp);
|
||||||
if lType^.kind = scalarType then
|
if lType^.kind = scalarType then
|
||||||
if lType^.baseType = cgVoid then
|
if lType^.baseType = cgVoid then
|
||||||
Gen2(pc_cnv, cgULong, cgVoid)
|
Gen2(pc_cnv, cgULong, cgVoid)
|
||||||
|
@ -4673,7 +4693,7 @@ case tree^.token.kind of
|
||||||
end; {case uasterisk}
|
end; {case uasterisk}
|
||||||
|
|
||||||
dotch: begin {.}
|
dotch: begin {.}
|
||||||
LoadAddress(tree^.left);
|
LoadAddress(tree^.left, checkNullPointers);
|
||||||
lType := expressionType;
|
lType := expressionType;
|
||||||
if lType^.kind in [arrayType,pointerType,structType,unionType] then begin
|
if lType^.kind in [arrayType,pointerType,structType,unionType] then begin
|
||||||
if lType^.kind = arrayType then
|
if lType^.kind = arrayType then
|
||||||
|
|
19
Gen.pas
19
Gen.pas
|
@ -999,6 +999,24 @@ else {if op^.opcode = pc_sbq then} begin
|
||||||
end; {GenAdqSbq}
|
end; {GenAdqSbq}
|
||||||
|
|
||||||
|
|
||||||
|
procedure GenCkp (op: icptr);
|
||||||
|
|
||||||
|
{ generate code for pc_ckp }
|
||||||
|
{ }
|
||||||
|
{ parameters: }
|
||||||
|
{ op - pc_ckp operation }
|
||||||
|
|
||||||
|
begin {GenCkp}
|
||||||
|
if op^.left^.opcode in [pc_lda,pc_lad,pc_lca,pc_lao] then
|
||||||
|
GenTree(op^.left)
|
||||||
|
else begin
|
||||||
|
gLong.preference := onStack;
|
||||||
|
GenTree(op^.left);
|
||||||
|
GenCall(98);
|
||||||
|
end; {else}
|
||||||
|
end; {GenCkp}
|
||||||
|
|
||||||
|
|
||||||
procedure GenCmp (op: icptr; rOpcode: pcodes; lb: integer);
|
procedure GenCmp (op: icptr; rOpcode: pcodes; lb: integer);
|
||||||
|
|
||||||
{ generate code for pc_les, pc_leq, pc_grt or pc_geq }
|
{ generate code for pc_les, pc_leq, pc_grt or pc_geq }
|
||||||
|
@ -7494,6 +7512,7 @@ case op^.opcode of
|
||||||
pc_bnq,pc_ngq: GenUnaryQuad(op);
|
pc_bnq,pc_ngq: GenUnaryQuad(op);
|
||||||
pc_bno: GenBno(op);
|
pc_bno: GenBno(op);
|
||||||
pc_bnt,pc_ngi,pc_not: GenBntNgiNot(op);
|
pc_bnt,pc_ngi,pc_not: GenBntNgiNot(op);
|
||||||
|
pc_ckp: GenCkp(op);
|
||||||
pc_cnv: GenCnv(op);
|
pc_cnv: GenCnv(op);
|
||||||
pc_cui: GenCui(op);
|
pc_cui: GenCui(op);
|
||||||
pc_cup: GenCup(op);
|
pc_cup: GenCup(op);
|
||||||
|
|
|
@ -18,7 +18,7 @@ uses CCommon, MM, Scanner, Symbol, CGI;
|
||||||
{$segment 'HEADER'}
|
{$segment 'HEADER'}
|
||||||
|
|
||||||
const
|
const
|
||||||
symFileVersion = 37; {version number of .sym file format}
|
symFileVersion = 38; {version number of .sym file format}
|
||||||
|
|
||||||
var
|
var
|
||||||
inhibitHeader: boolean; {should .sym includes be blocked?}
|
inhibitHeader: boolean; {should .sym includes be blocked?}
|
||||||
|
@ -827,6 +827,7 @@ procedure EndInclude {chPtr: ptr};
|
||||||
| (ord(profileFlag) << 2)
|
| (ord(profileFlag) << 2)
|
||||||
| (ord(traceBack) << 3)
|
| (ord(traceBack) << 3)
|
||||||
| (ord(checkStack) << 4)
|
| (ord(checkStack) << 4)
|
||||||
|
| (ord(checkNullPointers) << 5)
|
||||||
| (ord(debugStrFlag) << 15));
|
| (ord(debugStrFlag) << 15));
|
||||||
|
|
||||||
p_lint: begin
|
p_lint: begin
|
||||||
|
@ -1496,6 +1497,7 @@ var
|
||||||
profileFlag := odd(val >> 2);
|
profileFlag := odd(val >> 2);
|
||||||
traceback := odd(val >> 3);
|
traceback := odd(val >> 3);
|
||||||
checkStack := odd(val >> 4);
|
checkStack := odd(val >> 4);
|
||||||
|
checkNullPointers := odd(val >> 5);
|
||||||
debugStrFlag := odd(val >> 15);
|
debugStrFlag := odd(val >> 15);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
|
@ -2274,6 +2274,7 @@ case callNum of
|
||||||
95: sp := @'~REALFIX';
|
95: sp := @'~REALFIX';
|
||||||
96: sp := @'~DOUBLEFIX';
|
96: sp := @'~DOUBLEFIX';
|
||||||
97: sp := @'~COMPFIX';
|
97: sp := @'~COMPFIX';
|
||||||
|
98: sp := @'~CHECKPTRC';
|
||||||
otherwise:
|
otherwise:
|
||||||
Error(cge1);
|
Error(cge1);
|
||||||
end; {case}
|
end; {case}
|
||||||
|
|
|
@ -3491,6 +3491,7 @@ if ch in ['a','d','e','i','l','p','u','w'] then begin
|
||||||
{ 4 - generate profiles }
|
{ 4 - generate profiles }
|
||||||
{ 8 - generate traceback code }
|
{ 8 - generate traceback code }
|
||||||
{ 16 - check for stack errors }
|
{ 16 - check for stack errors }
|
||||||
|
{ 32 - check for null pointer dereferences }
|
||||||
{ 32768 - generate inline function names }
|
{ 32768 - generate inline function names }
|
||||||
FlagPragmas(p_debug);
|
FlagPragmas(p_debug);
|
||||||
NumericDirective;
|
NumericDirective;
|
||||||
|
@ -3503,6 +3504,7 @@ if ch in ['a','d','e','i','l','p','u','w'] then begin
|
||||||
profileFlag := odd(val >> 2);
|
profileFlag := odd(val >> 2);
|
||||||
traceBack := odd(val >> 3);
|
traceBack := odd(val >> 3);
|
||||||
checkStack := odd(val >> 4);
|
checkStack := odd(val >> 4);
|
||||||
|
checkNullPointers := odd(val >> 5);
|
||||||
debugStrFlag := odd(val >> 15);
|
debugStrFlag := odd(val >> 15);
|
||||||
profileFlag := profileFlag or debugFlag;
|
profileFlag := profileFlag or debugFlag;
|
||||||
if token.kind <> eolsy then
|
if token.kind <> eolsy then
|
||||||
|
|
22
cc.notes
22
cc.notes
|
@ -16,8 +16,8 @@ Updated by Stephen Heumann and Kelvin Sherlock, 2017-2023
|
||||||
|
|
||||||
5. Certain errors that were previously ignored are now detected.
|
5. Certain errors that were previously ignored are now detected.
|
||||||
|
|
||||||
6. New option added to generate inline function names for use with
|
6. Two new #pragma debug bits are defined. See "Additions to
|
||||||
assembly-level debugging tools. See "Inline Function Names."
|
#pragma debug."
|
||||||
|
|
||||||
7. Some new headers specified by recent C standards are added.
|
7. Some new headers specified by recent C standards are added.
|
||||||
See "New Headers."
|
See "New Headers."
|
||||||
|
@ -185,7 +185,7 @@ ORCA/C now supports several standard pragmas of the form "#pragma STDC ...", as
|
||||||
|
|
||||||
p. 256
|
p. 256
|
||||||
|
|
||||||
The #pragma debug directive supports a new bit. If bit 15 is set, ORCA/C generates inline function names for use with assembly-level debugging tools. See "Inline Function Names," below.
|
The #pragma debug directive supports two new bits. If bit 5 is set, ORCA/C generates code to check for illegal use of null pointers. If bit 15 is set, ORCA/C generates inline function names for use with assembly-level debugging tools. See "Additions to #pragma debug," below.
|
||||||
|
|
||||||
p. 257
|
p. 257
|
||||||
|
|
||||||
|
@ -700,14 +700,20 @@ Note that _Generic expressions always use the stricter type compatibility rules
|
||||||
(Mike Westerfield, Kelvin Sherlock, Stephen Heumann)
|
(Mike Westerfield, Kelvin Sherlock, Stephen Heumann)
|
||||||
|
|
||||||
|
|
||||||
Inline Function Names
|
Additions to #pragma debug
|
||||||
---------------------
|
--------------------------
|
||||||
|
|
||||||
ORCA/C now supports recording the names of functions using the inline name format documented in Apple IIGS Technical Note #103. This allows assembly-level debugging tools such as GSBug and Nifty List to display the names of functions in an ORCA/C program while debugging it. To enable generation of inline function names, set #pragma debug bit 15 (a value of 0x8000).
|
Two new debugging features can now be enabled with #pragma debug:
|
||||||
|
|
||||||
Note that inline function names are unrelated to the other types of debug code that ORCA/C can generate. In particular, inline function names are not needed for source-level debugging using the desktop development environment or other compatible source-level debuggers, although it is possible to enable both types of debugging information at the same time.
|
* Checking for illegal use of null pointers:
|
||||||
|
|
||||||
(Kelvin Sherlock)
|
Setting #pragma debug bit 5 (a value of 32) turns on checking for illegal use of null pointers. If this bit is set, ORCA/C will detect when your program would dereference a null pointer or when it would do pointer arithmetic on a null pointer. A "Subrange exceeded" error will be reported in these cases.
|
||||||
|
|
||||||
|
* Inline function names:
|
||||||
|
|
||||||
|
Setting #pragma debug bit 15 (a value of 0x8000) causes ORCA/C to record the names of functions using the inline name format documented in Apple IIGS Technical Note #103. This allows assembly-level debugging tools such as GSBug and Nifty List to display the names of functions in an ORCA/C program while debugging it. Note that inline function names are unrelated to the other types of debug code that ORCA/C can generate. In particular, inline function names are not needed for source-level debugging using the desktop development environment or other compatible source-level debuggers, although it is possible to enable both types of debugging information at the same time.
|
||||||
|
|
||||||
|
(Stephen Heumann, Kelvin Sherlock)
|
||||||
|
|
||||||
|
|
||||||
Enhancements to #pragma lint
|
Enhancements to #pragma lint
|
||||||
|
|
Loading…
Reference in New Issue