Invalid pointer operation

Please report only one bug per message!

Moderators: white, Hacker, petermad, Stefan2

Post Reply
davitof
Junior Member
Junior Member
Posts: 31
Joined: 2005-09-04, 09:36 UTC
Location: France

Invalid pointer operation

Post by *davitof »

Hello,

I just got this error. I am running TC in a Windows XP Mode virtual PC. I discovered this error dialog when switching back from my Seven 64 bit host session to the WXPMode window. As far as I can remember, I was not doing anything special in TC, only checking what options the contextual menu offered when on a specific folder. Since the last time I checked the WXPMode window, I had switched to the Seven host session without closing the WXPMode session, and done quite a few things (but none which should have an influence on the virtual PC). My laptop did go to sleep once during that time. TC was at the root of the virtual machine and the focus was on "System Volume Information".

---------------------------
Total Commander 8.01
---------------------------
Invalid pointer operation.
Invalid pointer operation
Windows XP SP3 5.1 (Build 2600)

Please report this error to the Author, with a description
of what you were doing when this error occurred!

Delphi exception: EInvalidPointer
Stack trace:
7C812AFB
402D2A 409306 4030A6 40E086 40E040 40EF5F
40D3BD 40B84E 40B971 40B9C7 424F9A 5D8F40
5DF41B 5E2F8E 634368 634694 444AD1 446A22
>423F38 445FE3 423F38 429604 42969C 6D9F34

Raw:
402D2A 402D2A 4026A0 402CEC 409017 402D2A
402D2A 402D2A 402726 402F73 402D57 402D65
402F68 40909B 403296 403296 409306 403296
4030A6 40D5FC 40E086 40E040 40F21F 40EF5F
403296 40D3BD 403296 40B84E 403296 40B971
403296 445CC5 445D10 447C7D 42622C 444AD1
446CF1 411022 425C14 444A1B 402249 4033D0
4021C8 402249 4033D0 4021C8 4026A0 402CEC
402F38 402D3E 40B9C7 403296 424F9A 403296
4212CB 4023EF 4033D0 5D8F40 5DF41B 402249

Press Ctrl+C to copy this report!
Continue execution?
---------------------------
Oui Non
---------------------------
Frederic
davitof
Junior Member
Junior Member
Posts: 31
Joined: 2005-09-04, 09:36 UTC
Location: France

Post by *davitof »

One more information: when I closed TC, I got a dialog saying :
"Exception EExternalException in module TOTALCMD.EXE at 0022A688. External exception C0000006."
Frederic
User avatar
ghisler(Author)
Site Admin
Site Admin
Posts: 48075
Joined: 2003-02-04, 09:46 UTC
Location: Switzerland
Contact:

Post by *ghisler(Author) »

I will check it, thanks.
Author of Total Commander
https://www.ghisler.com
User avatar
MarcinW
Power Member
Power Member
Posts: 852
Joined: 2012-01-23, 15:58 UTC
Location: Poland

Post by *MarcinW »

Exception C0000006 is EXCEPTION_IN_PAGE_ERROR or STATUS_IN_PAGE_ERROR. This means that the Total Commander tried to read a memory, but reading a memory page failed. Possible reasons:

1) Hard disk failure - swap file (pagefile.sys) could not be read. There should be an error logged in the system log (eventvwr.msc). The problem may concern the hard disk itself or a hard disk controller.

2) Program is running over the network connection and the network became down.

3) Program is running from the CD/DVD/USB drive and it has been removed.

If not executed from the local disk, small EXE and DLL files are being cached entirely in the RAM or in the swap file, so the reasons 2) and 3) are less possible for the Total Commander.

More info:
http://blogs.msdn.com/b/oldnewthing/archive/2008/12/04/9172708.aspx

@davitof: You should search your system log for hard disk errors. In case of many errors, you should perform some hard disk tests to check if your drive is not dying...

@ghisler(Author): It is not a problem with the Total Commander. However you may consider writing your own handler for C0000006 exceptions, to recommend the user testing his hard drive. Below are samples for the low level handler and also for the VCL handler (tested with Delphi 2). Low level handler is the last resort handler - it kills the application with exit code 1 and it is being fired:
a) for threads (other than the main thread),
b) for the main thread for non-VCL applications,
c) for VCL applications, when VCL handler fails.

In our case the VCL handler displayed "Delphi exception: EInvalidPointer" message, but - due to serious problems - the low level handler has also been fired with "External exception C0000006" message.

Code: Select all

{Low level exception handler}

program Test;

uses Windows, SysUtils;

var
  OrigExceptProc : procedure(E : TObject; ExceptAddr : Pointer);

procedure CheckExternalException(E : TObject);
begin
  {When the exception is not raised originally by the operating system,
   but raised using the "raise" clause, ExceptionRecord is nil}
  if E is EExternalException then
  if EExternalException(E).ExceptionRecord <> nil then
  if EExternalException(E).ExceptionRecord^.ExceptionCode = $C0000006 then
    EExternalException(E).Message:='WARNING: CHECK YOUR DRIVE - IT MAY BE DYING!!!';
end;

procedure ExceptHandler(E : TObject; ExceptAddr : Pointer);
begin
  CheckExternalException(E); {Setting our own message}
  OrigExceptProc(E,ExceptAddr);
end;

var
  E : EExternalException;
  ExceptionRecord : TExceptionRecord;
begin
  {Installation}
  OrigExceptProc:=ExceptProc;
  ExceptProc:=@ExceptHandler;

  {Test}
  E:=EExternalException.Create('Test');
  E.ExceptionRecord:=@ExceptionRecord;
  E.ExceptionRecord.ExceptionCode:=$C0000006;
  raise E;
end.

Code: Select all

{VCL exception handler}

unit Unit1;

interface

uses
  Windows, SysUtils, Classes, Controls, Forms, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    procedure ExceptionProc(Sender : TObject; E : Exception);
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure CheckExternalException(E : TObject);
begin
  {When the exception is not raised originally by the operating system,
   but raised using the "raise" clause, ExceptionRecord is nil}
  if E is EExternalException then
  if EExternalException(E).ExceptionRecord <> nil then
  if EExternalException(E).ExceptionRecord^.ExceptionCode = $C0000006 then
    EExternalException(E).Message:='WARNING: CHECK YOUR DRIVE - IT MAY BE DYING!!!';
end;

procedure TForm1.ExceptionProc(Sender : TObject; E : Exception);
begin
  CheckExternalException(E); {Setting our own message}
  Application.ShowException(Exception(ExceptObject));
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  {Installation}
  Application.OnException:=ExceptionProc;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  E : EExternalException;
  ExceptionRecord : TExceptionRecord;
begin
  {Test}
  E:=EExternalException.Create('Test');
  E.ExceptionRecord:=@ExceptionRecord;
  E.ExceptionRecord.ExceptionCode:=$C0000006;
  raise E;
end;

end.
Regards!
User avatar
MarcinW
Power Member
Power Member
Posts: 852
Joined: 2012-01-23, 15:58 UTC
Location: Poland

Post by *MarcinW »

Additional info on EXCEPTION_IN_PAGE_ERROR exception:

http://msdn.microsoft.com/en-us/library/windows/desktop/aa366801.aspx
User avatar
ghisler(Author)
Site Admin
Site Admin
Posts: 48075
Joined: 2003-02-04, 09:46 UTC
Location: Switzerland
Contact:

Post by *ghisler(Author) »

2MarcinW
I'm already using my own error handler to show a custom stack trace, so adding special handling for this error may be a good idea. However, there is a danger that the error handler isn't in memory either when the error occurs...
Author of Total Commander
https://www.ghisler.com
User avatar
MarcinW
Power Member
Power Member
Posts: 852
Joined: 2012-01-23, 15:58 UTC
Location: Poland

Post by *MarcinW »

However, there is a danger that the error handler isn't in memory either when the error occurs...
Low level exception handler should be installed at the very beginning of the main project file (.dpr), before any other lines, before Application.Initialize. This ensures you that your custom exception handler will always be properly installed:

Code: Select all

begin
  {Installation} 
  OrigExceptProc:=ExceptProc;
  ExceptProc:=@ExceptHandler;

  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;

  {Deinstallation} 
  ExceptProc:=OrigExceptProc;
end.

VCL exception handler should be installed at the very beginning of the FormCreate event (of the main form) and deinstalled at the very end of the FormDestroy event. It may fail to handle the exception, but then the low level handler will do the work. So, to be safe, both handlers should be used.


By the way, the warning message could be like this:

Code: Select all

Accessing virtual memory failed.
This is NOT a problem with Total Commander.

Possible causes:
- You are running Total Commander (or some of its files)
  from a removable media and this media has been removed,
- You are running Total Commander (or some of its files)
  over a network and the network connection has failed,
- You are running Total Commander (or some of its files)
  from a local disk and this disk has failed,
- Accessing your paging file (swap file) has failed,
- One of your local disks is completely full.

Check your system log for errors.
Regards
User avatar
ghisler(Author)
Site Admin
Site Admin
Posts: 48075
Joined: 2003-02-04, 09:46 UTC
Location: Switzerland
Contact:

Post by *ghisler(Author) »

Low level exception handler should be installed at the very beginning of the main project file (.dpr), before any other lines, before Application.Initialize. This ensures you that your custom exception handler will always be properly installed:
I'm even calling the handler with a dummy parameter to ensure that it's loaded, but this doesn't guarantee that Windows doesn't swap it out in a low memory condition.
Author of Total Commander
https://www.ghisler.com
User avatar
MarcinW
Power Member
Power Member
Posts: 852
Joined: 2012-01-23, 15:58 UTC
Location: Poland

Post by *MarcinW »

but this doesn't guarantee that Windows doesn't swap it out in a low memory condition.
But Windows must load it again before executing.

Process may be swapped out of physical RAM memory, partially or entirely. The second case may be achieved manually, by calling SetProcessWorkingSetSize(hProcess,$FFFFFFFF,$FFFFFFFF). We can swap out any process and - as we can see - after switching to this process (by activating its window) it is being loaded to the RAM again and continues executing.

Exception handler is a normal piece of code, so Windows must load it to the RAM memory before executing. Windows may even swap out other processes in order to free some RAM memory for our exception handler. It is completely unlikely for Windows to be unable to free some memory for the exception handler. But if this happens, exception handler fails to execute.

Fail in calling exception handler will terminate our process immediately. Try this:

Code: Select all

procedure TForm1.Button1Click(Sender: TObject);
begin
  try
    {We damage SEH stack frame - we set exception handler address to nil}
    asm
      mov eax,fs:[0]
      mov dword ptr [eax+4],0
    end;

    {We raise an exception - exception can't be handled and our process
     will be terminated immediately}
    PByte(nil)^:=0;
  except
    Application.HandleException(Self);
  end;
end;
and this:

Code: Select all

procedure TForm1.Button1Click(Sender: TObject);
begin
  {We lead to stack overflow - we touch the stack guard page and Windows
   converts it to a normal stack page in order to make a bit of additional
   stack space for handling the exception}
  try
    asm
@1:   push eax
      jmp @1
    end;
  except
  end;

  {We lead to stack overflow again - there is already no stack guard page
   and Windows can't make a bit of additional stack space for handling the
   exception - exception can't be handled and our process will be terminated
   immediately}
  try
    asm
@1:   push eax
      jmp @1
    end;
  except
  end;
end;
Summary: if our exception handler has been swapped out of physical RAM memory and Windows can't load it again (it is almost impossible), our process will be terminated. And we probably have much more serious problem than not executing our exception handler...
User avatar
MarcinW
Power Member
Power Member
Posts: 852
Joined: 2012-01-23, 15:58 UTC
Location: Poland

Post by *MarcinW »

Additional note: similar to the exception C0000006, EOutOfMemory doesn't need to display full exception report - simple message would be enough (instead of "Please report this error to the Author [...]").
User avatar
MarcinW
Power Member
Power Member
Posts: 852
Joined: 2012-01-23, 15:58 UTC
Location: Poland

Post by *MarcinW »

I overlooked something. I just ignored the first exception (EInvalidPointer) and focused on the second (EExternalException).

According to the crash report above, the exception EInvalidPointer was raised after calling FreeMem with an invalid pointer (FreeMem was called from inside of TObject.FreeInstance, this suggests invalid object instance - although the stack trace is a bit strange, 402D2A points to the middle of the call instruction).

So there are two possibilities of this error:
- memory corruption caused by a hardware malfunction (second exception, EExternalException, may suggest this),
- bug in TC (so the crash report is worth to be checked).

P.S. Have you tried to use a FastMM memory manager? It's not originally designed for Delphi 2, but few simple corrections should allow to use it as far as I know. FastMM has powerful tracing of problems with memory. And it's much faster than a standard memory manager in old Delphi versions (FastMM is a default memory manager in current Delphi releases).

Regards
User avatar
ghisler(Author)
Site Admin
Site Admin
Posts: 48075
Joined: 2003-02-04, 09:46 UTC
Location: Switzerland
Contact:

Post by *ghisler(Author) »

I'm already using a different memory manager which warns me about memory problems.
Author of Total Commander
https://www.ghisler.com
Post Reply