Bug 30146 - stack imbalance in DllImport with CallingConvention.StdCall
Summary: stack imbalance in DllImport with CallingConvention.StdCall
Alias: None
Product: Runtime
Classification: Mono
Component: General ()
Version: unspecified
Hardware: PC Windows
: --- normal
Target Milestone: ---
Assignee: Zoltan Varga
Depends on:
Reported: 2015-05-15 15:53 UTC by remirpan
Modified: 2017-11-15 15:06 UTC (History)
6 users (show)

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

test case (350 bytes, text/plain)
2016-08-01 21:57 UTC, Vincent Povirk

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 remirpan 2015-05-15 15:53:53 UTC

 the difference between FAIL() and PASS2() is CallingConvention.StdCall for FAIL() function.

 mono_arch_emit_epilog function for FAIL(0) uses x86_ret_imm(code, stack_to_pop), which gives "ret 4" and stack imbalance.

 mono_arch_emit_epilog function for PASS2(0) uses x86_ret(code), which gives the "ret".

 void mono_arch_emit_epilog (MonoCompile *cfg)
	if (stack_to_pop) {
		g_assert (need_stack_frame);
		x86_ret_imm (code, stack_to_pop); // when called FAIL(0)
	} else {
		x86_ret (code); // when called PASS2()


using System;
using System.Runtime.InteropServices;

class Program

	static void Main()
#if true // 0xC000005 demo
		for (int i = 0; i < 16; i++)
#else // stack overflow demo
		while (true)

	[DllImport("kernel32.dll", EntryPoint = "Sleep", CallingConvention = CallingConvention.StdCall)]
	static extern void FAIL (UInt32 ms);

	[DllImport("kernel32.dll", EntryPoint = "Sleep", CallingConvention = CallingConvention.Winapi)]
	static extern void PASS1 (UInt32 ms);

	[DllImport("kernel32.dll", EntryPoint = "Sleep")]
	static extern void PASS2 (UInt32 ms);


Comment 1 Vincent Povirk 2016-08-01 21:56:08 UTC
I found a version that didn't have this bug, and then bisected it. The first bad commit was:

commit 7968a8df1674a6e2aa8990faaca3c426efc2e279
Author: Zoltan Varga <vargaz@gmail.com>
Date:   Mon Sep 29 13:01:41 2014 -0400

    [x86] Reenable the no pushes code again.
Comment 2 Vincent Povirk 2016-08-01 21:57:27 UTC
Created attachment 16853 [details]
test case

Here's a test case for any x86 platform (not just Windows).
Comment 3 Ludovic Henry 2017-11-10 21:23:58 UTC
Hi, can you still reproduce with Mono (2017-06/e66d9abbb27) (https://dl.xamarin.com/MonoFrameworkMDK/Macx86/MonoFramework-MDK- I tried on macOS and couldn't reproduce it, so it might be a Windows specific bug.
Comment 4 Vincent Povirk 2017-11-13 20:27:29 UTC
I'm not able to reproduce this on current Mono. I tried, which was the latest build on the website, and my own build from the master branch.
Comment 5 Ludovic Henry 2017-11-15 15:06:24 UTC
Please reopen if you can reproduce with a later Mono version than 5.4. Thank you