wiz0u / WTelegramClient

Telegram Client API (MTProto) library written 100% in C# and .NET
https://wiz0u.github.io/WTelegramClient/
MIT License
956 stars 156 forks source link

Since version 4.1.5 WTC throws Stackoverflow exception when disposing the client #274

Closed call-eax closed 1 month ago

call-eax commented 1 month ago

When upgrading from 4.1.4 to 4.1.5 (and also 4.1.6) my winforms application crashes with a Stackoverflow exception when closing. The FormClosing event disposes the WTC client which in turn enters into an infinite recursion causing the Stackoverflow. The application allows me to easily download media and images without having to do so manually in the official client.

I managed to debug into WTC source, the infinite recursion happens here: https://github.com/wiz0u/WTelegramClient/blob/e5c6086e1199c947131c2ef44b526ef51501cd67/src/Client.cs#L229

The expression https://github.com/wiz0u/WTelegramClient/blob/e5c6086e1199c947131c2ef44b526ef51501cd67/src/Client.cs#L227 is always true for one of the (in my case 6) _session.DCSessions.Values in every iteration. The exeption is only thrown when a download has been performed before. If I start the application and immediately close it without downloading anything, no exception is thrown. The error does not happen with every download, just with some. I presume this is caused by the recently added download acceleration into WTC #261 and, as I understand it, the DCs vary depending on where the user's account has been initially created. I can provide a channel where the download of a media file causes the above behaviour for me, if needed.

grafik

grafik

call-eax commented 1 month ago

Forgot the logs:

2024-08-01 15:24:02 [D] 2>Receiving RpcResult                                2024-08-01 19:24:01Z
2024-08-01 15:24:02 [D]              → Upload_File                           #FE8D
2024-08-01 15:24:02 [D] 2>Receiving MsgsAck                                  2024-08-01 19:24:01Z (svc) 
2024-08-01 15:24:02 [D] 2>Receiving RpcResult                                2024-08-01 19:24:01Z
2024-08-01 15:24:02 [D]              → Upload_File                           #2DC9
2024-08-01 15:24:02 [D] 2>Receiving RpcResult                                2024-08-01 19:24:01Z
2024-08-01 15:24:02 [D]              → Upload_File                           #4DB1
2024-08-01 15:24:05 [I] 2>Disposing the client
2024-08-01 15:24:05 [D] 2>Sending   MsgsAck                                  2024-08-01 19:24:05Z (svc)
2024-08-01 15:24:07 [I] 2>Disposing the client
2024-08-01 15:24:07 [D] 2>Sending   MsgsAck                                  2024-08-01 19:24:07Z (svc)
2024-08-01 15:24:09 [I] 2>Disposing the client
2024-08-01 15:24:09 [I] 2>Disposing the client
2024-08-01 15:24:09 [I] 2>Disposing the client
.
.
.
The last line repeats over 6000 times
wiz0u commented 1 month ago

Thanks, I'm looking at it now

wiz0u commented 1 month ago

Make sure you include here all useful things that you've discussed in the group, so I don't have to search through your chat messages.

call-eax commented 1 month ago

Make sure you include here all useful things that you've discussed in the group

Sure, this is part of my code: Forms app:

private async void bLogin_Click(object sender, EventArgs e)
{
  var t = GetTelephone();
  if (string.IsNullOrEmpty(t)) return;
  tgAPI = new TelegramAPI(t);
  tgAPI.GetSecurityCodeMethod += TgAPI_GetSecurityCode;
  tgAPI.Get2FACodeMethod += TgAPI_GetSecurity2FAMethod;
  tgAPI.OnOtherMethod += TgAPI_OnOtherMethod;
  tgAPI.InitLogs();
  try
  {
    IsLoggedIn = await tgAPI?.Login();
  }
  catch (Exception ex)
  {
    MessageBox.Show("Telegram sagt: " + ex.Message);
  }
}
private void TDForm_FormClosing(object sender, FormClosingEventArgs e)
{
  tgAPI.GetSecurityCodeMethod -= TgAPI_GetSecurityCode;
  tgAPI.Get2FACodeMethod -= TgAPI_GetSecurity2FAMethod;
  tgAPI.OnOtherMethod -= TgAPI_OnOtherMethod;
  tgAPI?.Dispose();
}

Wrapper around WTC:

public void Dispose()
{
  try
  {
    Client?.Dispose();
    if (WTelegramLogs.BaseStream != null)
    {
      WTelegramLogs?.Flush();
      WTelegramLogs?.Close();
    }
    SessionStore.Dispose();
  }
  catch (Exception ex)
  {
  }
}
public async Task<bool> Login()
{
  Myself = await Task.Run(() => Client.LoginUserIfNeeded());
  Debug.WriteLine($"User: {Myself.first_name} {Myself.last_name} Hash: {Myself.access_hash} ID: {Myself.ID}");
  Dialogs = await Client.Messages_GetAllDialogs();
  Users[Myself.ID] = Myself;
  Dialogs.CollectUsersChats(Users, Chats);
  Client.OnUpdate += Client_OnUpdate;
  return Myself != null;
}
public TelegramAPI(string telephone)
{
  _telephone = telephone;
  SessionStore = InitSessionStore();
  Client = new Client(Config, SessionStore);
  TheClient = Client;

  string folder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), AppPath);
  logLocation = Path.Combine(folder, "WTelegram.log");
  WTelegramLogs = new StreamWriter(logLocation, true, Encoding.UTF8) { AutoFlush = true };
  Client.OnOther += Client_OnOther;

  Filter = string.Empty;
#if DEBUG
  Client.PingInterval = 300;
#endif
}

public void InitLogs()
{
  WTelegram.Helpers.Log = (lvl, str) => WTelegramLogs.WriteLine($"{DateTime.Now:yyyy-MM-dd HH:mm:ss} [{"TDIWE!"[lvl]}] {str}");
}

Visual Studio's call stack window:

    [Managed to Native Transition]  
    mscorlib.dll!System.IO.FileStream.WriteFileNative(Microsoft.Win32.SafeHandles.SafeFileHandle handle, byte[] bytes, int offset, int count, System.Threading.NativeOverlapped* overlapped, out int hr) Line 2570  C#
    mscorlib.dll!System.IO.FileStream.WriteCore(byte[] buffer, int offset, int count) Line 1846 C#
    mscorlib.dll!System.IO.FileStream.FlushInternalBuffer() Line 1339   C#
    mscorlib.dll!System.IO.FileStream.Flush(bool flushToDisk) Line 1329 C#
    mscorlib.dll!System.IO.FileStream.Flush() Line 1319 C#
    mscorlib.dll!System.IO.StreamWriter.Flush(bool flushStream, bool flushEncoder) Line 321 C#
    mscorlib.dll!System.IO.StreamWriter.Write(char[] buffer, int index, int count) Line 418 C#
    mscorlib.dll!System.IO.TextWriter.WriteLine(string value) Line 485  C#
>   TGDownloader.exe!TGDownloader.Telegram.TelegramAPI.InitLogs.AnonymousMethod__21_0(int lvl, string str) Line 110 C#
    WTelegramClient.dll!WTelegram.Client.Dispose() Line 183 C#
    WTelegramClient.dll!WTelegram.Client.Reset(bool resetUser, bool resetSessions) Line 230 C#
    WTelegramClient.dll!WTelegram.Client.Dispose() Line 184 C#
    [The 2 frame(s) above this were repeated 6224 times]    
    System.Windows.Forms.dll!System.Windows.Forms.Form.OnFormClosing(System.Windows.Forms.FormClosingEventArgs e)   Unknown
    System.Windows.Forms.dll!System.Windows.Forms.Form.WmClose(ref System.Windows.Forms.Message m)  Unknown
    System.Windows.Forms.dll!System.Windows.Forms.Form.WndProc(ref System.Windows.Forms.Message m)  Unknown
    System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.OnMessage(ref System.Windows.Forms.Message m) Unknown
    System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.WndProc(ref System.Windows.Forms.Message m)   Unknown
    System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.DebuggableCallback(System.IntPtr hWnd, int msg, System.IntPtr wparam, System.IntPtr lparam)  Unknown
    [Native to Managed Transition]  
    [Managed to Native Transition]  
    System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.DefWndProc(ref System.Windows.Forms.Message m)   Unknown
    System.Windows.Forms.dll!System.Windows.Forms.Form.DefWndProc(ref System.Windows.Forms.Message m)   Unknown
    System.Windows.Forms.dll!System.Windows.Forms.Control.WndProc(ref System.Windows.Forms.Message m)   Unknown
    System.Windows.Forms.dll!System.Windows.Forms.ScrollableControl.WndProc(ref System.Windows.Forms.Message m) Unknown
    System.Windows.Forms.dll!System.Windows.Forms.ContainerControl.WndProc(ref System.Windows.Forms.Message m)  Unknown
    System.Windows.Forms.dll!System.Windows.Forms.Form.WmSysCommand(ref System.Windows.Forms.Message m) Unknown
    System.Windows.Forms.dll!System.Windows.Forms.Form.WndProc(ref System.Windows.Forms.Message m)  Unknown
    System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.OnMessage(ref System.Windows.Forms.Message m) Unknown
    System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.WndProc(ref System.Windows.Forms.Message m)   Unknown
    System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.DebuggableCallback(System.IntPtr hWnd, int msg, System.IntPtr wparam, System.IntPtr lparam)  Unknown
    [Native to Managed Transition]  
    [Managed to Native Transition]  
    System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.DefWndProc(ref System.Windows.Forms.Message m)   Unknown
    System.Windows.Forms.dll!System.Windows.Forms.Form.DefWndProc(ref System.Windows.Forms.Message m)   Unknown
    System.Windows.Forms.dll!System.Windows.Forms.Control.WndProc(ref System.Windows.Forms.Message m)   Unknown
    System.Windows.Forms.dll!System.Windows.Forms.ScrollableControl.WndProc(ref System.Windows.Forms.Message m) Unknown
    System.Windows.Forms.dll!System.Windows.Forms.ContainerControl.WndProc(ref System.Windows.Forms.Message m)  Unknown
    System.Windows.Forms.dll!System.Windows.Forms.Form.WmNcButtonDown(ref System.Windows.Forms.Message m)   Unknown
    System.Windows.Forms.dll!System.Windows.Forms.Form.WndProc(ref System.Windows.Forms.Message m)  Unknown
    System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.OnMessage(ref System.Windows.Forms.Message m) Unknown
    System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.WndProc(ref System.Windows.Forms.Message m)   Unknown
    System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.DebuggableCallback(System.IntPtr hWnd, int msg, System.IntPtr wparam, System.IntPtr lparam)  Unknown
    [Native to Managed Transition]  
    [Managed to Native Transition]  
    System.Windows.Forms.dll!System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(System.IntPtr dwComponentID, int reason, int pvLoopData)  Unknown
    System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(int reason, System.Windows.Forms.ApplicationContext context)    Unknown
    System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoop(int reason, System.Windows.Forms.ApplicationContext context) Unknown
    System.Windows.Forms.dll!System.Windows.Forms.Application.Run(System.Windows.Forms.Form mainForm)   Unknown
    TGDownloader.exe!TGDownloader.Program.Main() Line 19    C#
wiz0u commented 1 month ago

Thank you very much. Can you confirm it's fixed in 4.7.1-dev.1 ?

call-eax commented 1 month ago

Can you confirm it's fixed in 4.7.1-dev.1 Yes, it's fixed! I checked all my downloads that led to this exception and the client gets disposed properly now! Thank you wiz0u!