* Rewrote fpc_dynarray_copy to trim out-of-range arguments instead of raising range error. Makes behavior Delphi-compatible and resolves #21396.

* Changed copying the entire array to use range 0..high(sizeint) instead of -1..-2.

git-svn-id: trunk@20468 -
This commit is contained in:
sergei 2012-03-04 04:41:52 +00:00
parent a417e9d0b6
commit 92f927976e
3 changed files with 35 additions and 35 deletions

View File

@ -2505,6 +2505,7 @@ begin
def_system_macro('FPC_HAS_CONSTREF'); def_system_macro('FPC_HAS_CONSTREF');
def_system_macro('FPC_STATICRIPFIXED'); def_system_macro('FPC_STATICRIPFIXED');
def_system_macro('FPC_VARIANTCOPY_FIXED'); def_system_macro('FPC_VARIANTCOPY_FIXED');
def_system_macro('FPC_DYNARRAYCOPY_FIXED');
{$if defined(x86) or defined(powerpc) or defined(powerpc64)} {$if defined(x86) or defined(powerpc) or defined(powerpc64)}
def_system_macro('FPC_HAS_INTERNAL_ABS_LONG'); def_system_macro('FPC_HAS_INTERNAL_ABS_LONG');
{$endif} {$endif}

View File

@ -749,9 +749,9 @@ implementation
end end
else else
begin begin
{ use special -1,-1 argument to copy the whole array } { copy the whole array using [0..high(sizeint)] range }
highppn:=cordconstnode.create(int64(-1),s32inttype,false); highppn:=cordconstnode.create(torddef(sinttype).high,sinttype,false);
lowppn:=cordconstnode.create(int64(-1),s32inttype,false); lowppn:=cordconstnode.create(0,sinttype,false);
end; end;
{ create call to fpc_dynarray_copy } { create call to fpc_dynarray_copy }

View File

@ -248,56 +248,55 @@ function int_dynarray_copy(psrc : pointer;ti : pointer;
function fpc_dynarray_copy(psrc : pointer;ti : pointer; function fpc_dynarray_copy(psrc : pointer;ti : pointer;
lowidx,count:tdynarrayindex) : pointer;[Public,Alias:'FPC_DYNARR_COPY'];compilerproc; lowidx,count:tdynarrayindex) : pointer;[Public,Alias:'FPC_DYNARR_COPY'];compilerproc;
var var
realpdest,
realpsrc : pdynarray; realpsrc : pdynarray;
cnt, i,size : sizeint;
i,size : longint;
highidx : tdynarrayindex;
elesize : sizeint; elesize : sizeint;
eletype : pointer; eletype : pointer;
pdest : pointer;
begin begin
highidx:=lowidx+count-1; result:=nil;
pdest:=nil;
result:=pdest;
if psrc=nil then if psrc=nil then
exit; exit;
{$ifndef FPC_DYNARRAYCOPY_FIXED}
if (lowidx=-1) and (count=-1) then
begin
lowidx:=0;
count:=high(tdynarrayindex);
end;
{$endif FPC_DYNARRAYCOPY_FIXED}
realpsrc:=pdynarray(psrc-sizeof(tdynarray)); realpsrc:=pdynarray(psrc-sizeof(tdynarray));
if (lowidx<0) then
begin
{ Decrease count if index is negative, this is different from how copy()
works on strings. Checked against D7. }
if count<=0 then
exit; { may overflow when adding lowidx }
count:=count+lowidx;
lowidx:=0;
end;
if (count>realpsrc^.high-lowidx+1) then
count:=realpsrc^.high-lowidx+1;
if count<=0 then
exit;
{ skip kind and name } { skip kind and name }
ti:=aligntoptr(ti+2+PByte(ti)[1]); ti:=aligntoptr(ti+2+PByte(ti)[1]);
elesize:=pdynarraytypedata(ti)^.elSize; elesize:=pdynarraytypedata(ti)^.elSize;
eletype:=pdynarraytypedata(ti)^.elType2; eletype:=pdynarraytypedata(ti)^.elType2;
{ -1, -1 (highidx=lowidx-1-1=-3) is used to copy the whole array like a:=copy(b);, so
update the lowidx and highidx with the values from psrc }
if (lowidx=-1) and (highidx=-3) then
begin
lowidx:=0;
highidx:=realpsrc^.high;
end;
{ get number of elements and check for invalid values }
if (lowidx<0) or (highidx<0) or (lowidx > realpsrc^.high) then
HandleErrorFrame(201,get_frame);
cnt:=highidx-lowidx+1;
if (cnt > realpsrc^.high - lowidx + 1) then
cnt := realpsrc^.high - lowidx + 1;
{ create new array } { create new array }
size:=elesize*cnt; size:=elesize*count;
getmem(realpdest,size+sizeof(tdynarray)); getmem(result,size+sizeof(tdynarray));
pdest:=pointer(realpdest)+sizeof(tdynarray); pdynarray(result)^.refcount:=1;
pdynarray(result)^.high:=count-1;
inc(result,sizeof(tdynarray));
{ copy data } { copy data }
move(pointer(psrc+elesize*lowidx)^,pdest^,size); move(pointer(psrc+elesize*lowidx)^,result^,size);
{ fill new refcount }
realpdest^.refcount:=1;
realpdest^.high:=cnt-1;
{ increment ref. count of members? } { increment ref. count of members? }
if PByte(eletype)^ in tkManagedTypes then if PByte(eletype)^ in tkManagedTypes then
for i:= 0 to cnt-1 do for i:=0 to count-1 do
int_addref(pointer(pdest+elesize*i),eletype); int_addref(pointer(result+elesize*i),eletype);
result:=pdest;
end; end;