문제

현재 기존 Delphi 5 응용 프로그램을 Delphi 2010으로 포팅하려고합니다.

Outlook에로드되는 멀티 스레드 DLL (Outlook에 의해 스레드가 생성되는 경우)입니다. Delphi 2010을 통해 컴파일되면 양식을 닫을 때마다 Tmonitor.destroy ... System.pas의 "Invalid Pointer 작업"이 발생합니다.

이것은 기존의 복잡한 응용 프로그램이므로 많은 조사 방향과 델파이 도움 문서조차 없습니다 이 특정 tmonitor 클래스를 처음부터 문서화하지 않습니다 (추가 정보가있는 Allen Bauer 게시물로 추적했습니다) ... 그래서 나는 누군가가 이전에 이것을 발견했는지 또는이 문제를 일으킬 수있는 것에 대한 제안이 있는지 먼저 물어볼 것이라고 생각했습니다. . 레코드를 위해 : 나는 내 코드에서 tmonitor 기능을 명시 적으로 사용하고 있지 않으며, 우리는 여기에서 델파이 5 코드의 스트레이트 포트를 이야기하고 있습니다.

편집하다 Callstack 현재 문제가 발생합니다.

System.TMonitor.Destroy
System.TObject.Free
Forms.TCustomForm.CMRelease(???)
Controls.TControl.WndProc(???)
Controls.TWinControl.WndProc((45089, 0, 0, 0, 0, 0, 0, 0, 0, 0))
Forms.TCustomForm.WndProc(???)
Controls.TWinControl.MainWndProc(???)
Classes.StdWndProc(15992630,45089,0,0)
Forms.TApplication.ProcessMessage(???)
도움이 되었습니까?

해결책

에 대한 포인터 System.Monitor 각 객체의 인스턴스는 모든 데이터 필드 후에 저장됩니다. 객체의 마지막 필드에 너무 많은 데이터를 쓰면 모니터의 주소에 가짜 값을 쓸 수 있습니다. 이는 대상의 파괴자가 가짜 모니터를 파괴하려고 시도 할 때 충돌로 이어질 수 있습니다. 이 주소가 있는지 확인할 수 있습니다 nil 에서 BeforeDestruction 양식의 방법, 직선 델파이 5 포트의 경우 할당 된 모니터가 없어야합니다. 같은 것

procedure TForm1.BeforeDestruction;
var
  MonitorPtr: PPMonitor;
begin
  MonitorPtr := PPMonitor(Integer(Self) + InstanceSize - hfFieldSize + hfMonitorOffset);
  Assert(MonitorPtr^ = nil);
  inherited;
end;

원래 코드에서 문제가되는 경우 모든 검사가 활성화 된 FastMM4 메모리 관리자를 사용하여 DLL의 DLLI 버전에서이를 감지 할 수 있어야합니다. OTOH 이것은 또한 유니 코드 빌드에서 문자 데이터의 크기 증가로 인해 발생할 수 있으며,이 경우 Delphi 2009 또는 2010을 사용하여 DLL 빌드에서만 나타납니다. 모든 수표와 함께 최신 FastMM4를 사용하는 것이 좋습니다.

편집하다:

스택 추적에서 모니터가 실제로 할당 된 것처럼 보입니다. 데이터 중단 점을 사용하는 이유를 찾기 위해. 나는 그들이 Delphi 2009와 함께 일하게 할 수 없었지만 WindBG로 쉽게 할 수 있습니다.

에서 OnCreate 양식의 처리기는 다음을 말하십시오.

var
  MonitorPtr: PPMonitor;
begin
  MonitorPtr := PPMonitor(Integer(Self) + InstanceSize - hfFieldSize + hfMonitorOffset);
  MessageDlg(Format('MonitorPtr: %p', [pointer(MonitorPtr)]), mtInformation,
    [mbOK], 0);
  DebugBreak;
  // ...

이제 WindBG를로드하고 열기를 열고 DLL을 호출하는 프로세스를 실행하십시오. 양식이 생성되면 메시지 상자에 모니터 인스턴스의 주소가 표시됩니다. 주소를 기록하고 확인을 클릭하십시오. 디버거가 나타나고, 당신은 다음과 같이 해당 포인터에 대한 쓰기 액세스에 대한 중단 점을 설정합니다.

BA W4 A32D00

교체 A32D00 메시지 상자에서 올바른 주소로. 실행을 계속하면 모니터가 할당되면 디버거가 중단 점에 도달해야합니다. 다양한 디버거보기 (모듈, 스레드, 스택)를 사용하면 해당 주소에 쓰는 코드에 대한 중요한 정보가 얻을 수 있습니다.

다른 팁

유효하지 않은 포인터 작업은 프로그램이 포인터를 풀려고 시도했지만 세 가지 중 하나가 잘못되었습니다.

  • 다른 메모리 관리자가 할당했습니다.
  • 그것은 이미 한 번만 해방되었습니다.
  • 그것은 아무것도 할당되지 않았습니다.

여러 메모리 관리자가 할당 된 것 같지는 않습니다. TMonitor 기록, 그래서 우리는 첫 번째 가능성을 배제 할 수 있다고 생각합니다.

두 번째 가능성에 관해서는, 프로그램에 사용자 정의 파괴자가 없거나 파괴자에 메모리를 자유롭게하지 않는 클래스가있는 경우 해당 객체에 대한 첫 번째 실제 메모리 거래는 Tobject에있을 수 있습니다. 객체의 모니터를 해방합니다. 해당 클래스의 인스턴스가 있고 두 번 자유롭게하려는 경우, 그 문제는 tmonitor에서 예외의 형태로 나타날 수 있습니다. 프로그램에서 이중 무료 오류를 찾으십시오. 그만큼 Fastmm의 디버깅 옵션 당신을 도울 수 있습니다. 또한 그 예외를 얻을 때 전화 스택 Tmonitor의 소멸자에 어떻게 도착했는지 알아 내기 위해.

세 번째 가능성이 원인이라면 기억 부패가 있습니다. 객체의 크기에 대해 가정하는 코드가 있다면 원인이 될 수 있습니다. Tobject는 Delphi 2009에서 4 바이트가 더 큽니다. 항상 사용하십시오. InstanceSize 객체의 크기를 얻는 방법; 모든 필드의 크기를 추가하거나 마법 번호를 사용하지 마십시오.

스레드는 Outlook에 의해 생성된다고 말합니다. 당신은 설정 했습니까? IsMultithread 글로벌 변수? 프로그램은 일반적으로 스레드를 생성 할 때 true로 설정하지만 스레드를 만드는 스레드가 아닌 경우 기본 오 탐지 값으로 유지되며, 메모리 관리자가 할당 및 거래 중에 글로벌 데이터 구조를 보호 해야하는지에 영향을 미칩니다. . DPR 파일의 기본 프로그램 블록에서 true로 설정하십시오.

많은 파기 후 나는 내가 멋지게하고 있었다는 것이 밝혀졌다 (읽기 : 끔찍한, 끔찍한, 그러나 그것은 우리의 델파이 5 앱에서 연령을 올바르게하고 있습니다.)

PClass(TForm)^ := TMyOwnClass 

응용 프로그램 프레임 워크의 창자에 깊은 곳. 분명히 Delphi 2010은 현재 발생하지 않은 "모니터 필드"를 초기화하기 위해 일부 클래스 초기화를 가지고있어 RTL이 getfieldAddress가 비 널 값을 반환했기 때문에 RTL이 형식 파괴시 "Syncobject를 자유롭게 해제"하게 만들었습니다. 어.

이유 우리는 처음 에이 해킹을하고있었습니다. 왜냐하면 나는 모든 형태의 인스턴스에서 CreateParams를 자동으로 변경하여 상징적 인 재판용 양식을 달성하기를 원했기 때문입니다. RTL 브레이크 해킹 없이이 작업을 수행하는 방법에 대한 새로운 질문을 열 것입니다 (지금은 단순히 형태에 멋진 반짝이는 아이콘을 추가 할 것입니다).

나는 Mghie의 제안을 대답으로 표시 할 것입니다. 왜냐하면 그것은 매우 많은 통찰력을 저에게 (그리고이 스레드를 읽는 사람)을 제공했기 때문입니다. 기여해 주셔서 감사합니다!

델파이에는 두 개의 tmonitor가 있습니다.

  1. System.tmonitor; 레코드이며 스레드 동기화에 사용됩니다.
  2. 양식 .tmonitor; 첨부 된 모니터 (디스플레이 장치)를 나타내는 클래스입니다.

System.tmonitor는 Delphi 2009 이후 Delphi에 추가됩니다. 따라서 Delphi 5에서 코드를 포팅하는 경우 코드가 사용했던 것은 System.tmonitor가 아닌 Forms.tmonitor입니다.

클래스 이름은 코드에서 단위 이름없이 참조되어 혼란을 겪고 있다고 생각합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top