Skip to content

Commit

Permalink
[runtime] Fix a nullref when casting a null object to a complex type …
Browse files Browse the repository at this point in the history
…when using --debug=casts. Fixes #14552/#14493.
  • Loading branch information
vargaz authored and abacon committed Sep 9, 2013
1 parent 1fbc219 commit a5501cb
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 8 deletions.
32 changes: 24 additions & 8 deletions mono/mini/method-to-ir.c
Expand Up @@ -3339,14 +3339,23 @@ emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_
}

static void
save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg)
save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check, MonoBasicBlock **out_bblock)
{
if (mini_get_debug_options ()->better_cast_details) {
int to_klass_reg = alloc_preg (cfg);
int vtable_reg = alloc_preg (cfg);
int klass_reg = alloc_preg (cfg);
MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
MonoBasicBlock *is_null_bb = NULL;
MonoInst *tls_get;

if (null_check) {
NEW_BBLOCK (cfg, is_null_bb);

MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
}

tls_get = mono_get_jit_tls_intrinsic (cfg);
if (!tls_get) {
fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
exit (1);
Expand All @@ -3359,6 +3368,12 @@ save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg)
MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
MONO_EMIT_NEW_PCONST (cfg, to_klass_reg, klass);
MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);

if (null_check) {
MONO_START_BB (cfg, is_null_bb);
if (out_bblock)
*out_bblock = cfg->cbb;
}
}
}

Expand Down Expand Up @@ -3386,7 +3401,7 @@ mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_cl

context_used = mini_class_check_context_used (cfg, array_class);

save_cast_details (cfg, array_class, obj->dreg);
save_cast_details (cfg, array_class, obj->dreg, FALSE, NULL);

MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, G_STRUCT_OFFSET (MonoObject, vtable));

Expand Down Expand Up @@ -3503,7 +3518,7 @@ handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_use
MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
} else {
save_cast_details (cfg, klass->element_class, obj_reg);
save_cast_details (cfg, klass->element_class, obj_reg, FALSE, NULL);
mini_emit_class_check (cfg, eclass_reg, klass->element_class);
reset_cast_details (cfg);
}
Expand Down Expand Up @@ -3872,7 +3887,7 @@ handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);

save_cast_details (cfg, klass, obj_reg);
save_cast_details (cfg, klass, obj_reg, FALSE, NULL);

if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
Expand Down Expand Up @@ -4182,7 +4197,7 @@ handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);

save_cast_details (cfg, klass, obj_reg);
save_cast_details (cfg, klass, obj_reg, FALSE, NULL);

if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
#ifndef DISABLE_REMOTING
Expand Down Expand Up @@ -9313,7 +9328,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));

/*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
save_cast_details (cfg, klass, sp [0]->dreg);

save_cast_details (cfg, klass, sp [0]->dreg, TRUE, &bblock);
*sp++ = mono_emit_method_call (cfg, mono_castclass, args, NULL);
reset_cast_details (cfg);
ip += 5;
Expand All @@ -9326,7 +9342,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
mono_castclass = mono_marshal_get_castclass (klass);
iargs [0] = sp [0];

save_cast_details (cfg, klass, sp [0]->dreg);
save_cast_details (cfg, klass, sp [0]->dreg, TRUE, &bblock);
costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass),
iargs, ip, cfg->real_offset, dont_inline, TRUE);
reset_cast_details (cfg);
Expand Down
12 changes: 12 additions & 0 deletions mono/tests/debug-casts.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;

public class Tests
{
Expand Down Expand Up @@ -30,4 +31,15 @@ public class Tests
}
return 0;
}

[MethodImplAttribute (MethodImplOptions.NoInlining)]
public static object return_null () {
return null;
}

public static int test_0_complex_1_null () {
object o = return_null ();
IEnumerable<object> ie = (IEnumerable<object>)o;
return 0;
}
}

0 comments on commit a5501cb

Please sign in to comment.