Bug 16808 - ThreadAbortException. Finally block does not execute
Summary: ThreadAbortException. Finally block does not execute
Alias: None
Product: Runtime
Classification: Mono
Component: JIT (show other bugs)
Version: 3.2.x
Hardware: PC Linux
: --- normal
Target Milestone: ---
Assignee: Zoltan Varga
Depends on:
Reported: 2013-12-15 15:46 UTC by Sergey Zhukov
Modified: 2016-09-18 16:58 UTC (History)
6 users (show)

See Also:
Is this bug a regression?: ---
Last known good build:

OrphanedLocksTest (2.25 KB, text/x-csharp)
2013-12-15 15:46 UTC, Sergey Zhukov

Description Sergey Zhukov 2013-12-15 15:46:09 UTC
Created attachment 5665 [details]

According to MSDN:
When a call is made to the Abort method to destroy a thread, the common language runtime throws a ThreadAbortException. ThreadAbortException is a special exception that can be caught, but it will automatically be raised again at the end of the catch block. When this exception is raised, the runtime executes all the finally blocks before ending the thread. Because the thread can do an unbounded computation in the finally blocks or call Thread.ResetAbort to cancel the abort, there is no guarantee that the thread will ever end. If you want to wait until the aborted thread has ended, you can call the Thread.Join method. Join is a blocking call that does not return until the thread actually stops executing.
The key phrase: "When this exception is raised, the runtime executes all the finally blocks before ending the thread."

I wrote simple test to check if it works correctly in mono and could be used for properly locking. When I run it after few minutes application gets in deadlock, the output is varies from time to time. In one time, I can get following output:

Aborted read b1=True, b2=True, b3=True, b4=False, s2=True
Aborted write b1=True, b2=False, b3=False, b4=False, s2=True

What means, that first finally block was not executed, while second was.

Or I can get:
Aborted read b1=True, b2=True, b3=True, b4=False, s2=False

What means, that first finally block was executed, while second was not.

But b1,b2 and s2 must always be 'True' if all finally blocks are executed properly.

Such random looks very strange. 

Mono Runtime Engine version 3.2.7 (master/01b7a50 Sat Dec 14 01:48:49 NOVT 2013)
Copyright (C) 2002-2013 Novell, Inc, Xamarin Inc and Contributors. www.mono-project.com
	TLS:           __thread
	SIGSEGV:       altstack
	Notifications: epoll
	Architecture:  x86
	Disabled:      none
	Misc:          softdebug 
	LLVM:          yes(3.4svn-mono-mono/e656cac)
	GC:            sgen
Comment 1 Sergey Zhukov 2013-12-15 15:58:49 UTC
You can decrease Thread.Sleep() time from 500 to 100 ms, to get the deadlock faster.

And one more thing:

In most cases you won't get a phrase "Gotcha!" on your screen, seems that timeout for TryEnterReadLock does not work correctly.
Comment 2 Zoltan Varga 2013-12-21 23:43:28 UTC
The testcase is racy, for example, the thread abort request could arrive when the thread is in the second finalizer, but before it executes the b4=true; line.
Comment 3 Sergey Zhukov 2013-12-22 04:29:26 UTC
I'm not sure the last comment is a confirmation of the bug or rejection, so want to mention, if ThreadAbortException is raised in second finally block before b4=true, runtime must execute all statements in the finally block and only after that pass execution flow to catch(ThreadAbortException) block. See remarks for ThreadAbortException class in msdn
Comment 4 Sergey Zhukov 2013-12-22 21:50:45 UTC
And msdn documentation of Thread.Abort method:


The thread is not guaranteed to abort immediately, or at all. This situation can occur if a thread does an unbounded amount of computation in the finally blocks that are called as part of the abort procedure, thereby indefinitely delaying the abort. To wait until a thread has aborted, you can call the Join method on the thread after calling the Abort method, but there is no guarantee that the wait will end.


The thread that calls Abort might block if the thread that is being aborted is in a protected region of code, such as a catch block, finally block, or constrained execution region.  
Comment 5 Sergey Zhukov 2013-12-22 23:30:48 UTC
And the code above does not deadlock on MS .NET
Comment 6 Zoltan Varga 2014-01-05 18:51:40 UTC
This is yet another async bug. When the testcase is aot-ed, it randomly crashes because 
the implementation of OP_ATOMIC_ADD_NEW_I4 uses callee-saved regs as temporary regs by push-ing and pop-ing them. If the thread is interrupted in the middle of this code sequence, the unwinder will use
the ebx value set by the code sequence instead of the original pushed value.
Comment 7 pr0vieh 2016-09-18 16:58:31 UTC
not sure if related to this Bug report

at shutdown i get randomly this Stacktrace @mono Master

 Failed to close connection: System.Threading.ThreadAbortException
  at System.Net.HttpWebRequest.Abort () <0x7f61f82507e0 + 0x00309> in <76b6376638884822b2efb587630d5b7e#2bbc429d4f85cbdaecb5d0cb86d630de>:0
  at mytool.WebCrawlerWorker.CloseConnection () <0x7f61f29f2280 + 0x00022> in <630e3cc849c549498c690f2b568f83e5#2bbc429d4f85cbdaecb5d0cb86d630de>:0
 Status: FinishedSystem.Threading.ThreadAbortException
  at mytool.WebCrawler.Crawl () [0x007cb] in <630e3cc849c549498c690f2b568f83e5>:0

* Assertion at aot-runtime.c:2897, condition `!async' not met


* Assertion at mini-exceptions.c:955, condition `unwind_options == MONO_UNWIND_NONE' not met

any news about this ?

Note You need to log in before you can comment on or make changes to this bug.