2012-09-24 34 views
6

Đây là một ứng dụng Delphi, nhưng tôi cho rằng đó là một câu hỏi chung về lập trình Windows.Tôi không hiểu lỗi tràn ngăn xếp với DispatchMessageW lặp lại trong ngăn xếp cuộc gọi

Tôi đã để ứng dụng của mình chạy (trong IDE Delphi) vào cuối tuần và vừa trở lại để tìm thấy tràn ngăn xếp.

Các ngăn xếp bắt đầu như thế này ...

:75c4417e kernel32.GetDriveTypeW + 0x23 
:75c452ae kernel32.IsProcessorFeaturePresent + 0xa9 
:75c45272 kernel32.IsProcessorFeaturePresent + 0x6d 
:75c45248 kernel32.IsProcessorFeaturePresent + 0x43 
:7678410b KERNELBASE.LoadStringBaseExW + 0xc7 
:76678ed2 USER32.LoadStringW + 0x19 
:0040c4ae LoadResString + $4A 
uADStanDef.TADDefinition.Create(nil) 
uADStanDef.TADDefinition.CreateTemporary 
uADStanDef.TADConnectionDefTemporaryFactory.CreateObject 
uADStanFactory.TADManager.CreateInterface((1050358107, 62550, 16757, (168, 100, 178, 87, 60, 74, 32, 21)),(no value),True) 
uADStanFactory.ADCreateInterface((1050358107, 62550, 16757, (168, 100, 178, 87, 60, 74, 32, 21)),(no value),True) 
uADCompClient.TADCustomConnection.Create($2DB7EB0) 
fMainForm.TMainForm.ServerAliveTimerTimer($2E8DE38) <========== my code 
:004f1546 Winapi + $4F1546 
:00461316 Winapi + $461316 
:766762fa ; C:\Windows\syswow64\USER32.dll 
:76676d3a USER32.GetThreadDesktop + 0xd7 
:766777c4 ; C:\Windows\syswow64\USER32.dll 
:7667788a USER32.DispatchMessageW + 0xf 

Vì vậy, một bộ đếm thời gian hết hạn, tôi đang tạo ra một đối tượng mới (của một thành phần AnyDac) và tràn stack. Mã chắc chắn giải phóng đối tượng. Tôi đã gắn nó dưới đây cho những người muốn kiểm tra, nhưng tôi không nghĩ rằng đó là câu hỏi của tôi.

Các ngăn xếp sau đó tiếp tục

:7669cdfd ; C:\Windows\syswow64\USER32.dll 
:7669cf5c ; C:\Windows\syswow64\USER32.dll 
:766cf73c ; C:\Windows\syswow64\USER32.dll 
:766cfa18 ; C:\Windows\syswow64\USER32.dll 
:766cfb1f USER32.MessageBoxTimeoutW + 0x52 
:766cfd15 USER32.MessageBoxExW + 0x1b 
:766cfd57 USER32.MessageBoxW + 0x18 
:00549986 Vcl + $549986 
:00549aa2 Vcl + $549AA2 
:00549873 Vcl + $549873 
:00461316 Winapi + $461316 
:766762fa ; C:\Windows\syswow64\USER32.dll 
:76676d3a USER32.GetThreadDesktop + 0xd7 
:766777c4 ; C:\Windows\syswow64\USER32.dll 
:7667788a USER32.DispatchMessageW + 0xf 

Với khối đó lặp lại đối với ba thoussand dòng (!) Và tôi không có ý tưởng đó là gì hay những gì nó đang làm. Sau đó, nó kết thúc

StoreRoom.StoreRoom 
:75c4339a kernel32.BaseThreadInitThunk + 0x12 
:77eb9ef2 ntdll.RtlInitializeExceptionChain + 0x63 
:77eb9ec5 ntdll.RtlInitializeExceptionChain + 0x36 

Tôi không hiểu được tất cả các ngăn xếp lặp lại - bất kỳ ai có thể tư vấn?

(Và đối với astutute bạn của những người nhận thấy rằng xử lý ngoại lệ của tôi đang hiển thị một hộp thoại, đó là một TForm mà đóng cửa khi người dùng nhấp OK)

Mã của tôi:

procedure TMainForm.ServerAliveTimerTimer(Sender: TObject); 
begin 
    try 
     ADConnection := TADConnection.Create(Self); <======= stack overflow here 
     ADConnection.DriverName := 'mysql'; 
     ADConnection.Params.Add('Server=' + MAIN_STOREROOM_IP_ADDRESS); 
     // other params, such as password, removed for posting 
     ADConnection.Connected := True; 

    except 
     on E : Exception do 
     begin 
     ADConnection.Free(); 
     theDialogForm := TDialogFormForm.Create(Nil); 
     theDialogForm.ShowTheForm('Database problem'+#13+#10+''+#13+#10+ 
            E.ClassName+#13+#10+E.Message);  
     StopTheApplication(); <===== just calls ExitProcess(0); 
     Exit;      as I had problems with Halt elsewhere in the code 
     end; 
    end; 

    if isMainStoreRoom then 
    begin 
     CheckIfStoreRoomIsAlive(SECONDARY_STOREROOM_IP_ADDRESS); 
    end 
    else 
    begin 
     CheckIfStoreRoomIsAlive(MAIN_STOREROOM_IP_ADDRESS); 
    end; 

    try // Now, update our own timestamp 
     timestamp := GetCurrentUnixTimeStamp(); 
     ADConnection.ExecSQL('UPDATE server_status SET alive_timestamp="' + IntToStr(timestamp) + '" WHERE ip_address="' + ipAddress + '"'); 

    except 
     on E : Exception do 
     begin 
     ADConnection.Free(); 
     Exit; 
     end; 
    end; 

    ADConnection.Free(); 
end;  // ServerAliveTimerTimer() 
+4

+1 cho câu hỏi tràn ngăn xếp về tràn ngăn xếp. – lkessler

+2

Tại sao bạn cần phải tạo một lớp kết nối mọi lúc thay vì sử dụng ADConnection.Connected True/False? Cài đặt kết nối cơ sở dữ liệu có thay đổi khi chạy không? – pani

+0

Câu hỏi được đặt tên là "Tôi không hiểu stackoverflow", nhưng có ai đó đã chỉnh sửa nó (+1 cho tất cả các người) – Mawg

Trả lời

15

ngăn xếp của bạn tràn là do MessageBox() được gọi là hơn và hơn và hơn để đáp ứng với một thông báo cửa sổ lặp lại. Bên trong, MessageBox() chạy vòng lặp tin nhắn của riêng nó, rõ ràng là đang xử lý và gửi đi cùng một thông điệp. Điều đó có thể chỉ ra một bộ đếm thời gian đã đi lạc lối. Tôi thực sự khuyên bạn nên tắt bộ hẹn giờ khi lần đầu tiên bạn nhập trình xử lý sự kiện OnTimer và sau đó bật lại bộ hẹn giờ trước khi thoát.

Trên ghi chú riêng, StopTheApplication() KHÔNG được gọi trực tiếp ExitProcess() (hoặc thậm chí Halt()). Sử dụng Application.Terminate() để thay thế.

+0

+1 Cảm ơn, @Remy. Tôi đã không đề cập đến việc tôi đã chạy trong IDE. Các cuộc gọi đến MessageBox() có được từ đó không? Tôi không gọi nó chút nào. Tôi gọi MessageDlg(), nhưng không phải trong bất kỳ bộ xử lý hẹn giờ - trong những người tôi tạo và hiển thị một biểu mẫu lỗi tùy chỉnh. Tôi chỉ có ba bộ đếm thời gian và mã xử lý cho hai bộ kia ngắn hơn số tôi đã đăng. Tôi lấy ý kiến ​​của bạn về việc tắt/bật hẹn giờ, nhưng ngắn nhất (hiển thị) là 8 giây. Một vài truy cập d/b không thể mất 8 giây. – Mawg

+0

Chờ ... Tôi không gọi MessageBox(), nhưng có lẽ mã AnyDac, nếu có lỗi cơ sở dữ liệu ... nhưng, thậm chí sau đó, tại sao nó sẽ được lặp? AnyDac hiện đã được kiểm tra tốt.Tôi sẽ cung cấp cho nó một chạy với bộ đếm thời gian vô hiệu hóa/kích hoạt mã trong và sẽ rút ngắn thời gian hẹn giờ để cố gắng đẩy nhanh vấn đề nếu nó xảy ra một lần nữa – Mawg

+2

'MessageBox()' có thể được gọi bởi 'Application.MessageBox()' vì nó đang được gọi bởi một số đoạn mã VCL trong ngăn xếp cuộc gọi. 'Application.MessageBox()' đôi khi được gọi bởi các trình xử lý ngoại lệ, ví dụ. Khó nói vì ngăn xếp cuộc gọi của bạn không hiển thị tên hàm của VCL. Bạn đang biên dịch cho bản phát hành thay vì gỡ lỗi? Trong mọi trường hợp, bất cứ điều gì gọi là 'MessageBox()' rõ ràng là không được viết để reentrant và đang bị mắc kẹt trong một vòng lặp đệ quy, đẩy ngày càng nhiều dữ liệu vào ngăn xếp với mỗi cuộc gọi lồng vào 'MessageBox()' cho đến khi tràn ngăn xếp . –

Các vấn đề liên quan