Reputation: 7387
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?
Upvotes: 1
Views: 213
Reputation: 163247
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.
Upvotes: 12
Reputation: 6402
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.
Upvotes: 0