Bug 3088 - Race condition when calling synchronized methods via ldftn and calli
Summary: Race condition when calling synchronized methods via ldftn and calli
Alias: None
Product: Runtime
Classification: Mono
Component: JIT ()
Version: unspecified
Hardware: PC Linux
: --- normal
Target Milestone: ---
Assignee: Bugzilla
Depends on:
Reported: 2012-01-26 06:59 UTC by Martin Daeumler
Modified: 2012-01-26 14:15 UTC (History)
3 users (show)

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

IL-code that creates two threads that call a synchronized method via "ldftn" and "calli" (4.25 KB, application/octet-stream)
2012-01-26 06:59 UTC, Martin Daeumler

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.

Please create a new report on GitHub or Developer Community with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:

Description Martin Daeumler 2012-01-26 06:59:20 UTC
Created attachment 1274 [details]
IL-code that creates two threads that call a synchronized method via "ldftn" and "calli"

In the test case, two threads are started. The threads execute the methods
"jumpStart1()" and "jumpStart2()", respectively. Those methods load a
pointer to the synchronized method "syncMethod()" via "ldftn". That
method is called via "calli" and it increments a static class variable
ten times. So, the expected output is "10" and "20", because the method
"syncMethod()" is synchronized. However, sometimes the output is
"10" and "10". I tested with

Mono-2.6.1 on x86 Linux
Mono-2.8.2 on x86 Linux
Mono- on x86 Linux
Mono-2.10.8 on Mac OS X

On .NET, it seems to work because in all test runs the output was "10"
and "20". The test case is compiled by "ilasm thread-ldftn.il" and
executed by "mono thread-ldftn.exe".

If I disable Mono-2.6.1's jump trampoline optimization in
"mono_create_jump_trampoline()", "mono_jit_compile_method_inner()"
and "mono_post_process_patches()" it seems to work correctly.

I guess, the problem is related to the runtime implementation of the
jump-opcode which is used by the ldftn-opcode: In "mono_postprocess_patches()",
the handle to the method jumped to is stored in the hash table
"jump_target_hash". When a synchronized method is jumped to the
first time, the magic trampoline creates a wrapper and returns
the address of the wrapper. The first jump instruction is patched
with that address.

A later lookup in the "jump_target_hash" ("mono_jit_compile_method_inner()",
in the scope of the JIT-compilation of the wrapper) doesn't return
pending jump patches because the handle of the method to be jumped
to of is stored, instead of the wrapper's handle. So, the second
jump instruction is not patched (if it is JIT-compiled so far).
Comment 1 Zoltan Varga 2012-01-26 14:15:16 UTC
Fixed in HEAD/2.10.