错误德尔福XE2 - Exception类$ C00000005(Error Delphi XE

2019-11-02 20:23发布

我得到这个错误将调试项目,该项目使用的是在Delphi 7,我已经升级到德尔福XE2,在几种方法发生了同样的错误。

First chance exception at $006DC660. Exception class $C0000005 with message 'access violation at 0x006dc660 read of address 0xffffffff' 

这是方法之一:

PFI = ^TFI;           
TFI = record
Id         : TToken;
Name       : TName;
Parameters : string;
end;

function TListFI.IsIn(S: PChar): PFI;

  function SearchName2(Item: PFI):Boolean;
  var N1, N2: PChar;
  begin
    N1:= StrNew(Item^.Name);
    N2:= StrNew(S); //Here is the issue
    SearchName2:= (StrComp(StrUpper(N1), StrUpper(N2)) = 0);
    StrDispose(N1);
    StrDispose(N2);
  end;

begin
  IsIn:= PFI(FirstThat(@SearchName2));
end;

我用Google搜索,我发现有人描述了类似的问题,他肯定的是,当增量链接被禁用它的工作原理,可有人告诉我什么,它在哪里或者给一些建议来解决这种情况。

[编辑]

现在卸下@给我下面的错误ISIN:= PFI(FirstThat(SearchName2));

E2010 Incompatible types: 'TObject' and 'PFI'

我加入FirstThat程序,看它是否可能帮助。

TFuncionColeccion = function (Elemento: TObject): Boolean;

function TColeccion.FirstThat (Rutina: TFuncionColeccion): TObject;
var
  i: Integer;
begin
  For i:=0 to Count-1 do
    if Rutina(Items[i]) then
    begin
      FirstThat:=Items[i];
      exit;
    end;
  FirstThat:=nil;
end;

Answer 1:

这是(而且一直)通过指针调用本地(嵌套)程序,这是你清楚什么错误FirstThat功能一样。 编译器有做特别的事情与堆栈调用本地函数,并给他们访问父范围的变量( S在你的代码),但是编译器只知道做那些特别的东西当本地函数直接调用。 编译器无法知道参数FirstThat将是一个局部功能,因此它不包括特殊代码时FirstThat调用指向的作用。

底线是,在函数内部堆栈不被设置了它应该的方式,这意味着可能出现任何数量的奇怪症状。 你必须使用一些其他的方式。 也许让SearchName2是两个参数的函数,然后写FirstThat接受S因为它可以转发到函数参数的参数。

你不应该需要使用@构造函数指针时操作。 当你这样做时,编译器倾向于跳过类型检查,这是什么让你通过本地函数指针FirstThat摆在首位。 当你真的传递函数所需的原型相匹配,编译器将允许您通过它没有@操作。



Answer 2:

您报告中的访问冲突

StrNew(S)

其中S的类型为PChar 。 的解释为,与概率非常接近1,是S事实上不是一个指向空的终止阵列WideChar

在Delphi 7, PChar是一个别名PAnsiChar 。 也就是说为null的终止阵列的指针AnsiChar ,即8位的字符。 在Delphi XE2, PChar是别名PWideChar ,指针为null的终止阵列WideChar ,即16个字符。

它有助于了解StrNew一样。 它引导的阵列,直到它找到一个空字符。 对于8位文本是一个零字节。 对于16位的文字,零是零16位字。 然后它分配的相同的长度的输入字符串的存储一个新的块,并进行复印到新的存储器。 的源代码是:

function StrNew(const Str: PWideChar): PWideChar;
var
  Size: Cardinal;
begin
  if Str = nil then Result := nil else
  begin
    Size := StrLen(Str) + 1;
    Result := StrMove(WideStrAlloc(Size), Str, Size);
  end;
end;

唯一可行的失效模式是,当StrLen行走阵列,它尝试一个无效存储器读。 如果你输入的参数是无效的,只能发生。 换句话说,这一定是你一个编程错误。

一个可能的解释是,你实际上是通过8位文本这个功能虽然承诺通过16位的文本。 一个容易犯的错误,特别是如果你还没有完全熟悉Unicode的变化。 8位文本具有零终止,但后面的字节碰巧不为零。 或零字节落在奇数从一开始偏移。 然后StrNew继续走缓冲区,但现在它是关闭的结束,所以发生,它并没有超越到尚未分配的地址之前找到一个零字。 这是一个访问冲突。

如果是这样的话解决方案将是两种:

  • 更改函数的参数为类型PAnsiChar ,并固定在调用点半信半疑的铸造。
  • 通过该功能16位文本,因为它需要。

在你更新你包括不能被读取的地址, 0xffffffff 。 这是-1十六进制。 这似乎是最平淡无奇的错误。 您的指针完全是假的! 你确切的错误信息可使用此代码被复制: StrNew(PChar(-1))

我没有在这里足够的信息来告诉你为什么你的指针是伪造的。 希望你学到一些调试和诊断技术,使您解决问题。 至少你现在知道错误是在你的代码。

假设BuscaName2和SearchName2是同一个东西,那么你需要看没有进一步。 当地的程序只能从包含函数调用。 作为@Rob正确地说,用程序使用@几乎总是不正确的,是严重的问题与您的代码的警告信号。



文章来源: Error Delphi XE2 - Exception class $C00000005