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 to FirstThat will be a local function, so it doesn't include the special code when FirstThat 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 write FirstThat to accept S 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 to FirstThat 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
StrNew(S)
where S is of type PChar. The explanation for that, with probability very close to 1, is that S is not in fact a pointer to null terminated array of WideChar.
In Delphi 7, PChar is an alias for PAnsiChar. That is a pointer to null terminated array of AnsiChar, i.e. 8 bit characters. In Delphi XE2, PChar is an alias for PWideChar, a pointer to null terminated array of WideChar, 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:
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;
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:
Change the function's parameter to be of type PAnsiChar, and fix the dubious casting at the call site.
Pass the function 16 bit text as it requires.
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.
Related
When dynamically loading a DLL where DoSomething is a method type variable we can do
DoSomething:= GetProcAddress(MyDLLHandle ,'DoSomething');
or
#DoSomething:= GetProcAddress(MyDLLHandle ,'DoSomething');
Both of these seem to behave identically in modern versions of Delphi. My question is - has the # operator always been optional and, if not, in which version of Delphi did it become optional?
The documentation states that #, when used with routine (function/procedure) types returns the entry point of the function with type Pointer. When using the variable directly it naturally has whatever specific type it was declared with but also returns the entry point to the method. GetProcAddress returns a Pointer so I'm assuming that the habit of including # when loading a DLL comes from a time when these mismatched types were not assignment compatible. Is this the case?
Are there any reasonable arguments to prefer either of these styles?
I don't believe that anything has changed since the original versions of Delphi.
The official header translation for GetProcAddress has a return type of FARPROC which is an alias to the untyped Pointer type. Because of this, you can put pretty much anything pointer-esque on the left hand side of the assignment statement, because type checking is suspended when one of the operands is Pointer.
On the other hand, consider this program:
var
Proc: procedure;
Ptr: Pointer;
begin
Ptr := Proc;
end.
This fails to compile with:
E2010 Incompatible types: 'Pointer' and 'procedure, untyped pointer or untyped parameter'
The simple fix is to use the # operator:
var
Proc: procedure;
Ptr: Pointer;
begin
Ptr := #Proc;
end.
It is certainly the case that many Delphi examples use:
#Proc := GetProcAddress(...);
rather than
Proc := GetProcAddress(...);
I rather suspect that there is nothing deep here. Just a case of a choice made by the author of one of the first online articles on the subject propagating throughout history with no good reason. Which reminds me of the terrible Rosetta code example of dynamic loading that tests whether an HMODULE is greater than 32, an erroneous check that can be seen in Stack Overflow questions on a weekly basis!
Should you use # in these circumstances or not? In my view you should not. It doesn't make much difference, and given that why bother with a needless piece of punctuation?
There is one other scenario that I know where you need to use #, and in that case you actually need ##. Consider the following program:
{$APPTYPE CONSOLE}
uses
SysUtils;
var
Proc: procedure;
Ptr: Pointer;
begin
Ptr := #Proc;
Writeln(Format('%p', [Ptr]));
Ptr := ##Proc;
Writeln(Format('%p', [Ptr]));
Readln;
end.
Output
00000000
00423EBC
The first assignment gets the value held in the Proc variable, which because it is a default initialised global, is zero. The second assignment gets the address of the Proc variable. And for that you need ##. It's pretty unusual to need this much indirection, but it tends to crop up when writing code related to dynamic linking.
Recently I've ported a huge chunk of code form C++ to Delphi (over 1mb of C code). The code is full with pointers. Despite project compiling and working well for 99% of the time, I'm seeing some weird results from time to time, which leads me to think there might be bugs with pointer handling - indeed, I've already found a couple. The problem is that they are really hard to track down without any clues/hints from compiler.
Maybe you have some tips, for such cases:
var
a: PSingle;
GetMem(a, SizeOf(Single));
a^ := 1.1;
// Call func declared as - someFunc(aIn: PSingle);
someFunc(#a); // <<-- Bug here. I mistakely added # while porting.
// someFunc needs PSingle, but gets a PPSingle instead
In the example, there's erroneous # inserted. Program does not crash, just deals with that erroneous data and keeps running. I need a way of finding such cases where "Pointer to a Pointer to a Value" gets passed instead of "Pointer to a Value".
How do you track down pointer bugs like these?
The "typed # operator" compiler option is designed to detect exactly that kind of mistake. When it's disabled, the expression #a has type Pointer, which is compatible with all pointer types. Enable the option, and the same expression has type ^PSingle, which is not compatible with the expected PSingle.
I recommend turning on that option in all projects; it baffles me that Delphi doesn't make that option the default all the time.
You can modify the state of that option within your code with the $T+ and $T- compiler directives.
Another thing you can do is convert your code to use more idiomatic Delphi. For example, pass the argument by reference instead of by pointer value. Change the definition of the argument:
procedure someFunc(var arg: Single);
With that declaration, passing #a will be an error that the compiler will find and forbid. You would instead pass a^, or you could even get rid of the pointer entirely and just declare a as a plain Single rather than PSingle.
Just because the original code was written in C and C-style C++, it doesn't mean your Delphi code has to look like it.
The problem is here:
someFunc(#a);
You are adding a pointer to a pointer not the pointer it self.
Let me make you an example:
uses
Math;
function Somefunc(value: pSingle): Single;
begin
Result := (value^ + 1.1)
end;
procedure TForm23.FormCreate(Sender: TObject);
var
a: pSingle;
b: Single;
begin
GetMem(a, SizeOf(Single));
a^ := 1.1;
//Example 1:
b := Somefunc(a);
Caption := BoolToStr(CompareValue(2.2, b, 0.00001) = 0., True); //Caption: True
//Example 2:
b := Somefunc(#a); //NOTE #a
Caption := BoolToStr(CompareValue(1.1, b, 0.00001) = 0., True); //Caption: True
FreeMem(a);
end;
As you see in the first example the actual value are changed, while in example 2 the value og a remains unchanged because you parse the pointer to the pointer and therefor it is the pointer you chanhe and not the value.
This question already has answers here:
Need simple demo call Delphi DLL in C++
(2 answers)
Closed 8 years ago.
How can I receive a string from a FPC DLL? I would like to send two pointers concat them and receive the result in another string in Delphi.
library Test;
{$mode Delphi}
uses
Classes;
function Concat(const S1, S2: PWideChar): String; cdecl;
begin
Result := S1 + S2;
end;
exports
Concat name 'Concat';
begin
end.
In Delphi, a String is a complex, structured type with many details managed for you by the compiler and RTL 'magic' that hides these details. In particular, for 'long strings' there is a reference count and a length and, depending on the Delphi version involved, possibly other information.
Any DLL cannot know the details of precisely what information is required to be returned (or may be present in) any 'string' variables (or results) that an application may require. The DLL may not even be called by a Delphi program at all, in which case the 'string' type will be quite different again.
For this reason, a DLL will usually choose to deal with strings as simple 'C'-style pointer to char types. That is, some pointer to a null terminated region of memory. The caller of the DLL must then also ensure to exchange 'string' values with the DLL accordingly.
In the case of some function returning a value, the issue is complicated by the fact that allocation of the area of memory required to hold the result must be performed by the caller, with the function in the DLL taking appropriate steps to ensure that the memory supplied is sufficient. Applying these principles in this case results in a DLL routine that might look similar to this:
function Concat(const S1, S2, DEST: PWideChar; const aMaxLen: Integer): Boolean; cdecl;
begin
// left as exercise
end;
This is a simple implementation that returns TRUE if aMaxLen is sufficient to accommodate the concatenated result. You should also consider other behaviours of the function under a variety of conditions (eg. S1 or S2 or both are NIL, aMaxLen is too big, etc).
Whatever implementation choices are made for performing the concatenation (left as an exercise for you), the result of the function call must be to place the result in the buffer pointed to by DEST.
The caller must then also ensure that a buffer of sufficient length is provided and the correct length indicated in the call:
var
a, b, ab: WideString; // Or: String or UnicodeString in Delphi 2009 and later
begin
a := 'foo';
b := 'bar';
// Make sure 'ab' is big enough to hold the concatenated result of a + b
SetLength(ab, Length(a) + Length(b));
if Concat(PWideChar(a), PWideChar(b), PWideChar(ab), Length(ab)) then
// success: ab == 'foobar'
else
// something went wrong
end;
The question has to be asked though: Why are you doing this in an FPC DLL when Delphi already handles the concatenation of strings quite comfortably ? O.o
I inherited a Delphi application and I know nothing about object pascal.
It's a BPL that I need to compile into the new version of C++ Builder XE.
When I run a make I get the error:
E2064 left side cannot be assigned to.
I've learned enough obj pascal to know I have a constant that is trying to be assigned a value.
But, apparently, you can over ride this behanvior; essentially turning constants into vars by going into Build options under the Delphi compiler and turning on "Assignable Typed constants".
I did that and I continue to get the same error.
I tried surrounding my code with {$J+} and {$J-} and still it will not compile.
procedure TChunkIDAT.CopyInterlacedRGB8(const Pass: Byte;
Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar );
var
Col: Integer;
begin
{Get first column and enter in loop}
Col := ColumnStart[Pass];
Dest := pChar(Longint(Dest) + Col * 3);
repeat
{Copy this row}
Byte(Dest^) := fOwner.GammaTable[pByte(Longint(Src) + 2)^]; inc(Dest);
Get the error on last line. If I change the const to a var, I then get the error that the declaration differs from the previous declaration but I have no idea where the previous declaration is....
You're type-casting a two-byte thing (Char) into a one-byte thing (Byte). Reading that value is easy to define, but making that value writable is tricky, probably for the same reason the types of formal and actual "var" parameters need to be identical.
Maybe you wanted to type-cast it to a two-byte thing, such as Word. Or maybe you want GammaTable to be an array of Char so you don't have to type-cast at all. Or maybe, if this code was originally written for a Delphi version earlier than 2009, you want those PChar declarations to be PAnsiChar — character types have gotten wider. Another option is to type-cast Dest to PByte, and then dereference the result. That's probably a bad idea, though, because you'll only be overwriting every other byte of the buffer.
Based on the name of the function, it sounds like PChar was never the right data type to use. That type is for character data, but I think this code is dealing with bytes. The correct thing to do is probably to change PChar to PByte, and then you don't need to type-cast Dest at all.
The $J directive is irrelevant; it controls whether the compiler will allow you to assign values to typed constants. You don't have any of those in this code.
The reason is that as of Delphi 2009, Char, PChar, and String are Unicode, and store more than one byte per character.
You should not cast those pointers to bytes, and the compiler prevents you from assigning them if you cast the left side of an assignment to a byte.
This compiles:
procedure CopyInterlacedRGB8(const Pass: Byte; Dest: pAnsiChar); overload;
begin
Byte(Dest^) := Pass;
end;
This doesn't:
procedure CopyInterlacedRGB8(const Pass: Byte; Dest: pChar); overload;
begin
Byte(Dest^) := Pass;
end;
Instead of pChar, you should use pByte, which makes the code simpler:
procedure CopyInterlacedRGB8(const Pass: Byte; Dest: PByte); overload;
begin
Dest^ := Pass;
end;
--jeroen
That looks like you're working with Gustavo Daud's TPngImage library. You don't need that code in an external BPL because it's been included in the RTL since D2009. Remove that unit from the BPL and you should be able to get at the updated version via the PngImage unit.
I was really impressed with this delphi two liner using the IFThen function from Math.pas. However, it evaluates the DB.ReturnFieldI first, which is unfortunate because I need to call DB.first to get the first record.
DB.RunQuery('select awesomedata1 from awesometable where awesometableid = "great"');
result := IfThen(DB.First = 0, DB.ReturnFieldI('awesomedata1'));
(as a pointless clarification, because I've got so many good answers already. I forgot to mention that 0 is the code that DB.First returns if it's got something in it, might not have made sense otherwise)
Obviously this isn't such a big deal, as I could make it work with five robust liners. But all I need for this to work is for Delphi to evaluate DB.first first and DB.ReturnFieldI second. I don't want to change math.pas and I don't think this warrants me making a overloaded ifthen because there's like 16 ifthen functions.
Just let me know what the compiler directive is, if there is an even better way to do this, or if there is no way to do this and anyone whose procedure is to call db.first and blindly retrieve the first thing he finds is not a real programmer.
The evaluation order of expressions is commonly undefined. (C and C++ are the same way. Java always evaluates left-to-right.) The compiler offers no control over it. If you need two expressions to be evaluated in a specific order, then write your code differently. I wouldn't really worry about the number of lines of code. Lines are cheap; use as many as you need. If you find yourself using this pattern often, write a function that wraps it all up:
function GetFirstIfAvailable(DB: TDatabaseObject; const FieldName: string): Integer;
begin
if DB.First = 0 then
Result := DB.ReturnFieldI(FieldName)
else
Result := 0;
end;
Your original code probably wouldn't have been what you wanted, even if evaluation order were different. Even if DB.First wasn't equal to zero, the call to ReturnFieldI would still be evaluated. All actual parameters are fully evaluated before invoking the function that uses them.
Changing Math.pas wouldn't help you anyway. It doesn't control what order its actual parameters are evaluated in. By the time it sees them, they've already been evaluated down to a Boolean value and an integer; they're not executable expressions anymore.
The calling convention can affect evaluation order, but there's still no guarantee. The order that parameters are pushed onto the stack does not need to match the order in which those values were determined. Indeed, if you find that stdcall or cdecl gives you your desired evaluation order (left-to-right), then they are being evaluated in the reverse order of the one they're passed with.
The pascal calling convention passes arguments left-to-right on the stack. That means the leftmost argument is the one at the bottom of the stack, and the rightmost argument is at the top, just below the return address. If the IfThen function used that calling convention, there are several ways the compiler could achieve that stack layout:
The way you expect, which is that each argument is evaluated and pushed immediately:
push (DB.First = 0)
push DB.ReturnFieldI('awesomedata1')
call IfThen
Evaluate arguments right-to-left and store the results in temporaries until they're pushed:
tmp1 := DB.ReturnFieldI('awesomedata1')
tmp2 := (DB.First = 0)
push tmp2
push tmp1
call IfThen
Allocate stack space first, and evaluate in whatever order is convenient:
sub esp, 8
mov [esp], DB.ReturnFieldI('awesomedata1')
mov [esp + 4], (DB.First = 0)
call IfThen
Notice that IfThen receives the argument values in the same order in all three cases, but the functions aren't necessarily called in that order.
The default register calling convention also passes arguments left-to-right, but the first three arguments that fit are passed in registers. The registers used to pass arguments, though, are also the registers most commonly used for evaluating intermediate expressions. The result of DB.First = 0 needed to be passed in the EAX register, but the compiler also needed that register for calling ReturnFieldI and for calling First. It was probably a little more convenient to evaluate the second function first, like this:
call DB.ReturnFieldI('awesomedata1')
mov [ebp - 4], eax // store result in temporary
call DB.First
test eax, eax
setz eax
mov edx, [ebp - 4]
call IfThen
Another thing to point out is that your first argument is a compound expression. There's a function call and a comparison. There's nothing to guarantee that those two parts are performed consecutively. The compiler might get the function calls out of the way first by calling First and ReturnFieldI, and afterward compare the First return value against zero.
The calling convention affects the way they are evaluated.
There is not a compiler define to control this.
Pascal is the calling convention you would have to use to get this behavior.
Although I would personally never depend on this type of behavior.
The following example program demonstrates how this works.
program Project2;
{$APPTYPE CONSOLE}
uses SysUtils;
function ParamEvalTest(Param : Integer) : Integer;
begin
writeln('Param' + IntToStr(Param) + ' Evaluated');
result := Param;
end;
procedure TestStdCall(Param1,Param2 : Integer); stdCall;
begin
Writeln('StdCall Complete');
end;
procedure TestPascal(Param1,Param2 : Integer); pascal;
begin
Writeln('Pascal Complete');
end;
procedure TestCDecl(Param1,Param2 : Integer); cdecl;
begin
Writeln('CDecl Complete');
end;
procedure TestSafecall(Param1,Param2 : Integer); safecall;
begin
Writeln('SafeCall Complete');
end;
begin
TestStdCall(ParamEvalTest(1),ParamEvalTest(2));
TestPascal(ParamEvalTest(1),ParamEvalTest(2));
TestCDecl(ParamEvalTest(1),ParamEvalTest(2));
TestSafeCall(ParamEvalTest(1),ParamEvalTest(2));
ReadLn;
end.
This would require you to write your own IfThen Functions.
If you really want this to be a one liner you really can do that in Delphi. I just think it looks ugly.
If (DB.First = 0) then result := DB.ReturnFieldI('awesomedata1') else result := 0;
Can't you change your query to have only one result so avoid to do the 'First' command ?
Just like :
SELECT TOP 1 awesomedata1 from awesometable
In Access...
AFAIK there is no compiler directive to control this. Unless you use the stdcall/cdecl/safecall conventions, parameters are passed left to right on the stack, but because the default register convention can pass parameters in the registers as well, it could happen that a parameter is calculated later an put in a register just before the call. And because only the register order is fixed (EAX, EDX, ECX) for parameters that qualify, registers can be loaded in any order. You could try to force a "pascal" calling convention (you'd need to rewrite the function, anyway) but IMHO is always dangerous to rely on such kind of code, if the compiler can't explicitly guarantee the order of evaluation. And imposing an evaluation order may greatly reduce the number of optimizations available.