I am getting this error will debugging a project, which used to be in Delphi 7 and I have been upgrading to Delphi XE2, the same error happens in several methods.
First chance exception at $006DC660. Exception class $C0000005 with message 'access violation at 0x006dc660 read of address 0xffffffff'
This is one of the methods:
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;
I have googled and I found someone describing a similar problem, and he affirms that when the incremental linker is disabled it works, can someone tell me what and where is it or give some advice to solve this situation.
[EDIT]
Removing the @ now gives me the following error in IsIn:= PFI(FirstThat(SearchName2));
E2010 Incompatible types: 'TObject' and 'PFI'
I am adding the FirstThat procedure to see if it may help.
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;
It is (and always has been) an error to call local (nested) procedures by pointer, which is clearly what your
FirstThat
function does. The compiler has to do special things with the stack to call local functions and give them access to the parent scope's variables (S
in your code), but the compiler can only know to do those special things when the local function is called directly. The compiler cannot know that the argument toFirstThat
will be a local function, so it doesn't include the special code whenFirstThat
invokes the pointed-to function.The bottom line is that the stack inside the function doesn't get set up the way it's supposed to, and that means any number of strange symptoms may appear. You'll have to use some other way. Maybe make
SearchName2
be a two-argument function, and then writeFirstThat
to acceptS
as a parameter that it can forward to the function argument.You shouldn't need to use the
@
operator when constructing a function pointer. When you do, the compiler tends to skip type checking, which is what allowed you to pass a local function pointer toFirstThat
in the first place. When the function you're passing really matches the required prototype, the compiler will allow you to pass it without the@
operator.You are reporting an access violation in
where
S
is of typePChar
. The explanation for that, with probability very close to 1, is thatS
is not in fact a pointer to null terminated array ofWideChar
.In Delphi 7,
PChar
is an alias forPAnsiChar
. That is a pointer to null terminated array ofAnsiChar
, i.e. 8 bit characters. In Delphi XE2,PChar
is an alias forPWideChar
, a pointer to null terminated array ofWideChar
, i.e. 16 bit characters.It helps to understand what
StrNew
does. It walks the array until it finds a null character. For 8 bit text that is a single zero byte. For 16 bit text, the null is a zero 16 bit word. Then it allocates a new block of memory of the same length as the input string, and makes a copy into that new memory. The source code is:The only plausible failure mode is that when
StrLen
walks the array, it attempts an invalid memory read. And that can only happen if your input parameter is invalid. In other words, this must be a programming error on your part.One possible explanation is that you are in fact passing 8 bit text to this function despite promising to pass 16 bit text. An easy mistake to make, especially if you are not yet fully familiar with the Unicode change. The 8 bit text has a zero terminator, but the byte that follows happens not to be zero. Or the zero byte falls at an odd numbered offset from the start. And then
StrNew
continues walking the buffer, but now it is off the end and it so happens that it doesn't find a zero word before overrunning into an address that has not been allocated. And that is an access violation.If that is so then solution will be either:
PAnsiChar
, and fix the dubious casting at the call site.In your update you include the address which cannot be read,
0xffffffff
. This is-1
in hex. And that would seem to be the most prosaic of errors. Your pointer is completely bogus! Your exact error message can be reproduced with this code:StrNew(PChar(-1))
.I don't have enough information here to tell you why your pointer is bogus. Hopefully you've learnt some debugging and diagnostic techniques that will enable you to solve the problem. At least you now know that the error is in your code.
Assuming that BuscaName2 and SearchName2 are one and the same thing, then you need look no further. Local procedures can only be called from a containing function. As @Rob correctly says, the use of @ with procedures is almost always incorrect and is a warning sign of serious problems with your code.