Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[dim] Emit error when calling abstract methods #15433

Merged
merged 2 commits into from Jun 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions mono/metadata/jit-icall-reg.h
Expand Up @@ -302,6 +302,7 @@ MONO_JIT_ICALL (mono_threads_exit_gc_unsafe_region_unbalanced) \
MONO_JIT_ICALL (mono_threads_state_poll) \
MONO_JIT_ICALL (mono_throw_exception) \
MONO_JIT_ICALL (mono_throw_method_access) \
MONO_JIT_ICALL (mono_throw_bad_image) \
MONO_JIT_ICALL (mono_trace_enter_method) \
MONO_JIT_ICALL (mono_trace_leave_method) \
MONO_JIT_ICALL (mono_upgrade_remote_class_wrapper) \
Expand Down
18 changes: 15 additions & 3 deletions mono/mini/interp/transform.c
Expand Up @@ -882,6 +882,15 @@ interp_generate_mae_throw (TransformData *td, MonoMethod *method, MonoMethod *ta
td->sp -= 2;
}

static void
interp_generate_bie_throw (TransformData *td)
{
MonoJitICallInfo *info = &mono_get_jit_icall_info ()->mono_throw_bad_image;

interp_add_ins (td, MINT_ICALL_PP_V);
td->last_ins->data [0] = get_data_item_index (td, (gpointer)info->func);
}

/*
* These are additional locals that can be allocated as we transform the code.
* They are allocated past the method locals so they are accessed in the same
Expand Down Expand Up @@ -1950,9 +1959,12 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target
if (target_method)
mono_class_init_internal (target_method->klass);

if (!is_virtual && target_method && (target_method->flags & METHOD_ATTRIBUTE_ABSTRACT))
/* MS.NET seems to silently convert this to a callvirt */
is_virtual = TRUE;
if (!is_virtual && target_method && (target_method->flags & METHOD_ATTRIBUTE_ABSTRACT)) {
if (!mono_class_is_interface (method->klass))
interp_generate_bie_throw (td);
else
is_virtual = TRUE;
}

if (is_virtual && target_method && (!(target_method->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
(MONO_METHOD_IS_FINAL (target_method) &&
Expand Down
8 changes: 8 additions & 0 deletions mono/mini/jit-icalls.c
Expand Up @@ -1522,6 +1522,14 @@ mono_throw_method_access (MonoMethod *caller, MonoMethod *callee)
g_free (caller_name);
}

void
mono_throw_bad_image ()
{
ERROR_DECL (error);
mono_error_set_generic_error (error, "System", "BadImageFormatException", "Bad IL format.");
mono_error_set_pending_exception (error);
}

void
mono_dummy_jit_icall (void)
{
Expand Down
2 changes: 2 additions & 0 deletions mono/mini/jit-icalls.h
Expand Up @@ -219,6 +219,8 @@ G_EXTERN_C double mono_ckfinite (double d);

G_EXTERN_C void mono_throw_method_access (MonoMethod *caller, MonoMethod *callee);

G_EXTERN_C void mono_throw_bad_image (void);

G_EXTERN_C void mono_dummy_jit_icall (void);

#endif /* __MONO_JIT_ICALLS_H__ */
16 changes: 12 additions & 4 deletions mono/mini/method-to-ir.c
Expand Up @@ -2243,6 +2243,12 @@ emit_method_access_failure (MonoCompile *cfg, MonoMethod *caller, MonoMethod *ca
mono_emit_jit_icall (cfg, mono_throw_method_access, args);
}

static void
emit_bad_image_failure (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
{
mono_emit_jit_icall (cfg, mono_throw_bad_image, NULL);
}

static MonoMethod*
get_method_nofail (MonoClass *klass, const char *method_name, int num_params, int flags)
{
Expand Down Expand Up @@ -7037,9 +7043,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
if (mono_security_core_clr_enabled ())
ensure_method_is_allowed_to_call_method (cfg, method, cil_method);

if (!virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
/* MS.NET seems to silently convert this to a callvirt */
virtual_ = TRUE;
if (!virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT)) {
if (!mono_class_is_interface (method->klass))
emit_bad_image_failure (cfg, method, cil_method);
else
virtual_ = TRUE;
}

{
/*
Expand Down Expand Up @@ -7810,7 +7819,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
}
emit_seq_point (cfg, method, next_ip, FALSE, TRUE);
}

break;
}
case MONO_CEE_RET:
Expand Down
1 change: 1 addition & 0 deletions mono/mini/mini-runtime.c
Expand Up @@ -4632,6 +4632,7 @@ register_icalls (void)
register_icall (mono_get_assembly_object, mono_icall_sig_object_ptr, TRUE);
register_icall (mono_get_method_object, mono_icall_sig_object_ptr, TRUE);
register_icall (mono_throw_method_access, mono_icall_sig_void_ptr_ptr, FALSE);
register_icall (mono_throw_bad_image, mono_icall_sig_void, FALSE);
register_icall_no_wrapper (mono_dummy_jit_icall, mono_icall_sig_void);

register_icall_with_wrapper (mono_monitor_enter_internal, mono_icall_sig_int32_obj);
Expand Down
1 change: 1 addition & 0 deletions mono/tests/Makefile.am
Expand Up @@ -1011,6 +1011,7 @@ TESTS_IL_SRC= \
dim-protected-accessibility2.il \
dim-reabstraction.il \
dim-reabstraction-generics.il \
dim-abstractcall.il \
twopassvariance.il \
tailcall-generic-cast-conservestack-il.il \
tailcall-generic-cast-nocrash-il.il \
Expand Down
115 changes: 115 additions & 0 deletions mono/tests/dim-abstractcall.il
@@ -0,0 +1,115 @@

// Microsoft (R) .NET Framework IL Disassembler. Version 4.6.1055.0
// Copyright (c) Microsoft Corporation. All rights reserved.



// Metadata version: v4.0.30319.assembly extern mscorlib { }
.assembly abstractcalls { }

.class interface public abstract auto ansi I1
{
.method public hidebysig newslot virtual abstract
instance int32 Add(int32 x) cil managed
{
}
}

.class public abstract auto ansi C1
extends [mscorlib]System.Object
implements I1
{
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
ldarg.0
call instance void [mscorlib]System.Object::.ctor()
ret
}

.method public hidebysig newslot virtual abstract
instance int32 Remove(int32 x) cil managed
{
}
}

.class public auto ansi C2
extends [mscorlib]System.Object
implements I1
{
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
ldarg.0
call instance void C1::.ctor()
ret
}

.method public hidebysig virtual
instance int32 Remove(int32 x) cil managed
{
ldc.i4.0
ret
}

.method public hidebysig newslot virtual
instance int32 Add(int32 x) cil managed
{
ldc.i4.5
ret
}
}

.method private hidebysig static void CallClass() cil managed
{
newobj instance void C2::.ctor()
ldc.i4.0
call instance int32 C1::Remove(int32)
pop
ret
}

.method private hidebysig static void CallInterface() cil managed
{
newobj instance void C2::.ctor()
ldc.i4.0
call instance int32 I1::Add(int32)
pop
ret
}

.method private hidebysig static int32 Main() cil managed
{
.entrypoint

.try
{
call void CallClass()
leave Fail
}
catch [System.Runtime]System.BadImageFormatException
{
leave AbstractClassOK
}

AbstractClassOK:

.try
{
call void CallInterface()
leave Fail
}
catch [System.Runtime]System.BadImageFormatException
{
leave AbstractInterfaceOK
}

AbstractInterfaceOK:
ldc.i4 0
ret

Fail:
ldc.i4 155
ret
}