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 ;
即使在使用FastMM4的大型程序中,此类代码段也可以编译并正常工作。但是有件事告诉我,这可能很危险... 有什么建议吗?
答案 0 :(得分:2)
我想您需要恢复逻辑。将静态数组转换为动态数组根本不安全(它在实际数据之前有一个计数器和引用计数),而相反(将动态数组转换为静态数组指针)是绝对安全的,如果您要注意的话缓冲区长度。
您的初始代码将触发一些随机的GPF(访问冲突),原因是在calcCRC()中的某些隐藏代码中将修改参考计数器-使用F2查看ASM:超出您的期望,特别是call DynArrayClear
,这是非常不安全的。由于内存中的内容,您还没有任何问题。但是如果在数据之前存储一个1整数,它将触发GPF,因为保留calcCRC()将使Delphi RTL尝试释放动态数组实例。
如果希望使用索引访问内存字节,则需要使用指向静态数组而不是动态数组的指针。
代码可能如下:
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;
还要确保您不会弄乱指针,例如您可以使用有关值(T ...)和指针(P ....)的适当Delphi约定来命名变量。还应遵循相同的约定,以区分代码中的静态数组和动态数组。
答案 1 :(得分:1)
这种方法当然是不安全的。静态阵列与动态阵列的内存布局不同。动态数组的元数据包含引用计数和长度。在这段简短的摘录中,您可能会不喜欢它,但是不建议您使用它。
无论是什么问题,这都不是解决方案。可能的解决方案可能涉及使用开放数组或指向字节的指针。