Skip to content

Conversation

@moorecj
Copy link
Contributor

@moorecj moorecj commented Jul 10, 2025

Bug: Instances of System.Threading.Timer can start a callback before the constructor of the Timer has returned. Particularly when the dueTime parameter is set to 0. In certain cases the timer attempts to dispose itself via its callback. This can cause exceptions that will crash the running app.

This was witnessed in the RtpIceChannel.CheckIceServers

Application: App.exe CoreCLR Version: 8.0.1124.51707 .NET Version: 8.0.11 Description: The process was terminated due to an unhandled exception. Exception Info: System.NullReferenceException: Object reference not set to an instance of an object. at SIPSorcery.Net.RtpIceChannel.CheckIceServers(Object state) in C:\Git\App\Common\sipsorcery\src\net\ICE\RtpIceChannel.cs:line 1184 at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state) --- End of stack trace from previous location --- at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.TimerQueueTimer.Fire(Boolean isThreadPool) at System.Threading.ThreadPoolWorkQueue.Dispatch() at System.Threading.PortableThreadPool.WorkerThread.WorkerThreadStart()

I created a simple app to illustrate the issue:
TimerIssue

The instances of the System.Threading.Timer have been changed to use the pattern of starting the timer after the contructor has returned. This ensures that the race is avoided.

…structor returns. Can cause exceptions that can't be caught and crash the running app.
@paulomorgado
Copy link
Contributor

paulomorgado commented Jul 10, 2025

@moorecj, that line of code in the exception is not a timer dispose. Is it?

My bad. Just noticed the version: 8.0.11

see https://github.com/sipsorcery-org/sipsorcery/blob/v8.0.11/src/net/ICE/RtpIceChannel.cs#L1184

@moorecj
Copy link
Contributor Author

moorecj commented Jul 10, 2025

@moorecj, that line of code in the exception is not a timer dispose. Is it?

My bad. Just noticed the version: 8.0.11

see https://github.com/sipsorcery-org/sipsorcery/blob/v8.0.11/src/net/ICE/RtpIceChannel.cs#L1184

Yeah I was on version 8.0.4 when I saw the error.
https://github.com/sipsorcery-org/sipsorcery/blob/v8.0.4/src/net/ICE/RtpIceChannel.cs#L1184

@sipsorcery
Copy link
Member

Thanks for the PR. I wasn't aware of that behaviour. Seems like a bit of a flaw in the Timer implementation.

@sipsorcery sipsorcery merged commit 1af44f8 into sipsorcery-org:master Jul 14, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants