* guarantee the order of parameter pushes again after r31201 on platforms

that don't use a fixed stack (mantis #28454)
   o moved the code to finalise managed out parameters from ncgcal to ncal,
     and add it to the init code of the call node (so it's evaluated before
     any parameters are processed, ensuring that mantis #28390 stays fixed)

git-svn-id: trunk@31328 -
This commit is contained in:
Jonas Maebe 2015-08-16 12:47:09 +00:00
parent c95a3f2cf7
commit e06181749c
5 changed files with 99 additions and 37 deletions

1
.gitattributes vendored
View File

@ -14680,6 +14680,7 @@ tests/webtbs/tw2834.pp svneol=native#text/plain
tests/webtbs/tw28372.pp svneol=native#text/plain
tests/webtbs/tw2841.pp svneol=native#text/plain
tests/webtbs/tw28442.pp svneol=native#text/pascal
tests/webtbs/tw28454.pp svneol=native#text/plain
tests/webtbs/tw28475.pp svneol=native#text/plain
tests/webtbs/tw2853.pp svneol=native#text/plain
tests/webtbs/tw2853a.pp svneol=native#text/plain

View File

@ -171,6 +171,9 @@ implementation
implicitptrpara,
verifyout: boolean;
begin
{ the original version doesn't do anything for garbage collected
platforms, but who knows in the future }
inherited;
{ implicit pointer types are already pointers -> no need to stuff them
in an array to pass them by reference (except in case of a formal
parameter, in which case everything is passed in an array since the

View File

@ -216,7 +216,7 @@ interface
finalization code }
fparainit,
fparacopyback: tnode;
procedure handlemanagedbyrefpara(orgparadef: tdef);virtual;abstract;
procedure handlemanagedbyrefpara(orgparadef: tdef);virtual;
{ on some targets, value parameters that are passed by reference must
be copied to a temp location by the caller (and then a reference to
this temp location must be passed) }
@ -612,6 +612,61 @@ implementation
TCALLPARANODE
****************************************************************************}
procedure tcallparanode.handlemanagedbyrefpara(orgparadef: tdef);
var
temp: ttempcreatenode;
npara: tcallparanode;
paraaddrtype: tdef;
begin
{ release memory for reference counted out parameters }
if (parasym.varspez=vs_out) and
is_managed_type(orgparadef) and
(not is_open_array(resultdef) or
is_managed_type(orgparadef)) and
not(target_info.system in systems_garbage_collected_managed_types) then
begin
paraaddrtype:=cpointerdef.getreusable(orgparadef);
{ create temp with address of the parameter }
temp:=ctempcreatenode.create(
paraaddrtype,paraaddrtype.size,tt_persistent,true);
{ put this code in the init/done statement of the call node, because
we should finalize all out parameters before other parameters
are evaluated (in case e.g. a managed out parameter is also
passed by value, we must not pass the pointer to the now possibly
freed data as the value parameter, but the finalized/nil value }
aktcallnode.add_init_statement(temp);
aktcallnode.add_init_statement(
cassignmentnode.create(
ctemprefnode.create(temp),
caddrnode.create(left)));
if not is_open_array(resultdef) or
not is_managed_type(tarraydef(resultdef).elementdef) then
{ finalize the entire parameter }
aktcallnode.add_init_statement(
cnodeutils.finalize_data_node(
cderefnode.create(ctemprefnode.create(temp))))
else
begin
{ passing a (part of, in case of slice) dynamic array as an
open array -> finalize the dynamic array contents, not the
dynamic array itself }
npara:=ccallparanode.create(
{ array length = high + 1 }
caddnode.create(addn,third.getcopy,genintconstnode(1)),
ccallparanode.create(caddrnode.create_internal
(crttinode.create(tstoreddef(tarraydef(resultdef).elementdef),initrtti,rdt_normal)),
ccallparanode.create(caddrnode.create_internal(
cderefnode.create(ctemprefnode.create(temp))),nil)));
aktcallnode.add_init_statement(
ccallnode.createintern('fpc_finalize_array',npara));
end;
left:=cderefnode.create(ctemprefnode.create(temp));
firstpass(left);
aktcallnode.add_done_statement(ctempdeletenode.create(temp));
end;
end;
procedure tcallparanode.copy_value_by_ref_para;
var
initstat,
@ -945,7 +1000,6 @@ implementation
get_paratype;
if assigned(parasym) and
(target_info.system in systems_managed_vm) and
(parasym.varspez in [vs_var,vs_out,vs_constref]) and
(parasym.vardef.typ<>formaldef) and
{ for record constructors }
@ -3803,18 +3857,8 @@ implementation
them from keeping on chasing eachother's tail }
while assigned(hp) do
begin
{ ensure that out parameters are finalised before other
parameters are processed, so that in case it has a reference
count of one and is also passed as a value parameter, the
value parameter does not get passed a pointer to a freed
memory block }
if (hpcurr.parasym.varspez=vs_out) and
is_managed_type(hpcurr.parasym.vardef) then
break;
if paramanager.use_fixed_stack and
hpcurr.contains_stack_tainting_call_cached and
not((hp.parasym.varspez=vs_out) and
is_managed_type(hp.parasym.vardef)) then
hpcurr.contains_stack_tainting_call_cached then
break;
case currloc of
LOC_REFERENCE :

View File

@ -1,4 +1,4 @@
{
{
Copyright (c) 1998-2002 by Florian Klaempfl
Generate assembler for call nodes
@ -283,29 +283,6 @@ implementation
hlcg.maybe_change_load_node_reg(current_asmdata.CurrAsmList,left,true);
{ release memory for refcnt out parameters }
if (parasym.varspez=vs_out) and
is_managed_type(left.resultdef) and
not(target_info.system in systems_garbage_collected_managed_types) then
begin
hlcg.location_get_data_ref(current_asmdata.CurrAsmList,left.resultdef,left.location,href,false,sizeof(pint));
if is_open_array(resultdef) then
begin
{ if elementdef is not managed, omit fpc_decref_array
because it won't do anything anyway }
if is_managed_type(tarraydef(resultdef).elementdef) then
begin
if third=nil then
InternalError(201103063);
secondpass(third);
hlcg.g_array_rtti_helper(current_asmdata.CurrAsmList,tarraydef(resultdef).elementdef,
href,third.location,'fpc_finalize_array');
end;
end
else
hlcg.g_finalize(current_asmdata.CurrAsmList,left.resultdef,href)
end;
paramanager.createtempparaloc(current_asmdata.CurrAsmList,aktcallnode.procdefinition.proccalloption,parasym,not followed_by_stack_tainting_call_cached,tempcgpara);
{ handle varargs first, because parasym is not valid }

37
tests/webtbs/tw28454.pp Normal file
View File

@ -0,0 +1,37 @@
{$mode objfpc}
type
tc = class(tinterfacedobject)
l: longint;
constructor create(f: longint);
end;
constructor tc.create(f: longint);
begin
l:=f;
end;
procedure test(out i1,i2: iinterface; k3,k4,k5,k6,k7,k8: longint; out i9,i10: iinterface); stdcall;
begin
i1:=tc.create(1);
i2:=tc.create(2);
i9:=tc.create(9);
i10:=tc.create(10);
end;
var
i1,i2,i9,i10: iinterface;
begin
test(i1,i2,3,4,5,6,7,8,i9,i10);
if (i1 as tc).l<>1 then
halt(1);
if (i2 as tc).l<>2 then
halt(2);
if (i9 as tc).l<>9 then
halt(3);
if (i10 as tc).l<>10 then
halt(4);
end.