Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--man/mono.16
-rw-r--r--mono/metadata/marshal.c2
-rw-r--r--mono/metadata/marshal.h1
-rw-r--r--mono/mini/aot-compiler.c2
-rw-r--r--mono/mini/cpu-x86.md2
-rw-r--r--mono/mini/method-to-ir.c36
-rw-r--r--mono/mini/mini-ops.h3
-rw-r--r--mono/mini/mini-x86.c6
-rw-r--r--mono/mini/mini.c5
-rw-r--r--mono/mini/mini.h9
-rw-r--r--mono/tests/libtest.c12
-rw-r--r--mono/tests/pinvoke2.cs20
12 files changed, 100 insertions, 4 deletions
diff --git a/man/mono.1 b/man/mono.1
index 74cbb7dbb8b..99be6c4f23b 100644
--- a/man/mono.1
+++ b/man/mono.1
@@ -1534,6 +1534,12 @@ after a SIGSEGV or SIGABRT in unmanaged code.
This option will suspend the program when a native SIGSEGV is received.
This is useful for debugging crashes which do not happen under gdb,
since a live process contains more information than a core file.
+.TP
+\fBcheck-pinvoke-callconv\fR
+This option causes the runtime to check for calling convention
+mismatches when using pinvoke, i.e. mixing cdecl/stdcall. It only
+works on windows. If a mismatch is detected, an
+ExecutionEngineException is thrown.
.ne
.RE
.TP
diff --git a/mono/metadata/marshal.c b/mono/metadata/marshal.c
index 792a1dcf37e..f7b8f98b5ea 100644
--- a/mono/metadata/marshal.c
+++ b/mono/metadata/marshal.c
@@ -9044,7 +9044,7 @@ mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions,
mb, csig, csig->param_count + 16);
mono_mb_free (mb);
- info = mono_wrapper_info_create (res, WRAPPER_SUBTYPE_NONE);
+ info = mono_wrapper_info_create (res, WRAPPER_SUBTYPE_PINVOKE);
info->d.managed_to_native.method = method;
mono_marshal_set_wrapper_info (res, info);
diff --git a/mono/metadata/marshal.h b/mono/metadata/marshal.h
index a5e45ee0d7a..a85bd5d26fb 100644
--- a/mono/metadata/marshal.h
+++ b/mono/metadata/marshal.h
@@ -104,6 +104,7 @@ typedef enum {
/* Subtypes of MONO_WRAPPER_MANAGED_TO_NATIVE */
WRAPPER_SUBTYPE_ICALL_WRAPPER,
WRAPPER_SUBTYPE_NATIVE_FUNC_AOT,
+ WRAPPER_SUBTYPE_PINVOKE,
/* Subtypes of MONO_WRAPPER_UNKNOWN */
WRAPPER_SUBTYPE_SYNCHRONIZED_INNER,
WRAPPER_SUBTYPE_GSHAREDVT_IN,
diff --git a/mono/mini/aot-compiler.c b/mono/mini/aot-compiler.c
index 8fb6c47d5a2..9f50e95b128 100644
--- a/mono/mini/aot-compiler.c
+++ b/mono/mini/aot-compiler.c
@@ -2655,7 +2655,7 @@ encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8
} else if (info->subtype == WRAPPER_SUBTYPE_NATIVE_FUNC_AOT) {
encode_method_ref (acfg, info->d.managed_to_native.method, p, &p);
} else {
- g_assert (info->subtype == WRAPPER_SUBTYPE_NONE);
+ g_assert (info->subtype == WRAPPER_SUBTYPE_NONE || info->subtype == WRAPPER_SUBTYPE_PINVOKE);
encode_method_ref (acfg, info->d.managed_to_native.method, p, &p);
}
break;
diff --git a/mono/mini/cpu-x86.md b/mono/mini/cpu-x86.md
index 1d7197f7392..b239ed0e765 100644
--- a/mono/mini/cpu-x86.md
+++ b/mono/mini/cpu-x86.md
@@ -634,3 +634,5 @@ gc_liveness_def: len:0
gc_liveness_use: len:0
gc_spill_slot_liveness_def: len:0
gc_param_slot_liveness_def: len:0
+get_sp: dest:i len:6
+set_sp: src1:i len:6
diff --git a/mono/mini/method-to-ir.c b/mono/mini/method-to-ir.c
index a83d01abe95..9024af39d73 100644
--- a/mono/mini/method-to-ir.c
+++ b/mono/mini/method-to-ir.c
@@ -2571,13 +2571,31 @@ inline static MonoInst*
mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
{
MonoCallInst *call;
+ MonoInst *ins;
int rgctx_reg = -1;
+ gboolean check_sp = FALSE;
+
+ if (cfg->check_pinvoke_callconv && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
+ WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
+
+ if (info && info->subtype == WRAPPER_SUBTYPE_PINVOKE)
+ check_sp = TRUE;
+ }
if (rgctx_arg) {
rgctx_reg = mono_alloc_preg (cfg);
MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
}
+ if (check_sp) {
+ if (!cfg->stack_inbalance_var)
+ cfg->stack_inbalance_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
+
+ MONO_INST_NEW (cfg, ins, OP_GET_SP);
+ ins->dreg = cfg->stack_inbalance_var->dreg;
+ MONO_ADD_INS (cfg->cbb, ins);
+ }
+
call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
call->inst.sreg1 = addr->dreg;
@@ -2587,6 +2605,24 @@ mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, Mo
MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
+ if (check_sp) {
+ int sp_reg;
+
+ sp_reg = mono_alloc_preg (cfg);
+
+ MONO_INST_NEW (cfg, ins, OP_GET_SP);
+ ins->dreg = sp_reg;
+ MONO_ADD_INS (cfg->cbb, ins);
+
+ /* Restore the stack so we don't crash when throwing the exception */
+ MONO_INST_NEW (cfg, ins, OP_SET_SP);
+ ins->sreg1 = cfg->stack_inbalance_var->dreg;
+ MONO_ADD_INS (cfg->cbb, ins);
+
+ MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, cfg->stack_inbalance_var->dreg, sp_reg);
+ MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ExecutionEngineException");
+ }
+
if (rgctx_arg)
set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
diff --git a/mono/mini/mini-ops.h b/mono/mini/mini-ops.h
index c9cec9f7cc6..59011ebccd3 100644
--- a/mono/mini/mini-ops.h
+++ b/mono/mini/mini-ops.h
@@ -1245,3 +1245,6 @@ MINI_OP(OP_LLVM_OUTARG_VT, "llvm_outarg_vt", IREG, VREG, NONE)
MINI_OP(OP_OBJC_GET_SELECTOR, "objc_get_selector", IREG, NONE, NONE)
+MINI_OP(OP_GET_SP, "get_sp", IREG, NONE, NONE)
+MINI_OP(OP_SET_SP, "set_sp", NONE, IREG, NONE)
+
diff --git a/mono/mini/mini-x86.c b/mono/mini/mini-x86.c
index 3d9863e868a..d34fc64190b 100644
--- a/mono/mini/mini-x86.c
+++ b/mono/mini/mini-x86.c
@@ -5039,6 +5039,12 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
ins->backend.pc_offset = code - cfg->native_code;
bb->spill_slot_defs = g_slist_prepend_mempool (cfg->mempool, bb->spill_slot_defs, ins);
break;
+ case OP_GET_SP:
+ x86_mov_reg_reg (code, ins->dreg, X86_ESP, sizeof (mgreg_t));
+ break;
+ case OP_SET_SP:
+ x86_mov_reg_reg (code, X86_ESP, ins->sreg1, sizeof (mgreg_t));
+ break;
default:
g_warning ("unknown opcode %s\n", mono_inst_name (ins->opcode));
g_assert_not_reached ();
diff --git a/mono/mini/mini.c b/mono/mini/mini.c
index 616d696b95b..941ced81111 100644
--- a/mono/mini/mini.c
+++ b/mono/mini/mini.c
@@ -4990,6 +4990,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl
cfg->gen_seq_points = debug_options.gen_seq_points;
cfg->explicit_null_checks = debug_options.explicit_null_checks;
cfg->soft_breakpoints = debug_options.soft_breakpoints;
+ cfg->check_pinvoke_callconv = debug_options.check_pinvoke_callconv;
if (try_generic_shared)
cfg->generic_sharing_context = (MonoGenericSharingContext*)&cfg->gsctx;
cfg->compile_llvm = try_llvm;
@@ -6985,9 +6986,11 @@ mini_parse_debug_options (void)
debug_options.better_cast_details = TRUE;
else if (!strcmp (arg, "soft-breakpoints"))
debug_options.soft_breakpoints = TRUE;
+ else if (!strcmp (arg, "check-pinvoke-callconv"))
+ debug_options.check_pinvoke_callconv = TRUE;
else {
fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
- fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'reverse-pinvoke-exceptions', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace', 'dont-free-domains', 'suspend-on-sigsegv', 'suspend-on-exception', 'suspend-on-unhandled', 'dyn-runtime-invoke', 'gdb', 'explicit-null-checks', 'init-stacks'\n");
+ fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'reverse-pinvoke-exceptions', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace', 'dont-free-domains', 'suspend-on-sigsegv', 'suspend-on-exception', 'suspend-on-unhandled', 'dyn-runtime-invoke', 'gdb', 'explicit-null-checks', 'init-stacks', 'check-pinvoke-callconv'\n");
exit (1);
}
}
diff --git a/mono/mini/mini.h b/mono/mini/mini.h
index 7069811551f..88adbd8c3c3 100644
--- a/mono/mini/mini.h
+++ b/mono/mini/mini.h
@@ -122,7 +122,7 @@
#endif
/* Version number of the AOT file format */
-#define MONO_AOT_FILE_VERSION 99
+#define MONO_AOT_FILE_VERSION 100
//TODO: This is x86/amd64 specific.
#define mono_simd_shuffle_mask(a,b,c,d) ((a) | ((b) << 2) | ((c) << 4) | ((d) << 6))
@@ -1412,6 +1412,8 @@ typedef struct {
MonoInst *lmf_var;
MonoInst *lmf_addr_var;
+ MonoInst *stack_inbalance_var;
+
unsigned char *cil_start;
#ifdef __native_client_codegen__
/* this alloc is not aligned, native_code */
@@ -1486,6 +1488,7 @@ typedef struct {
guint has_indirection : 1;
guint has_atomic_add_new_i4 : 1;
guint has_atomic_exchange_i4 : 1;
+ guint check_pinvoke_callconv : 1;
gpointer debug_info;
guint32 lmf_offset;
guint16 *intvars;
@@ -1843,6 +1846,10 @@ typedef struct {
* Load AOT JIT info eagerly.
*/
gboolean load_aot_jit_info_eagerly;
+ /*
+ * Check for pinvoke calling convention mismatches.
+ */
+ gboolean check_pinvoke_callconv;
} MonoDebugOptions;
enum {
diff --git a/mono/tests/libtest.c b/mono/tests/libtest.c
index f683ee2b66e..e057944bbd7 100644
--- a/mono/tests/libtest.c
+++ b/mono/tests/libtest.c
@@ -1973,6 +1973,18 @@ mono_test_stdcall_name_mangling (int a, int b, int c)
return a + b + c;
}
+LIBTEST_API int
+mono_test_stdcall_mismatch_1 (int a, int b, int c)
+{
+ return a + b + c;
+}
+
+LIBTEST_API int STDCALL
+mono_test_stdcall_mismatch_2 (int a, int b, int c)
+{
+ return a + b + c;
+}
+
/*
* PASSING AND RETURNING SMALL STRUCTURES FROM DELEGATES TESTS
*/
diff --git a/mono/tests/pinvoke2.cs b/mono/tests/pinvoke2.cs
index 22c83573c40..71c51a7d814 100644
--- a/mono/tests/pinvoke2.cs
+++ b/mono/tests/pinvoke2.cs
@@ -1320,6 +1320,26 @@ public class Tests {
return string_marshal_test3 (null);
}
+#if FALSE
+ [DllImport ("libtest", EntryPoint="mono_test_stdcall_mismatch_1", CallingConvention=CallingConvention.StdCall)]
+ public static extern int mono_test_stdcall_mismatch_1 (int a, int b, int c);
+
+ /* Test mismatched called conventions, the native function is cdecl */
+ public static int test_0_stdcall_mismatch_1 () {
+ mono_test_stdcall_mismatch_1 (0, 1, 2);
+ return 0;
+ }
+
+ [DllImport ("libtest", EntryPoint="mono_test_stdcall_mismatch_2", CallingConvention=CallingConvention.Cdecl)]
+ public static extern int mono_test_stdcall_mismatch_2 (int a, int b, int c);
+
+ /* Test mismatched called conventions, the native function is stdcall */
+ public static int test_0_stdcall_mismatch_2 () {
+ mono_test_stdcall_mismatch_2 (0, 1, 2);
+ return 0;
+ }
+#endif
+
[DllImport ("libtest", EntryPoint="mono_test_stdcall_name_mangling", CallingConvention=CallingConvention.StdCall)]
public static extern int mono_test_stdcall_name_mangling (int a, int b, int c);