mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-13 17:59:09 +02:00
* Fixed handling of "open array of managed type" out-parameters at caller side. Reference count should be decremented only for those array elements which are actually passed to the called procedure; it may be a part of original array if range or slice is used. Concludes work on #18859.
+ Test git-svn-id: trunk@17136 -
This commit is contained in:
parent
2df0ef4937
commit
48d93dc40e
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -9457,6 +9457,7 @@ tests/test/tarray5.pp svneol=native#text/plain
|
|||||||
tests/test/tarray6.pp svneol=native#text/plain
|
tests/test/tarray6.pp svneol=native#text/plain
|
||||||
tests/test/tarray7.pp svneol=native#text/plain
|
tests/test/tarray7.pp svneol=native#text/plain
|
||||||
tests/test/tarray8.pp svneol=native#text/plain
|
tests/test/tarray8.pp svneol=native#text/plain
|
||||||
|
tests/test/tarray9.pp svneol=native#text/plain
|
||||||
tests/test/tasmread.pp svneol=native#text/plain
|
tests/test/tasmread.pp svneol=native#text/plain
|
||||||
tests/test/tasout.pp svneol=native#text/plain
|
tests/test/tasout.pp svneol=native#text/plain
|
||||||
tests/test/tassignmentoperator1.pp svneol=native#text/pascal
|
tests/test/tassignmentoperator1.pp svneol=native#text/pascal
|
||||||
|
@ -201,6 +201,9 @@ interface
|
|||||||
function can_be_inlined: boolean;
|
function can_be_inlined: boolean;
|
||||||
|
|
||||||
property nextpara : tnode read right write right;
|
property nextpara : tnode read right write right;
|
||||||
|
{ third is reused to store the parameter name (only while parsing
|
||||||
|
vardispatch calls, never in real node tree) and copy of 'high'
|
||||||
|
parameter tree when the parameter is an open array of managed type }
|
||||||
property parametername : tnode read third write third;
|
property parametername : tnode read third write third;
|
||||||
|
|
||||||
{ returns whether the evaluation of this parameter involves a
|
{ returns whether the evaluation of this parameter involves a
|
||||||
@ -620,6 +623,8 @@ implementation
|
|||||||
old_array_constructor:=allow_array_constructor;
|
old_array_constructor:=allow_array_constructor;
|
||||||
allow_array_constructor:=true;
|
allow_array_constructor:=true;
|
||||||
typecheckpass(left);
|
typecheckpass(left);
|
||||||
|
if assigned(third) then
|
||||||
|
typecheckpass(third);
|
||||||
allow_array_constructor:=old_array_constructor;
|
allow_array_constructor:=old_array_constructor;
|
||||||
if codegenerror then
|
if codegenerror then
|
||||||
resultdef:=generrordef
|
resultdef:=generrordef
|
||||||
@ -635,6 +640,8 @@ implementation
|
|||||||
if not assigned(left.resultdef) then
|
if not assigned(left.resultdef) then
|
||||||
get_paratype;
|
get_paratype;
|
||||||
firstpass(left);
|
firstpass(left);
|
||||||
|
if assigned(third) then
|
||||||
|
firstpass(third);
|
||||||
expectloc:=left.expectloc;
|
expectloc:=left.expectloc;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -2492,6 +2499,7 @@ implementation
|
|||||||
varargspara,
|
varargspara,
|
||||||
currpara : tparavarsym;
|
currpara : tparavarsym;
|
||||||
hiddentree : tnode;
|
hiddentree : tnode;
|
||||||
|
paradef : tdef;
|
||||||
begin
|
begin
|
||||||
pt:=tcallparanode(left);
|
pt:=tcallparanode(left);
|
||||||
oldppt:=pcallparanode(@left);
|
oldppt:=pcallparanode(@left);
|
||||||
@ -2527,7 +2535,19 @@ implementation
|
|||||||
if not assigned(pt) or (i=0) then
|
if not assigned(pt) or (i=0) then
|
||||||
internalerror(200304081);
|
internalerror(200304081);
|
||||||
{ we need the information of the previous parameter }
|
{ we need the information of the previous parameter }
|
||||||
hiddentree:=gen_high_tree(pt.left,tparavarsym(procdefinition.paras[i-1]).vardef);
|
paradef:=tparavarsym(procdefinition.paras[i-1]).vardef;
|
||||||
|
hiddentree:=gen_high_tree(pt.left,paradef);
|
||||||
|
{ for open array of managed type, a copy of high parameter is
|
||||||
|
necessary to properly initialize before the call }
|
||||||
|
if is_open_array(paradef) and
|
||||||
|
(tparavarsym(procdefinition.paras[i-1]).varspez=vs_out) and
|
||||||
|
is_managed_type(tarraydef(paradef).elementdef) then
|
||||||
|
begin
|
||||||
|
typecheckpass(hiddentree);
|
||||||
|
{this eliminates double call to fpc_dynarray_high, if any}
|
||||||
|
maybe_load_in_temp(hiddentree);
|
||||||
|
oldppt^.third:=hiddentree.getcopy;
|
||||||
|
end;
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
if vo_is_typinfo_para in currpara.varoptions then
|
if vo_is_typinfo_para in currpara.varoptions then
|
||||||
|
@ -167,6 +167,15 @@ implementation
|
|||||||
is_managed_type(left.resultdef) then
|
is_managed_type(left.resultdef) then
|
||||||
begin
|
begin
|
||||||
location_get_data_ref(current_asmdata.CurrAsmList,left.location,href,false,sizeof(pint));
|
location_get_data_ref(current_asmdata.CurrAsmList,left.location,href,false,sizeof(pint));
|
||||||
|
if is_open_array(resultdef) then
|
||||||
|
begin
|
||||||
|
if third=nil then
|
||||||
|
InternalError(201103063);
|
||||||
|
secondpass(third);
|
||||||
|
cg.g_array_rtti_helper(current_asmdata.CurrAsmList,tarraydef(resultdef).elementdef,
|
||||||
|
href,third.location,'FPC_DECREF_ARRAY');
|
||||||
|
end
|
||||||
|
else
|
||||||
cg.g_decrrefcount(current_asmdata.CurrAsmList,left.resultdef,href);
|
cg.g_decrrefcount(current_asmdata.CurrAsmList,left.resultdef,href);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
122
tests/test/tarray9.pp
Normal file
122
tests/test/tarray9.pp
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
{ %OPT=-gh }
|
||||||
|
|
||||||
|
{ Test correct RTTI handling of open arrays with managed elements.
|
||||||
|
When a part (slice or range) of array is passed as an out-parameter open array
|
||||||
|
to a procedure, the entire array should NOT be finalized, only part that is actually passed should. }
|
||||||
|
|
||||||
|
{$mode objfpc}{$h+}
|
||||||
|
uses SysUtils;
|
||||||
|
|
||||||
|
|
||||||
|
procedure test3(out arr: array of string);
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
{ implicit initialization happens here }
|
||||||
|
for i := 0 to High(arr) do
|
||||||
|
begin
|
||||||
|
Pointer(arr[i]):=nil; // if array initialization was correct, this will be a no-op
|
||||||
|
// otherwise, it will trigger a memory leak
|
||||||
|
arr[i] := 'tested'+IntToStr(i);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure test_entire_openarray(var arr: array of string);
|
||||||
|
begin
|
||||||
|
test3(arr);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure test_openarray_subrange(var arr: array of string);
|
||||||
|
begin
|
||||||
|
test3(arr[1..2]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure test_openarray_slice(var arr: array of string);
|
||||||
|
begin
|
||||||
|
test3(slice(arr,2));
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
var
|
||||||
|
sarr: array[0..3] of string;
|
||||||
|
darr: array of string;
|
||||||
|
|
||||||
|
procedure prepare;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
for i := 0 to 3 do
|
||||||
|
begin
|
||||||
|
sarr[i] := 'static'+IntToStr(i);
|
||||||
|
darr[i] := 'dynamic'+IntToStr(i);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
HaltOnNotReleased := True;
|
||||||
|
SetLength(darr,4);
|
||||||
|
|
||||||
|
prepare;
|
||||||
|
test_entire_openarray(sarr);
|
||||||
|
if sarr[0] <> 'tested0' then Halt(1);
|
||||||
|
if sarr[1] <> 'tested1' then Halt(2);
|
||||||
|
if sarr[2] <> 'tested2' then Halt(3);
|
||||||
|
if sarr[3] <> 'tested3' then Halt(4);
|
||||||
|
|
||||||
|
prepare;
|
||||||
|
test_openarray_subrange(sarr); // must leave elements 0 and 3 intact
|
||||||
|
if sarr[0] <> 'static0' then Halt(11);
|
||||||
|
if sarr[1] <> 'tested0' then Halt(12);
|
||||||
|
if sarr[2] <> 'tested1' then Halt(13);
|
||||||
|
if sarr[3] <> 'static3' then Halt(14);
|
||||||
|
|
||||||
|
prepare;
|
||||||
|
test_openarray_slice(sarr); // must leave elements 2 and 3 intact
|
||||||
|
if sarr[0] <> 'tested0' then Halt(21);
|
||||||
|
if sarr[1] <> 'tested1' then Halt(22);
|
||||||
|
if sarr[2] <> 'static2' then Halt(23);
|
||||||
|
if sarr[3] <> 'static3' then Halt(24);
|
||||||
|
|
||||||
|
prepare;
|
||||||
|
test3(sarr); // entire static array
|
||||||
|
if sarr[0] <> 'tested0' then Halt(31);
|
||||||
|
if sarr[1] <> 'tested1' then Halt(32);
|
||||||
|
if sarr[2] <> 'tested2' then Halt(33);
|
||||||
|
if sarr[3] <> 'tested3' then Halt(34);
|
||||||
|
|
||||||
|
prepare;
|
||||||
|
test3(sarr[1..2]); // static array subrange
|
||||||
|
if sarr[0] <> 'static0' then Halt(41);
|
||||||
|
if sarr[1] <> 'tested0' then Halt(42);
|
||||||
|
if sarr[2] <> 'tested1' then Halt(43);
|
||||||
|
if sarr[3] <> 'static3' then Halt(44);
|
||||||
|
|
||||||
|
prepare;
|
||||||
|
test3(slice(sarr,2)); // static array slice
|
||||||
|
if sarr[0] <> 'tested0' then Halt(51);
|
||||||
|
if sarr[1] <> 'tested1' then Halt(52);
|
||||||
|
if sarr[2] <> 'static2' then Halt(53);
|
||||||
|
if sarr[3] <> 'static3' then Halt(54);
|
||||||
|
|
||||||
|
prepare;
|
||||||
|
test3(darr); // entire dynamic array
|
||||||
|
if darr[0] <> 'tested0' then Halt(61);
|
||||||
|
if darr[1] <> 'tested1' then Halt(62);
|
||||||
|
if darr[2] <> 'tested2' then Halt(63);
|
||||||
|
if darr[3] <> 'tested3' then Halt(64);
|
||||||
|
|
||||||
|
prepare;
|
||||||
|
test3(darr[1..2]); // dynamic array subrange
|
||||||
|
if darr[0] <> 'dynamic0' then Halt(71);
|
||||||
|
if darr[1] <> 'tested0' then Halt(72);
|
||||||
|
if darr[2] <> 'tested1' then Halt(73);
|
||||||
|
if darr[3] <> 'dynamic3' then Halt(74);
|
||||||
|
|
||||||
|
prepare;
|
||||||
|
test3(slice(darr,2)); // dynamic array slice
|
||||||
|
if darr[0] <> 'tested0' then Halt(81);
|
||||||
|
if darr[1] <> 'tested1' then Halt(82);
|
||||||
|
if darr[2] <> 'dynamic2' then Halt(83);
|
||||||
|
if darr[3] <> 'dynamic3' then Halt(84);
|
||||||
|
|
||||||
|
end.
|
Loading…
Reference in New Issue
Block a user