0

Q: Is it safe to cast dynamic array over a static one ?

type
  Bytearray = array of byte;

function calcCRC(buf1: pointer) : dword;    
var
  buf: ByteArray ;
  outbuffer : array [1..30] of byte;
begin
  buf := bytearray(buf1^); // <- is it safe ?
  outbuffer[1] := buf[0];
end;

procedure test;
var
  testarr : array [1..30] of byte ;
begin
  calccrc(@testarr);
end ;

Such snippet compiles and works correctly, even in quite large program with FastMM4. But something tells me, that it can be dangerous ... Any advice ?

4
  • A dynamic array is managed, and has heap allocation for length and ref-count. Commented Dec 10, 2018 at 7:57
  • Yes, that should work, but generally, it is not safe to cast static to dynamic, because dynamic arrays are reference types and they are automatically reference counted. If the runtime tries to get the length or do such an auto-refcount on a static array, things tend to go terribly wrong. So for your hack to work, range checking should be off. Commented Dec 10, 2018 at 7:58
  • @RudyVelthuis Even if you don't use the the length, since the compiler handles reference counting - as you stated - it generates a call DynArrayClear which is pretty unsafe in this context. So no, it doesn't "work"! :) Commented Dec 10, 2018 at 8:32
  • 1
    @Arnaud: You are right. I misread the code. The cast does indeed induce a DynArrayClear and that is indeed unsafe. Commented Dec 10, 2018 at 8:46

2 Answers 2

3

I guess you need to revert your logic. Casting a static array into a dynamic array is not safe at all (it has a counter and reference count before the actual data), whereas the opposite - casting a dynamic array into a static array pointer - is perfectly safe, if you take care of the buffer length.

Your initial code will trigger some random GPF (Access Violations) due to the fact that the reference counter will be modified in calcCRC() in some hidden code - look at the ASM using F2: there is more than you may expect, especially a call DynArrayClear which is pretty unsafe. You didn't have any problem yet because of what was in your memory. But if e.g. a 1 integer is stored before the data, it would trigger a GPF, since leaving calcCRC() would let the Delphi RTL try to release the dynamic array instance.

If you expect to access bytes of memory using indexes, you need to use a pointer to a static array, not a dynamic array.

The code could be the following:

Type
  TByteDynArray = array of byte ;
  TByteArray = array[0 .. (maxInt div sizeof(byte)) - 1] of byte;
  PByteArray = ^TByteArray;

function calcCRCptr(buf1: PByteArray; buf1len: integer): dword;   
var
  outbuffer : array [1..30] of byte;
begin
  result := 0;
  // ensure you don't create any access violation by using big indexes
  if buf1len < 1 then
    exit; // avoid GPF
  outbuffer[1] := buf1[0];
  ...
end;

function calcCRCdynarray(const buf1: TByteDynArray): dword;   
begin
  // you can use length(buf1) to get the number of items/bytes
  result := calcCRCptr(pointer(buf1), length(buf1));
end;

procedure test ;
var
  testdynarr: TByteDynArray;
  teststaticarray: array[0..10] of byte;
begin
  Setlength(testdynarr, 100);
  calccrcdynarray(testdynarr) ;     // safe
  calccrcptr(pointer(testdynarr), length(testdynarr)); // direct call
  calccrcptr(@teststaticarray, 11); // OK
end;

Also ensure that you don't mess with pointers, e.g. that you name your variables with proper Delphi convention about values (T...) and pointers (P....). Also follow the same convention to distinguish static arrays and dynamic arrays in your code.

Sign up to request clarification or add additional context in comments.

2 Comments

many thanks, that's what I exactly felt :) I do lot of stuff in C++ (embedded systems), so sometimes want to do nasty things in Delphi, too :)
Exactly what you felt? Er, then why did the code in the question do the exact opposite?
1

This approach is certainly not safe. The static array has a different memory layout from the dynamic array. The dynamic array has metadata containing reference count and length. You might get away with it in this short excerpt but it is not a technique to be recommended.

Whatever the problem is, this is not the solution. Possible solutions might involve working with open arrays or pointers to byte.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.