Menu ▾ ▴

#536 D13x64 - AV on open Configuration

Closed
closed-fixed
None
5
2 hours ago
1 day ago
markbd13
No

Delphi 13.1 (Delphi 13 Version 37.0.59082.6021 ; Update 1; May Patch)
GExpert compiled from sources, revision 5848.

Gexport --> More --> Configuration

[Window Title]
Delphi 13 (64-bit)

[Content]
EAccessViolation: Access violation at address 00007FFD4AA6B9E6 in module 'coreide370.bpl' (offset 58B9E6). Read of address FFFFFFFFF6568DFB

[OK]

D13x32 - there is not AV.

1 Attachments

Discussion

  • Thomas Mueller

    Thanks for the report and the call stack.

    I cannot reproduce this with Delphi 13.2 64-bit and a DLL built from revision 5848: the configuration dialog opens without an error. The address that could not be read (FFFFFFFFF6568DFB) looks like a 32-bit value that was widened to 64 bits, which only matters when the memory involved lies above 2 GB, so it may well depend on the machine.

    To find out which GExperts code calls into coreide370.bpl there, I need to resolve the four GExperts64RS130.dll lines of your call stack. Since you compiled GExperts yourself, could you please attach the file GExperts64RS130.map from the Binaries folder, from the same build that produced the error? It is written next to the DLL, and only the one matching the crashing DLL helps.

    It would also help to know:

    • which other IDE plugins are installed in the 64-bit IDE (e.g. CnPack, MMX, DDevExtensions),
    • whether it happens every time the configuration dialog is opened, or only sometimes.
     
  • markbd13

    markbd13 - 8 hours ago

    Analysis

    The exception comes from TfmConfiguration.Create > CheckShortcutConflicts > Ota.TryGetShortCutOwner > Ota.TryGetShortCutBindingOwners. That function calls IOTAKeyboardServices.LookupKeyBinding and then GetNextBindingRec.

    In ToolsAPI.pas of RAD Studio 13, TKeyBindingRecis declared like this:

    TKeyBindingRec = record
      KeyCode: TShortCut;
      KeyProc: TKeyBindingProc;
      Context: Pointer;
      Next: Integer;
      Reserved: Integer;
    end;
    

    Next holds a pointer to the next binding, but it is declared as Integer. In the 64-bit IDE that pointer gets cut to 32 bits, and coreide then follows the truncated value. The sign-extended read address FFFFFFFFxxxxxxxx points that way. Skipping only GetNextBindingRec was not enough: LookupKeyBinding itself crashed at the same address. So these keyboard binding queries look unusable in the 64-bit IDE. This is probably also worth reporting to Embarcadero.

    The same function is used by the Keyboard Shortcuts expert (Ota.IsKeyMappingPackageActive, Ota.IsKeyBoundByMappingPackage, Ota.TryGetShortCutBindingOwner), so that expert is affected as well.

    Suggested fix (tested locally, see below)

    Source/Utils/GX_OtaUtils.pas, Ota.TryGetShortCutBindingOwners: do not query the IDE under WIN64.

      if (Length(_Keys) = 0) or (_Keys[0] = 0) then
        Exit; //==>
    
    {$IFDEF WIN64}
      // TKeyBindingRec.Next is declared as Integer, but the IDE keeps a pointer in it. The 64 bit
      // IDE (checked with RAD Studio 13) cuts that pointer to 32 bits, and both LookupKeyBinding
      // and GetNextBindingRec raise an access violation in coreide when they follow it. So the
      // bindings cannot be asked for there.
      Exit; //==>
    {$ENDIF}
    

    As a result, the 64-bit IDE no longer finds shortcuts that another plugin has bound without an action. Conflicts with IDE actions, menu keys and the keymapping tables are still detected.

    ExternalSource/GX_SizeGripHWND.pas: this unit is not the cause of this crash, but it has a 64-bit bug that showed up while fixing it. It subclasses the window with GetWindowLong/SetWindowLong(GWL_WNDPROC), which cut the window procedure address to 32 bits in Win64. That breaks the size grip of the Configuration dialog, of Open File and of the IDE forms made sizeable via GX_IdeManagedForm. The fix uses the Ptr variants under WIN64, in GxSetWindowSizeGrip and in the WM_NCDESTROY handler of SizeGripWndProc:

    {$IFDEF WIN64}
          Info^.OldWndProc := TWndProc(Pointer(GetWindowLongPtr(hWnd, GWL_WNDPROC)));
    {$ELSE}
          Info^.OldWndProc := TWndProc(Pointer(GetWindowLong(hWnd, GWL_WNDPROC)));
    {$ENDIF}
    ...
    {$IFDEF WIN64}
        SetWindowLongPtr(hWnd, GWL_WNDPROC, LONG_PTR(@SizeGripWndProc));
    {$ELSE}
        SetWindowLong(hWnd, GWL_WNDPROC, NativeInt(@SizeGripWndProc));
    {$ENDIF}
    

    and in WM_NCDESTROY:

    {$IFDEF WIN64}
                SetWindowLongPtr(hWnd, GWL_WNDPROC, LONG_PTR(@Info^.OldWndProc));
    {$ELSE}
                SetWindowLong(hWnd, GWL_WNDPROC, NativeInt(@Info^.OldWndProc));
    {$ENDIF}
    

    Tested with RAD Studio 13, both 32-bit and 64-bit IDE:

    the Configuration dialog opens and can be resized
    the Keyboard Shortcuts window opens and can be resized
    Both changes are inside {$IFDEF WIN64}, so the 32-bit code is unchanged. I could not build with Delphi 6 or 2007.

    Possibly related, not fixed: Source/Framework/GX_EditorChangeServices.pas, TGxEditorNotifier.HookEditorWndProc/UnhookEditorWndProc, has the same pattern. It uses SetWindowLong(..., GWL_WNDPROC, ...) and stores the old window procedure in FOldEditControlWndProc: Integer, which truncates the address in Win64.

     
  • Thomas Mueller

    Thomas Mueller - 6 hours ago

    Thanks a lot for the analysis, that was the cause. Fixed in revision #5853.

    The key binding queries: I could reproduce it, but not in the way I first tried. In my 64-bit Delphi 13.2 the queries worked, and the values in Next looked harmless (e.g. 0B160007). The 64-bit IDE of Delphi 12.3 also showed nothing at first, because no key had a second binding. With a small test package that binds one key twice, it crashed exactly as you describe: LookupKeyBinding returned Next = B59BD623, and GetNextBindingRec raised an access violation in coreide290.bpl reading FFFFFFFFB59BD629, i.e. Next sign-extended plus 6. So Next is a pointer cut to 32 bits, and whether that fails depends on whether the memory it points to lies above 2 GB. That is why it did not show in my 13.2.

    The fix is what you suggested: under WIN64, Ota.TryGetShortCutBindingOwners no longer queries the IDE at all, regardless of the version. The Configuration dialog and the Keyboard Shortcuts window still report conflicts with IDE actions, menu keys and the keymapping tables, just not keys bound by other plugins without an action.

    The size grip: I did not change GX_SizeGripHWND.pas. In Delphi 13, which is the only version GExperts builds a 64-bit DLL for, Winapi.Windows declares GetWindowLong/SetWindowLong with NativeInt and implements them with GetWindowLongPtr/SetWindowLongPtr, so nothing is cut there. The size grip of the Configuration dialog is there in my 64-bit IDE. I suspect you did not see it because the dialog crashed while it was being created.

    GX_EditorChangeServices.pas: you are right that FOldEditControlWndProc: Integer would cut the address in Win64. That hook is currently never installed (HookEditorWndProc is only called behind if False), so it did no harm, but the field is GXNativeInt now.

    Could you please check revision #5853 with your 13.1 64-bit IDE?

     
  • Thomas Mueller

    Thomas Mueller - 6 hours ago

    bug report #RSS-6058 submitted to Embarcadero:

     
  • markbd13

    markbd13 - 5 hours ago

    I downloaded revision 5853.
    The configuration and keyboard mapping windows open, and they are resizable.
    Checked in D13.1 x32 and D13.1 x64.

     
  • Thomas Mueller

    Thomas Mueller - 2 hours ago

    Thanks for testing it with 13.1, closing.

     

Log in to post a comment.