Does TMonitor.GetBoundsRect have an access violation bug in Delphi 2007 triggered by VNC?

delphi, delphi-2007

Solution

It's most likely qc #53932 (also #25466 #57953), and patching Forms.pas does fix it. In my case, using D7, it only got triggered by using remote access, and the problem/fix is the same as for D2007.

Specifically, the patch is to change TScreen.FindMonitor. This is the D7 change, not sure if it needs any edits for D2007.

function TScreen.FindMonitor(Handle: HMONITOR): TMonitor;
var
  I: Integer;
begin
  Result := nil;
  for I := 0 to MonitorCount - 1 do
    if Monitors[I].Handle = Handle then
    begin
      Result := Monitors[I];
//      break;
      Exit;
    end;
  //if we get here, the Monitors array has changed, so we need to clear and reinitialize it
  for i := 0 to MonitorCount-1 do
    TMonitor(Monitors[i]).Free;
  fMonitors.Clear;
  EnumDisplayMonitors(0, nil, @EnumMonitorsProc, LongInt(FMonitors));
  for I := 0 to MonitorCount - 1 do
    if Monitors[I].Handle = Handle then
    begin
      Result := Monitors[I];
      Exit;
    end;
end;

Problem

This is a crash report I get from customers running one of our big products built in Delphi 2007, that I am unable to reproduce and which doesn't even have any non-VCL code directly involved via the call stack. The VCL Source code for TMonitor in Delphi 2007 is very simple (`Forms.pas`) `TMonitor.GetBoundsRect` calls win32 API `GetMonitorInfo` after initializing a struct's `cbSize` so that the Windows API knows what size to return. I have been over and over this code and I can't see how this level could crash, unless the Self pointer is invalid, although I suspect it might actually be the `THintWindow` level malfunctioning, and it is only at the `TMonitor.GetBoundsRect` that this malfunction becomes a visible crash because somehow it has gotten a pointer to an invalid `TMonitor` object and invoked a method on it. ``` function TMonitor.GetBoundsRect: TRect; var MonInfo: TMonitorInfo; begin MonInfo.cbSize := SizeOf(MonInfo); GetMonitorInfo(FHandle, @MonInfo); // <----- CRASH. Result := MonInfo.rcMonitor; end; ``` Crash call stack via madExcept is only reproduceable on client systems: ``` main thread ($70): 004f5004 +010 myapp.exe Forms 6361 +2 TMonitor.GetBoundsRect 004f4fe2 +00a myapp.exe Forms 6352 +1 TMonitor.GetWidth 004e022f +06b myapp.exe Controls 9929 +7 THintWindow.ActivateHint 004e0457 +017 myapp.exe Controls 9970 +1 THintWindow.ActivateHintData 004f95fa +31a myapp.exe Forms 8923 +56 TApplication.ActivateHint 004f8fc1 +02d myapp.exe Forms 8728 +8 TApplication.HintTimerExpired 004f61e6 +022 myapp.exe Forms 7083 +3 HintTimerProc 7e4196c2 +00a USER32.dll DispatchMessageA 004f7f00 +0fc myapp.exe Forms 8105 +23 TApplication.ProcessMessage 004f7f3a +00a myapp.exe Forms 8124 +1 TApplication.HandleMessage 004f822f +0b3 myapp.exe Forms 8223 +20 TApplication.Run 0155cf77 +2f3 myapp.exe myapp 368 +41 initialization ``` All the code above in the entire call stack is VCL source code, none of it is mine. Aside from disabling all Hints in the entire application, is there anything I could do to further troubleshoot this or work around it? Update: Registers and disasm, and exception address: ``` exception class : EAccessViolation exception message : Access violation at address 004F5004 in module 'hirepnt.exe'. Read of address 00000004. cpu registers: eax = 00000000 ebx = 0012fccc ecx = 7e42ac2c edx = 0012fccc esi = 07b694a8 edi = 0012fd14 eip = 004f5004 esp = 0012fc90 ebp = 0012fd1c stack dump: 0012fc90 94 fc 12 00 28 00 00 00 - 2c ac 42 7e 70 b3 6f 02 ....(...,.B~p.o. 0012fca0 fc fc 12 00 01 00 00 00 - 70 b3 6f 02 cc 53 4f 00 ........p.o..SO. 0012fcb0 01 00 00 00 01 00 00 00 - 3c 56 4f 00 14 fd 12 00 ........<VO..... 0012fcc0 a8 94 b6 07 00 00 00 00 - e7 4f 4f 00 00 00 00 00 .........OO..... 0012fcd0 4b 64 4f 00 14 fd 12 00 - a8 94 b6 07 00 00 00 00 KdO............. 0012fce0 34 02 4e 00 4c fd 12 00 - c4 5c 40 00 1c fd 12 00 4.N.L....\@..... 0012fcf0 40 fd 12 00 97 fd 12 00 - 0c 23 4d 00 e0 01 00 00 @........#M..... 0012fd00 6d 01 00 00 e0 01 00 00 - 6d 01 00 00 41 02 00 00 m.......m...A... 0012fd10 80 01 00 00 34 fd 12 00 - 10 cc 6e 02 40 fd 12 00 ....4.....n.@... 0012fd20 5d 04 4e 00 d8 fd 12 00 - 0c 23 4d 00 f0 fd 12 00 ].N......#M..... 0012fd30 e0 01 00 00 6d 01 00 00 - 41 02 00 00 7c 01 00 00 ....m...A...|... 0012fd40 f4 fd 12 00 00 96 4f 00 - 00 00 00 00 0c fe 12 00 ......O......... 0012fd50 c4 5c 40 00 f4 fd 12 00 - 8c fe 12 00 c4 61 4f 00 .\@..........aO. 0012fd60 40 41 6f 02 00 00 00 00 - 00 00 00 00 28 05 00 00 @Ao.........(... 0012fd70 15 02 00 00 00 00 00 00 - 00 00 00 00 d9 04 00 00 ................ 0012fd80 ac 01 00 00 84 00 00 e0 - 01 00 00 6d 01 00 00 41 ...........m...A 0012fd90 02 00 00 7c 01 00 00 01 - 4f 00 00 00 69 00 00 00 ...|....O...i... 0012fda0 51 00 00 00 6b 00 00 00 - e0 01 00 00 61 01 00 00 Q...k.......a... 0012fdb0 f0 84 22 06 0c 23 4d 00 - e0 01 00 00 6d 01 00 00 .."..#M.....m... 0012fdc0 56 05 00 00 18 00 00 ff - fe ff ff ff fe ff ff ff V............... disassembling: [...] 004f4ff6 push edi 004f4ff7 add esp, -$28 004f4ffa mov ebx, edx 004f4ffc 6360 mov dword ptr [esp], $28 004f5003 6361 push esp 004f5004 > mov eax, [eax+4] 004f5007 push eax 004f5008 mov eax, [$1644560] 004f500d mov eax, [eax] 004f500f call eax 004f5011 6362 mov edi, ebx [...] ```

Original source

Related problems