14

I can't seem to figure this one out. My program compiles and runs successfully, but during debugging only it pops up a message box saying "Invalid Pointer Operation" when shutting the program down. I have painstakingly checked all the FormCloseQuery and FormDestory events for any syntax or logical error. I found none and they execute as expected without any error.

enter image description here

When I do tell the compiler to break at Invalid Pointer Operation error, it doesn't do anything but hangs up the program. At which point, I had to terminate or kill the process.

How do you figure this one out?

Thanks in advance,

Wolf
  • 9,679
  • 7
  • 62
  • 108
ThN
  • 3,235
  • 3
  • 57
  • 115
  • 6
    Enable Debug DCUs and step through the shutdown until you can find what triggers this error. Are you running with FastMM in Full Debug mode? – David Heffernan Apr 11 '12 at 20:09
  • @DavidHeffernan, :) I remember we had a conversation about FastMM. Unfortunately, I have not used FastMM since I test ran it while back. I will enable DCU and see what happens. – ThN Apr 11 '12 at 20:16
  • @DavidHeffernan, after the break with dcu enabled, debugger stopped in System.pas file. Bit confusing but I thinking its because one of Mason wheeler's reason. I guess now I have to put FastMM back in. – ThN Apr 12 '12 at 12:30
  • @DavidHeffernan, Yep after using FastMM, I found the problem with my program. It was trying to free an object that was already destroyed. However, the problem is not because there was any logical or syntax error. For some odd reason my program is calling the same Destroy event more than once. So, the program is trying to free an object that it already destroyed because the form Destroy event is called again. – ThN Apr 12 '12 at 15:06
  • The problem could be at your end, or it is possible that it is a known VCL bug. I recommend that you add a call to `MainForm.Free` in your .dpr file, after Application.Run. Naturally you'll replace `MainForm` with whatever your main form is called. In fact if you have more than one global form variable then you should do this for them all. Letting them get destroyed by dint of being owned by `Application` can lead to the error you describe due to a known but unfixed bug in the VCL. – David Heffernan Apr 12 '12 at 15:11
  • 1
    Set some stack tracer and perhaps turn one "use debug DCUs" It looks that you have some stray pointer that youtry to free two times. http://stackoverflow.com/questions/3631987 http://stackoverflow.com/questions/12505251 http://stackoverflow.com/questions/2237028 – Arioch 'The Jan 18 '13 at 10:52
  • Start by clicking the `Break` button, and when the IDE takes control view the Stack Trace to find the last part of your own code that executed. Set a breakpoint in that code, and then rerun your app until it triggers the breakpoint. Single step through the code to see if you can cause the exception and locate where it's happening. Also, you can install MadExcept or EurekaLog, both of which can help track down this sort of problem. With no other info, there's not much else we can tell you. – Ken White Jan 18 '13 at 12:24
  • @Ken - read below the screenshot "it doesn't do anything but hangs up the program". Apart from user mistaking IDE for compiler, the rst seems he tried to break it. – Arioch 'The Jan 18 '13 at 13:02
  • Install and use MadExcept. It's free for non commercial use. (EurekaLog is not.) -- One place where this might happen that you might overlook is in finalization sections of units in your program, and the units in the components and libraries that you are linking in. Presumably you clicked Break, and you tried to look at the Stack? – Warren P Jan 18 '13 at 14:23
  • 1
    If you "found none," then you need to look harder, because obviously there *is* a problem in your program. – Rob Kennedy Jan 18 '13 at 15:36

4 Answers4

34

An Invalid Pointer exception is thrown by the memory manager when it tries to free invalid memory. There are three ways this can happen.

The most common is because you're trying to free an object that you've already freed. If you turn on FastMM's FullDebugMode, it will detect this and point you directly to the problem. (But make sure to build a map file so it will have the information it needs to create useful stack traces from.)

The second way is if you're trying to free memory that was allocated somewhere other than the memory manager. I've seen this a few times when passing a string from a Delphi EXE to a Delphi DLL that wasn't using the shared memory manager feature.

And the third way involves messing around with pointers directly and probably doesn't apply to you. If you try to FreeMem or Dispose a bad pointer that doesn't refer to an actual block of memory allocated by FastMM, you'll get this error.

It's most likely the first one. Use FullDebugMode and you'll find the source of the problem easily.

Mason Wheeler
  • 82,511
  • 50
  • 270
  • 477
  • you are absolutely right. Your first reason is why my program is raising this exception notification. However, it is raising because my TForm's destroy event is called more than once. That I don't understand why. – ThN Apr 12 '12 at 15:10
  • If I were to take a guess, I'd say because your form was created with an owner (such as Application; did you use `Application.CreateForm` to construct it?) and then somewhere else you're trying to free it manually. Take a look at the stack traces for the two times it's being freed; they'll give you an idea what's going on. And keep the [Single Ownership Principle](http://tech.turbu-rpg.com/106/delphi-memory-management-made-simple) in mind: Your forms can be owned by Application, or by your code, but not by both. – Mason Wheeler Apr 12 '12 at 16:19
11

Invalid pointer operations occur when you tell the Delphi memory manager to release memory that doesn't belong to it. There are three ways that might happen:

  • Freeing a pointer or object that has already been freed.
  • Using FreeMem to free something that was allocated by some other memory manager (such as GlobalAlloc or CoTaskMemAlloc).
  • Freeing an uninitialized pointer. (This is distinct from freeing a null pointer, which is completely safe.)

Somewhere in your program, you are doing one of those things. The debugger has detected the exception thrown by the memory manager, so do some debugging. From the stack trace, you should be able to see which variable you're trying to free. Check the rest of your program for other ways that variable is used.

Tools like MadExcept and Eureka Log can help you find double-free errors. They can keep track of where the pointer in question got allocated and where it was freed the first time, and that is sometimes enough information to figure out your mistake and stop freeing things multiple times.

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
  • Is it also thrown if you try to free the address of a locally declared object? – Wolf Jan 13 '15 at 09:17
  • Yes, @Wolf. That's covered by the second bullet point. In that case, you'd be attempting to free memory allocated on the stack. – Rob Kennedy Jan 13 '15 at 13:18
  • Thanks. This "allocated" or "memory manager" looks strange when talking about automatic variables. Maybe this should be added as well (in a more explicit way)? – Wolf Jan 13 '15 at 13:22
  • I think the first sentence of the answer covers everything pretty well, @Wolf. The rest of the answer is just elaborating on that. I don't want to have to give an exhaustive list of all the ways memory can be allocated that aren't the main Delphi memory manager. – Rob Kennedy Jan 13 '15 at 13:36
  • I see. I just tried to provoke that exception by freeing stack memory, but I wasn't able to. The only I got working was an `EAccessViolation` by calling `delete` pointer variables that I filled with `int` values via `reinterpret_cast`. – Wolf Jan 13 '15 at 13:43
  • @Wolf, the question asks what would cause EInvalidPointer. It's predicated on the assumption that you've gotten such an exception, and the answer explains what you might have done to cause that: "If you get X, it's because you did Y." You're approaching it from the other way: You're performing certain operations, and hoping to get a particular exception. The things you're doing formally lead to undefined behavior. (It's formal because you're using C++, which is standardized.) Doing Y doesn't necessary lead to X. Other things might get in the way (including access violations). – Rob Kennedy Jan 13 '15 at 13:52
  • Sorry for the confusion, I use Borland C++ Builder (6.0!) which is very close to the Delphi of that time. I'm personally dealing with a sporadic Error that's causing sometimes EAccessVialoation and sometimes EInvalidPointer. – Wolf Jan 13 '15 at 14:14
2

A 4th reason an invalid pointer operation can occur. I had two pointers that where array[0..1000] of real and a third pointer that was an array[1..200] of real. All 3 pointers where initialized with for i := 0 to 1000 do begin ptr1^[i]:=0;ptr2^[i]:=0;ptr3^[i]:=0; end; While this poor programing did not bother Pascal in Delphi a call to Dispose any of the 3 pointers resulted in an Invalid Pointer Operation. The fix was simply to initialize the 3rd pointer correctly.

Dick Brown
  • 21
  • 1
0

I have been caught out by this type of "indicated error" during Delphi debugging.

Check if you have any watched variables with "Allow Function Calls" enabled or watches that try to show other variables in the same unit (or global) that might be uninitialised. When stopping on a breakpoint this can cause Delphi's debugger to attempt to display the value via a function call that accesses an uninitialised Pointer or variable. The actual variable that causes the AV my not even be on your watch list.

Despatcher
  • 1,745
  • 12
  • 18
  • 4
    EAccessViolation is distinct from EInvalidPointer. *Accessing* an invalid pointer gives the former; only *freeing* gives the latter. – Rob Kennedy Jan 18 '13 at 15:35