Commit message: Handle invalid instantiation of generic methods.

	* verify.c: Add new function to internal verifier API to check
	method instantiations.

	* reflection.c (mono_reflection_bind_generic_method_parameters):
	Check the instantiation before returning it.

	Fixes #655847
CVE: CVE-2010-4254
CWE: CWE-20
Vulnerability description: Mono, when Moonlight before 2.3.0.1 or 2.99.x before 2.99.0.10 is used, does not properly validate arguments to generic methods, which allows remote attackers to bypass generic constraints, and possibly execute arbitrary code, via a crafted method call.

Project: mono

mono_image_verify_tables (MonoImage *image, int level)
{
	GSList *error_list = NULL;

	error_list = verify_assembly_table (image, error_list, level);
	/* 
	 * AssemblyOS, AssemblyProcessor, AssemblyRefOs and
	 * AssemblyRefProcessor should be ignored, 
	 * though we may want to emit a warning, since it should not 
	 * be present in a PE file.
	 */
	error_list = verify_assemblyref_table (image, error_list, level);
	error_list = verify_class_layout_table (image, error_list, level);
	error_list = verify_constant_table (image, error_list, level);
	/*
	 * cutom attribute, declsecurity 
	 */
	error_list = verify_event_map_table (image, error_list, level);
	error_list = verify_event_table (image, error_list, level);
	error_list = verify_field_table (image, error_list, level);
	error_list = verify_file_table (image, error_list, level);
	error_list = verify_moduleref_table (image, error_list, level);
	error_list = verify_standalonesig_table (image, error_list, level);

	return g_slist_reverse (error_list);
}

Project: mono

stack_init (VerifyContext *ctx, ILCodeDesc *state) 
{
	if (state->flags & IL_CODE_FLAG_STACK_INITED)
		return;
	state->size = 0;
	state->flags |= IL_CODE_FLAG_STACK_INITED;
	if (!state->stack)
		state->stack = g_new0 (ILStackDesc, ctx->max_stack);
}

Project: mono

verify_class_layout_table (MonoImage *image, GSList *list, int level)
{
	MonoTableInfo *t = &image->tables [MONO_TABLE_CLASSLAYOUT];
	MonoTableInfo *tdef = &image->tables [MONO_TABLE_TYPEDEF];
	guint32 cols [MONO_CLASS_LAYOUT_SIZE];
	guint32 value, i;

	if (level & MONO_VERIFY_ERROR) {
		for (i = 0; i < t->rows; ++i) {
			mono_metadata_decode_row (t, i, cols, MONO_CLASS_LAYOUT_SIZE);

			if (cols [MONO_CLASS_LAYOUT_PARENT] > tdef->rows || !cols [MONO_CLASS_LAYOUT_PARENT]) {
				ADD_ERROR (list, g_strdup_printf ("Parent in class layout is invalid in row %d", i + 1));
			} else {
				value = mono_metadata_decode_row_col (tdef, cols [MONO_CLASS_LAYOUT_PARENT] - 1, MONO_TYPEDEF_FLAGS);
				if (value & TYPE_ATTRIBUTE_INTERFACE)
					ADD_ERROR (list, g_strdup_printf ("Parent in class layout row %d is an interface", i + 1));
				if (value & TYPE_ATTRIBUTE_AUTO_LAYOUT)
					ADD_ERROR (list, g_strdup_printf ("Parent in class layout row %d is AutoLayout", i + 1));
				if (value & TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT) {
					switch (cols [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
					case 0: case 1: case 2: case 4: case 8: case 16:
					case 32: case 64: case 128: break;
					default:
						ADD_ERROR (list, g_strdup_printf ("Packing size %d in class layout row %d is invalid", cols [MONO_CLASS_LAYOUT_PACKING_SIZE], i + 1));
					}
				} else if (value & TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
					/*
					 * FIXME: LAMESPEC: it claims it must be 0 (it's 1, instead).
					if (cols [MONO_CLASS_LAYOUT_PACKING_SIZE])
						ADD_ERROR (list, g_strdup_printf ("Packing size %d in class layout row %d is invalid with explicit layout", cols [MONO_CLASS_LAYOUT_PACKING_SIZE], i + 1));
					*/
				}
				/*
				 * FIXME: we need to check that if class size != 0, 
				 * it needs to be greater than the class calculated size.
				 * If parent is a valuetype it also needs to be smaller than
				 * 1 MByte (0x100000 bytes).
				 * To do both these checks we need to load the referenced 
				 * assemblies, though (the spec claims we didn't have to, bah).
				 */
				/* 
				 * We need to check that the parent types have the same layout 
				 * type as well.
				 */
			}
		}
	}

	return list;
}

Project: mono

is_valid_generic_instantiation (MonoGenericContainer *gc, MonoGenericContext *context, MonoGenericInst *ginst)
{
	MonoError error;
	int i;

	if (ginst->type_argc != gc->type_argc)
		return FALSE;

	for (i = 0; i < gc->type_argc; ++i) {
		MonoGenericParamInfo *param_info = mono_generic_container_get_param_info (gc, i);
		MonoClass *paramClass;
		MonoClass **constraints;

		if (!param_info->constraints && !(param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK))
			continue;
		if (mono_type_is_generic_argument (ginst->type_argv [i]))
			continue; //it's not our job to validate type variables

		paramClass = mono_class_from_mono_type (ginst->type_argv [i]);

		if (paramClass->exception_type != MONO_EXCEPTION_NONE)
			return FALSE;

		/*it's not safe to call mono_class_init from here*/
		if (paramClass->generic_class && !paramClass->inited) {
			if (!mono_class_is_valid_generic_instantiation (NULL, paramClass))
				return FALSE;
		}

		if ((param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) && (!paramClass->valuetype || mono_class_is_nullable (paramClass)))
			return FALSE;

		if ((param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) && paramClass->valuetype)
			return FALSE;

		if ((param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) && !paramClass->valuetype && !mono_class_has_default_constructor (paramClass))
			return FALSE;

		if (!param_info->constraints)
			continue;

		for (constraints = param_info->constraints; *constraints; ++constraints) {
			MonoClass *ctr = *constraints;
			MonoType *inflated;

			inflated = mono_class_inflate_generic_type_checked (&ctr->byval_arg, context, &error);
			if (!mono_error_ok (&error)) {
				mono_error_cleanup (&error);
				return FALSE;
			}
			ctr = mono_class_from_mono_type (inflated);
			mono_metadata_free_type (inflated);

			if (!mono_class_is_constraint_compatible (paramClass, ctr))
				return FALSE;
		}
	}
	return TRUE;
}

Project: mono

mono_class_interface_implements_interface (MonoClass *candidate, MonoClass *iface)
{
	MonoError error;
	int i;
	do {
		if (candidate == iface)
			return TRUE;
		mono_class_setup_interfaces (candidate, &error);
		if (!mono_error_ok (&error)) {
			mono_error_cleanup (&error);
			return FALSE;
		}

		for (i = 0; i < candidate->interface_count; ++i) {
			if (candidate->interfaces [i] == iface || mono_class_interface_implements_interface (candidate->interfaces [i], iface))
				return TRUE;
		}
		candidate = candidate->parent;
	} while (candidate);
	return FALSE;
}

Project: mono

GSList*
mono_method_verify (MonoMethod *method, int level)
{
	MonoError error;
	const unsigned char *ip, *code_start;
	const unsigned char *end;
	MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;

	int i, n, need_merge = 0, start = 0;
	guint token, ip_offset = 0, prefix = 0;
	MonoGenericContext *generic_context = NULL;
	MonoImage *image;
	VerifyContext ctx;
	GSList *tmp;
	VERIFIER_DEBUG ( printf ("Verify IL for method %s %s %s\n",  method->klass->name_space,  method->klass->name, method->name); );

	if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
			(method->flags & (METHOD_ATTRIBUTE_PINVOKE_IMPL | METHOD_ATTRIBUTE_ABSTRACT))) {
		return NULL;
	}

	memset (&ctx, 0, sizeof (VerifyContext));

	//FIXME use mono_method_get_signature_full
	ctx.signature = mono_method_signature (method);
	if (!ctx.signature) {
		ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Could not decode method signature"));
		return ctx.list;
	}
	ctx.header = mono_method_get_header (method);
	if (!ctx.header) {
		ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Could not decode method header"));
		return ctx.list;
	}
	ctx.method = method;
	code_start = ip = ctx.header->code;
	end = ip + ctx.header->code_size;
	ctx.image = image = method->klass->image;


	ctx.max_args = ctx.signature->param_count + ctx.signature->hasthis;
	ctx.max_stack = ctx.header->max_stack;
	ctx.verifiable = ctx.valid = 1;
	ctx.level = level;

	ctx.code = g_new (ILCodeDesc, ctx.header->code_size);
	ctx.code_size = ctx.header->code_size;

	memset(ctx.code, 0, sizeof (ILCodeDesc) * ctx.header->code_size);


	ctx.num_locals = ctx.header->num_locals;
	ctx.locals = g_memdup (ctx.header->locals, sizeof (MonoType*) * ctx.header->num_locals);

	if (ctx.num_locals > 0 && !ctx.header->init_locals)
		CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Method with locals variable but without init locals set"));

	ctx.params = g_new (MonoType*, ctx.max_args);
	if (ctx.signature->hasthis)
		ctx.params [0] = method->klass->valuetype ? &method->klass->this_arg : &method->klass->byval_arg;
	memcpy (ctx.params + ctx.signature->hasthis, ctx.signature->params, sizeof (MonoType *) * ctx.signature->param_count);

	if (ctx.signature->is_inflated)
		ctx.generic_context = generic_context = mono_method_get_context (method);

	if (!generic_context && (method->klass->generic_container || method->is_generic)) {
		if (method->is_generic)
			ctx.generic_context = generic_context = &(mono_method_get_generic_container (method)->context);
		else
			ctx.generic_context = generic_context = &method->klass->generic_container->context;
	}

	for (i = 0; i < ctx.num_locals; ++i) {
		MonoType *uninflated = ctx.locals [i];
		ctx.locals [i] = mono_class_inflate_generic_type_checked (ctx.locals [i], ctx.generic_context, &error);
		if (!mono_error_ok (&error)) {
			char *name = mono_type_full_name (ctx.locals [i] ? ctx.locals [i] : uninflated);
			ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid local %d of type %s", i, name));
			g_free (name);
			mono_error_cleanup (&error);
			/* we must not free (in cleanup) what was not yet allocated (but only copied) */
			ctx.num_locals = i;
			ctx.max_args = 0;
			goto cleanup;
		}
	}
	for (i = 0; i < ctx.max_args; ++i) {
		MonoType *uninflated = ctx.params [i];
		ctx.params [i] = mono_class_inflate_generic_type_checked (ctx.params [i], ctx.generic_context, &error);
		if (!mono_error_ok (&error)) {
			char *name = mono_type_full_name (ctx.params [i] ? ctx.params [i] : uninflated);
			ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid parameter %d of type %s", i, name));
			g_free (name);
			mono_error_cleanup (&error);
			/* we must not free (in cleanup) what was not yet allocated (but only copied) */
			ctx.max_args = i;
			goto cleanup;
		}
	}
	stack_init (&ctx, &ctx.eval);

	for (i = 0; i < ctx.num_locals; ++i) {
		if (!mono_type_is_valid_in_context (&ctx, ctx.locals [i]))
			break;
		if (get_stack_type (ctx.locals [i]) == TYPE_INV) {
			char *name = mono_type_full_name (ctx.locals [i]);
			ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid local %i of type %s", i, name));
			g_free (name);
			break;
		}
		
	}

	for (i = 0; i < ctx.max_args; ++i) {
		if (!mono_type_is_valid_in_context (&ctx, ctx.params [i]))
			break;

		if (get_stack_type (ctx.params [i]) == TYPE_INV) {
			char *name = mono_type_full_name (ctx.params [i]);
			ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid parameter %i of type %s", i, name));
			g_free (name);
			break;
		}
	}

	if (!ctx.valid)
		goto cleanup;

	for (i = 0; i < ctx.header->num_clauses && ctx.valid; ++i) {
		MonoExceptionClause *clause = ctx.header->clauses + i;
		VERIFIER_DEBUG (printf ("clause try %x len %x filter at %x handler at %x len %x\n", clause->try_offset, clause->try_len, clause->data.filter_offset, clause->handler_offset, clause->handler_len); );

		if (clause->try_offset > ctx.code_size || ADD_IS_GREATER_OR_OVF (clause->try_offset, clause->try_len, ctx.code_size))
			ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("try clause out of bounds at 0x%04x", clause->try_offset));

		if (clause->try_len <= 0)
			ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("try clause len <= 0 at 0x%04x", clause->try_offset));

		if (clause->handler_offset > ctx.code_size || ADD_IS_GREATER_OR_OVF (clause->handler_offset, clause->handler_len, ctx.code_size))
			ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("handler clause out of bounds at 0x%04x", clause->try_offset));

		if (clause->handler_len <= 0)
			ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("handler clause len <= 0 at 0x%04x", clause->try_offset));

		if (clause->try_offset < clause->handler_offset && ADD_IS_GREATER_OR_OVF (clause->try_offset, clause->try_len, HANDLER_START (clause)))
			ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("try block (at 0x%04x) includes handler block (at 0x%04x)", clause->try_offset, clause->handler_offset));

		if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
			if (clause->data.filter_offset > ctx.code_size)
				ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("filter clause out of bounds at 0x%04x", clause->try_offset));

			if (clause->data.filter_offset >= clause->handler_offset)
				ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("filter clause must come before the handler clause at 0x%04x", clause->data.filter_offset));
		}

		for (n = i + 1; n < ctx.header->num_clauses && ctx.valid; ++n)
			verify_clause_relationship (&ctx, clause, ctx.header->clauses + n);

		if (!ctx.valid)
			break;

		ctx.code [clause->try_offset].flags |= IL_CODE_FLAG_WAS_TARGET;
		if (clause->try_offset + clause->try_len < ctx.code_size)
			ctx.code [clause->try_offset + clause->try_len].flags |= IL_CODE_FLAG_WAS_TARGET;
		if (clause->handler_offset + clause->handler_len < ctx.code_size)
			ctx.code [clause->handler_offset + clause->handler_len].flags |= IL_CODE_FLAG_WAS_TARGET;

		if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) {
			if (!clause->data.catch_class) {
				ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Catch clause %d with invalid type", i));
				break;
			}
		
			init_stack_with_value_at_exception_boundary (&ctx, ctx.code + clause->handler_offset, clause->data.catch_class);
		}
		else if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
			init_stack_with_value_at_exception_boundary (&ctx, ctx.code + clause->data.filter_offset, mono_defaults.exception_class);
			init_stack_with_value_at_exception_boundary (&ctx, ctx.code + clause->handler_offset, mono_defaults.exception_class);	
		}
	}

	original_bb = bb = mono_basic_block_split (method, &error);
	if (!mono_error_ok (&error)) {
		ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid branch target: %s", mono_error_get_message (&error)));
		mono_error_cleanup (&error);
		goto cleanup;
	}
	g_assert (bb);

	while (ip < end && ctx.valid) {
		int op_size;
		ip_offset = ip - code_start;
		{
			const unsigned char *ip_copy = ip;
			int op;

			if (ip_offset > bb->end) {
				ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Branch or EH block at [0x%04x] targets middle instruction at 0x%04x", bb->end, ip_offset));
				goto cleanup;
			}

			if (ip_offset == bb->end)
				bb = bb->next;
	
			op_size = mono_opcode_value_and_size (&ip_copy, end, &op);
			if (op_size == -1) {
				ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction %x at 0x%04x", *ip, ip_offset));
				goto cleanup;
			}

			if (ADD_IS_GREATER_OR_OVF (ip_offset, op_size, bb->end)) {
				ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Branch or EH block targets middle of instruction at 0x%04x", ip_offset));
				goto cleanup;
			}

			/*Last Instruction*/
			if (ip_offset + op_size == bb->end && mono_opcode_is_prefix (op)) {
				ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Branch or EH block targets between prefix '%s' and instruction at 0x%04x", mono_opcode_name (op), ip_offset));
				goto cleanup;
			}
		}

		ctx.ip_offset = ip_offset = ip - code_start;

		/*We need to check against fallthrou in and out of protected blocks.
		 * For fallout we check the once a protected block ends, if the start flag is not set.
		 * Likewise for fallthru in, we check if ip is the start of a protected block and start is not set
		 * TODO convert these checks to be done using flags and not this loop
		 */
		for (i = 0; i < ctx.header->num_clauses && ctx.valid; ++i) {
			MonoExceptionClause *clause = ctx.header->clauses + i;

			if ((clause->try_offset + clause->try_len == ip_offset) && start == 0) {
				CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("fallthru off try block at 0x%04x", ip_offset));
				start = 1;
			}

			if ((clause->handler_offset + clause->handler_len == ip_offset) && start == 0) {
				if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER)
					ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("fallout of handler block at 0x%04x", ip_offset));
				else
					CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("fallout of handler block at 0x%04x", ip_offset));
				start = 1;
			}

			if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER && clause->handler_offset == ip_offset && start == 0) {
				ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("fallout of filter block at 0x%04x", ip_offset));
				start = 1;
			}

			if (clause->handler_offset == ip_offset && start == 0) {
				CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("fallthru handler block at 0x%04x", ip_offset));
				start = 1;
			}

			if (clause->try_offset == ip_offset && ctx.eval.size > 0 && start == 0) {
				ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Try to enter try block with a non-empty stack at 0x%04x", ip_offset));
				start = 1;
			}
		}

		/*This must be done after fallthru detection otherwise it won't happen.*/
		if (bb->dead) {
			/*FIXME remove this once we move all bad branch checking code to use BB only*/
			ctx.code [ip_offset].flags |= IL_CODE_FLAG_SEEN;
			ip += op_size;
			continue;
		}

		if (!ctx.valid)
			break;

		if (need_merge) {
			VERIFIER_DEBUG ( printf ("extra merge needed! 0x%04x \n", ctx.target); );
			merge_stacks (&ctx, &ctx.eval, &ctx.code [ctx.target], FALSE, TRUE);
			need_merge = 0;	
		}
		merge_stacks (&ctx, &ctx.eval, &ctx.code[ip_offset], start, FALSE);
		start = 0;

		/*TODO we can fast detect a forward branch or exception block targeting code after prefix, we should fail fast*/
#ifdef MONO_VERIFIER_DEBUG
		{
			char *discode;
			discode = mono_disasm_code_one (NULL, method, ip, NULL);
			discode [strlen (discode) - 1] = 0; /* no \n */
			g_print ("[%d] %-29s (%d)\n",  ip_offset, discode, ctx.eval.size);
			g_free (discode);
		}
		dump_stack_state (&ctx.code [ip_offset]);
		dump_stack_state (&ctx.eval);
#endif

		switch (*ip) {
		case CEE_NOP:
		case CEE_BREAK:
			++ip;
			break;

		case CEE_LDARG_0:
		case CEE_LDARG_1:
		case CEE_LDARG_2:
		case CEE_LDARG_3:
			push_arg (&ctx, *ip - CEE_LDARG_0, FALSE);
			++ip;
			break;

		case CEE_LDARG_S:
		case CEE_LDARGA_S:
			code_bounds_check (2);
			push_arg (&ctx, ip [1],  *ip == CEE_LDARGA_S);
			ip += 2;
			break;

		case CEE_ADD_OVF_UN:
			do_binop (&ctx, *ip, add_ovf_un_table);
			++ip;
			break;

		case CEE_SUB_OVF_UN:
			do_binop (&ctx, *ip, sub_ovf_un_table);
			++ip;
			break;

		case CEE_ADD_OVF:
		case CEE_SUB_OVF:
		case CEE_MUL_OVF:
		case CEE_MUL_OVF_UN:
			do_binop (&ctx, *ip, bin_ovf_table);
			++ip;
			break;

		case CEE_ADD:
			do_binop (&ctx, *ip, add_table);
			++ip;
			break;

		case CEE_SUB:
			do_binop (&ctx, *ip, sub_table);
			++ip;
			break;

		case CEE_MUL:
		case CEE_DIV:
		case CEE_REM:
			do_binop (&ctx, *ip, bin_op_table);
			++ip;
			break;

		case CEE_AND:
		case CEE_DIV_UN:
		case CEE_OR:
		case CEE_REM_UN:
		case CEE_XOR:
			do_binop (&ctx, *ip, int_bin_op_table);
			++ip;
			break;

		case CEE_SHL:
		case CEE_SHR:
		case CEE_SHR_UN:
			do_binop (&ctx, *ip, shift_op_table);
			++ip;
			break;

		case CEE_POP:
			if (!check_underflow (&ctx, 1))
				break;
			stack_pop_safe (&ctx);
			++ip;
			break;

		case CEE_RET:
			do_ret (&ctx);
			++ip;
			start = 1;
			break;

		case CEE_LDLOC_0:
		case CEE_LDLOC_1:
		case CEE_LDLOC_2:
		case CEE_LDLOC_3:
			/*TODO support definite assignment verification? */
			push_local (&ctx, *ip - CEE_LDLOC_0, FALSE);
			++ip;
			break;

		case CEE_STLOC_0:
		case CEE_STLOC_1:
		case CEE_STLOC_2:
		case CEE_STLOC_3:
			store_local (&ctx, *ip - CEE_STLOC_0);
			++ip;
			break;

		case CEE_STLOC_S:
			code_bounds_check (2);
			store_local (&ctx, ip [1]);
			ip += 2;
			break;

		case CEE_STARG_S:
			code_bounds_check (2);
			store_arg (&ctx, ip [1]);
			ip += 2;
			break;

		case CEE_LDC_I4_M1:
		case CEE_LDC_I4_0:
		case CEE_LDC_I4_1:
		case CEE_LDC_I4_2:
		case CEE_LDC_I4_3:
		case CEE_LDC_I4_4:
		case CEE_LDC_I4_5:
		case CEE_LDC_I4_6:
		case CEE_LDC_I4_7:
		case CEE_LDC_I4_8:
			if (check_overflow (&ctx))
				stack_push_val (&ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
			++ip;
			break;

		case CEE_LDC_I4_S:
			code_bounds_check (2);
			if (check_overflow (&ctx))
				stack_push_val (&ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
			ip += 2;
			break;

		case CEE_LDC_I4:
			code_bounds_check (5);
			if (check_overflow (&ctx))
				stack_push_val (&ctx,TYPE_I4, &mono_defaults.int32_class->byval_arg);
			ip += 5;
			break;

		case CEE_LDC_I8:
			code_bounds_check (9);
			if (check_overflow (&ctx))
				stack_push_val (&ctx,TYPE_I8, &mono_defaults.int64_class->byval_arg);
			ip += 9;
			break;

		case CEE_LDC_R4:
			code_bounds_check (5);
			if (check_overflow (&ctx))
				stack_push_val (&ctx, TYPE_R8, &mono_defaults.double_class->byval_arg);
			ip += 5;
			break;

		case CEE_LDC_R8:
			code_bounds_check (9);
			if (check_overflow (&ctx))
				stack_push_val (&ctx, TYPE_R8, &mono_defaults.double_class->byval_arg);
			ip += 9;
			break;

		case CEE_LDNULL:
			if (check_overflow (&ctx))
				stack_push_val (&ctx, TYPE_COMPLEX | NULL_LITERAL_MASK, &mono_defaults.object_class->byval_arg);
			++ip;
			break;

		case CEE_BEQ_S:
		case CEE_BNE_UN_S:
			code_bounds_check (2);
			do_branch_op (&ctx, (signed char)ip [1] + 2, cmp_br_eq_op);
			ip += 2;
			need_merge = 1;
			break;

		case CEE_BGE_S:
		case CEE_BGT_S:
		case CEE_BLE_S:
		case CEE_BLT_S:
		case CEE_BGE_UN_S:
		case CEE_BGT_UN_S:
		case CEE_BLE_UN_S:
		case CEE_BLT_UN_S:
			code_bounds_check (2);
			do_branch_op (&ctx, (signed char)ip [1] + 2, cmp_br_op);
			ip += 2;
			need_merge = 1;
			break;

		case CEE_BEQ:
		case CEE_BNE_UN:
			code_bounds_check (5);
			do_branch_op (&ctx, (gint32)read32 (ip + 1) + 5, cmp_br_eq_op);
			ip += 5;
			need_merge = 1;
			break;

		case CEE_BGE:
		case CEE_BGT:
		case CEE_BLE:
		case CEE_BLT:
		case CEE_BGE_UN:
		case CEE_BGT_UN:
		case CEE_BLE_UN:
		case CEE_BLT_UN:
			code_bounds_check (5);
			do_branch_op (&ctx, (gint32)read32 (ip + 1) + 5, cmp_br_op);
			ip += 5;
			need_merge = 1;
			break;

		case CEE_LDLOC_S:
		case CEE_LDLOCA_S:
			code_bounds_check (2);
			push_local (&ctx, ip[1], *ip == CEE_LDLOCA_S);
			ip += 2;
			break;

		case CEE_UNUSED99:
			ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Use of the `unused' opcode"));
			++ip;
			break; 

		case CEE_DUP: {
			ILStackDesc * top;
			if (!check_underflow (&ctx, 1))
				break;
			if (!check_overflow (&ctx))
				break;
			top = stack_pop_safe (&ctx);
			copy_stack_value (stack_push (&ctx), top); 
			copy_stack_value (stack_push (&ctx), top);
			++ip;
			break;
		}

		case CEE_JMP:
			code_bounds_check (5);
			if (ctx.eval.size)
				ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Eval stack must be empty in jmp at 0x%04x", ip_offset));
			token = read32 (ip + 1);
			if (in_any_block (ctx.header, ip_offset))
				ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("jmp cannot escape exception blocks at 0x%04x", ip_offset));

			CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Intruction jmp is not verifiable at 0x%04x", ctx.ip_offset));
			/*
			 * FIXME: check signature, retval, arguments etc.
			 */
			ip += 5;
			break;
		case CEE_CALL:
		case CEE_CALLVIRT:
			code_bounds_check (5);
			do_invoke_method (&ctx, read32 (ip + 1), *ip == CEE_CALLVIRT);
			ip += 5;
			break;

		case CEE_CALLI:
			code_bounds_check (5);
			token = read32 (ip + 1);
			/*
			 * FIXME: check signature, retval, arguments etc.
			 * FIXME: check requirements for tail call
			 */
			CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Intruction calli is not verifiable at 0x%04x", ctx.ip_offset));
			ip += 5;
			break;
		case CEE_BR_S:
			code_bounds_check (2);
			do_static_branch (&ctx, (signed char)ip [1] + 2);
			need_merge = 1;
			ip += 2;
			start = 1;
			break;

		case CEE_BRFALSE_S:
		case CEE_BRTRUE_S:
			code_bounds_check (2);
			do_boolean_branch_op (&ctx, (signed char)ip [1] + 2);
			ip += 2;
			need_merge = 1;
			break;

		case CEE_BR:
			code_bounds_check (5);
			do_static_branch (&ctx, (gint32)read32 (ip + 1) + 5);
			need_merge = 1;
			ip += 5;
			start = 1;
			break;

		case CEE_BRFALSE:
		case CEE_BRTRUE:
			code_bounds_check (5);
			do_boolean_branch_op (&ctx, (gint32)read32 (ip + 1) + 5);
			ip += 5;
			need_merge = 1;
			break;

		case CEE_SWITCH: {
			guint32 entries;
			code_bounds_check (5);
			entries = read32 (ip + 1);

			if (entries > 0xFFFFFFFFU / sizeof (guint32))
				ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Too many switch entries %x at 0x%04x", entries, ctx.ip_offset));

			ip += 5;
			code_bounds_check (sizeof (guint32) * entries);
			
			do_switch (&ctx, entries, ip);
			ip += sizeof (guint32) * entries;
			break;
		}
		case CEE_LDIND_I1:
		case CEE_LDIND_U1:
		case CEE_LDIND_I2:
		case CEE_LDIND_U2:
		case CEE_LDIND_I4:
		case CEE_LDIND_U4:
		case CEE_LDIND_I8:
		case CEE_LDIND_I:
		case CEE_LDIND_R4:
		case CEE_LDIND_R8:
		case CEE_LDIND_REF:
			do_load_indirect (&ctx, *ip);
			++ip;
			break;
			
		case CEE_STIND_REF:
		case CEE_STIND_I1:
		case CEE_STIND_I2:
		case CEE_STIND_I4:
		case CEE_STIND_I8:
		case CEE_STIND_R4:
		case CEE_STIND_R8:
		case CEE_STIND_I:
			do_store_indirect (&ctx, *ip);
			++ip;
			break;

		case CEE_NOT:
		case CEE_NEG:
			do_unary_math_op (&ctx, *ip);
			++ip;
			break;

		case CEE_CONV_I1:
		case CEE_CONV_I2:
		case CEE_CONV_I4:
		case CEE_CONV_U1:
		case CEE_CONV_U2:
		case CEE_CONV_U4:
			do_conversion (&ctx, TYPE_I4);
			++ip;
			break;			

		case CEE_CONV_I8:
		case CEE_CONV_U8:
			do_conversion (&ctx, TYPE_I8);
			++ip;
			break;			

		case CEE_CONV_R4:
		case CEE_CONV_R8:
		case CEE_CONV_R_UN:
			do_conversion (&ctx, TYPE_R8);
			++ip;
			break;			

		case CEE_CONV_I:
		case CEE_CONV_U:
			do_conversion (&ctx, TYPE_NATIVE_INT);
			++ip;
			break;

		case CEE_CPOBJ:
			code_bounds_check (5);
			do_cpobj (&ctx, read32 (ip + 1));
			ip += 5;
			break;

		case CEE_LDOBJ:
			code_bounds_check (5);
			do_ldobj_value (&ctx, read32 (ip + 1));
			ip += 5;
			break;

		case CEE_LDSTR:
			code_bounds_check (5);
			do_ldstr (&ctx, read32 (ip + 1));
			ip += 5;
			break;

		case CEE_NEWOBJ:
			code_bounds_check (5);
			do_newobj (&ctx, read32 (ip + 1));
			ip += 5;
			break;

		case CEE_CASTCLASS:
		case CEE_ISINST:
			code_bounds_check (5);
			do_cast (&ctx, read32 (ip + 1), *ip == CEE_CASTCLASS ? "castclass" : "isinst");
			ip += 5;
			break;

		case CEE_UNUSED58:
		case CEE_UNUSED1:
			ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Use of the `unused' opcode"));
			++ip;
			break;

		case CEE_UNBOX:
			code_bounds_check (5);
			do_unbox_value (&ctx, read32 (ip + 1));
			ip += 5;
			break;

		case CEE_THROW:
			do_throw (&ctx);
			start = 1;
			++ip;
			break;

		case CEE_LDFLD:
		case CEE_LDFLDA:
			code_bounds_check (5);
			do_push_field (&ctx, read32 (ip + 1), *ip == CEE_LDFLDA);
			ip += 5;
			break;

		case CEE_LDSFLD:
		case CEE_LDSFLDA:
			code_bounds_check (5);
			do_push_static_field (&ctx, read32 (ip + 1), *ip == CEE_LDSFLDA);
			ip += 5;
			break;

		case CEE_STFLD:
			code_bounds_check (5);
			do_store_field (&ctx, read32 (ip + 1));
			ip += 5;
			break;

		case CEE_STSFLD:
			code_bounds_check (5);
			do_store_static_field (&ctx, read32 (ip + 1));
			ip += 5;
			break;

		case CEE_STOBJ:
			code_bounds_check (5);
			do_stobj (&ctx, read32 (ip + 1));
			ip += 5;
			break;

		case CEE_CONV_OVF_I1_UN:
		case CEE_CONV_OVF_I2_UN:
		case CEE_CONV_OVF_I4_UN:
		case CEE_CONV_OVF_U1_UN:
		case CEE_CONV_OVF_U2_UN:
		case CEE_CONV_OVF_U4_UN:
			do_conversion (&ctx, TYPE_I4);
			++ip;
			break;			

		case CEE_CONV_OVF_I8_UN:
		case CEE_CONV_OVF_U8_UN:
			do_conversion (&ctx, TYPE_I8);
			++ip;
			break;			

		case CEE_CONV_OVF_I_UN:
		case CEE_CONV_OVF_U_UN:
			do_conversion (&ctx, TYPE_NATIVE_INT);
			++ip;
			break;

		case CEE_BOX:
			code_bounds_check (5);
			do_box_value (&ctx, read32 (ip + 1));
			ip += 5;
			break;

		case CEE_NEWARR:
			code_bounds_check (5);
			do_newarr (&ctx, read32 (ip + 1));
			ip += 5;
			break;

		case CEE_LDLEN:
			do_ldlen (&ctx);
			++ip;
			break;

		case CEE_LDELEMA:
			code_bounds_check (5);
			do_ldelema (&ctx, read32 (ip + 1));
			ip += 5;
			break;

		case CEE_LDELEM_I1:
		case CEE_LDELEM_U1:
		case CEE_LDELEM_I2:
		case CEE_LDELEM_U2:
		case CEE_LDELEM_I4:
		case CEE_LDELEM_U4:
		case CEE_LDELEM_I8:
		case CEE_LDELEM_I:
		case CEE_LDELEM_R4:
		case CEE_LDELEM_R8:
		case CEE_LDELEM_REF:
			do_ldelem (&ctx, *ip, 0);
			++ip;
			break;

		case CEE_STELEM_I:
		case CEE_STELEM_I1:
		case CEE_STELEM_I2:
		case CEE_STELEM_I4:
		case CEE_STELEM_I8:
		case CEE_STELEM_R4:
		case CEE_STELEM_R8:
		case CEE_STELEM_REF:
			do_stelem (&ctx, *ip, 0);
			++ip;
			break;

		case CEE_LDELEM:
			code_bounds_check (5);
			do_ldelem (&ctx, *ip, read32 (ip + 1));
			ip += 5;
			break;

		case CEE_STELEM:
			code_bounds_check (5);
			do_stelem (&ctx, *ip, read32 (ip + 1));
			ip += 5;
			break;
			
		case CEE_UNBOX_ANY:
			code_bounds_check (5);
			do_unbox_any (&ctx, read32 (ip + 1));
			ip += 5;
			break;

		case CEE_CONV_OVF_I1:
		case CEE_CONV_OVF_U1:
		case CEE_CONV_OVF_I2:
		case CEE_CONV_OVF_U2:
		case CEE_CONV_OVF_I4:
		case CEE_CONV_OVF_U4:
			do_conversion (&ctx, TYPE_I4);
			++ip;
			break;

		case CEE_CONV_OVF_I8:
		case CEE_CONV_OVF_U8:
			do_conversion (&ctx, TYPE_I8);
			++ip;
			break;

		case CEE_CONV_OVF_I:
		case CEE_CONV_OVF_U:
			do_conversion (&ctx, TYPE_NATIVE_INT);
			++ip;
			break;

		case CEE_REFANYVAL:
			code_bounds_check (5);
			do_refanyval (&ctx, read32 (ip + 1));
			ip += 5;
			break;

		case CEE_CKFINITE:
			do_ckfinite (&ctx);
			++ip;
			break;

		case CEE_MKREFANY:
			code_bounds_check (5);
			do_mkrefany (&ctx,  read32 (ip + 1));
			ip += 5;
			break;

		case CEE_LDTOKEN:
			code_bounds_check (5);
			do_load_token (&ctx, read32 (ip + 1));
			ip += 5;
			break;

		case CEE_ENDFINALLY:
			if (!is_correct_endfinally (ctx.header, ip_offset))
				ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("endfinally must be used inside a finally/fault handler at 0x%04x", ctx.ip_offset));
			ctx.eval.size = 0;
			start = 1;
			++ip;
			break;

		case CEE_LEAVE:
			code_bounds_check (5);
			do_leave (&ctx, read32 (ip + 1) + 5);
			ip += 5;
			start = 1;
			need_merge = 1;
			break;

		case CEE_LEAVE_S:
			code_bounds_check (2);
			do_leave (&ctx, (signed char)ip [1] + 2);
			ip += 2;
			start = 1;
			need_merge = 1;
			break;

		case CEE_PREFIX1:
			code_bounds_check (2);
			++ip;
			switch (*ip) {
			case CEE_STLOC:
				code_bounds_check (3);
				store_local (&ctx, read16 (ip + 1));
				ip += 3;
				break;

			case CEE_CEQ:
				do_cmp_op (&ctx, cmp_br_eq_op, *ip);
				++ip;
				break;

			case CEE_CGT:
			case CEE_CGT_UN:
			case CEE_CLT:
			case CEE_CLT_UN:
				do_cmp_op (&ctx, cmp_br_op, *ip);
				++ip;
				break;

			case CEE_STARG:
				code_bounds_check (3);
				store_arg (&ctx, read16 (ip + 1) );
				ip += 3;
				break;


			case CEE_ARGLIST:
				if (!check_overflow (&ctx))
					break;
				if (ctx.signature->call_convention != MONO_CALL_VARARG)
					ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Cannot use arglist on method without VARGARG calling convention at 0x%04x", ctx.ip_offset));
				set_stack_value (&ctx, stack_push (&ctx), &mono_defaults.argumenthandle_class->byval_arg, FALSE);
				++ip;
				break;
	
			case CEE_LDFTN:
				code_bounds_check (5);
				do_load_function_ptr (&ctx, read32 (ip + 1), FALSE);
				ip += 5;
				break;

			case CEE_LDVIRTFTN:
				code_bounds_check (5);
				do_load_function_ptr (&ctx, read32 (ip + 1), TRUE);
				ip += 5;
				break;

			case CEE_LDARG:
			case CEE_LDARGA:
				code_bounds_check (3);
				push_arg (&ctx, read16 (ip + 1),  *ip == CEE_LDARGA);
				ip += 3;
				break;

			case CEE_LDLOC:
			case CEE_LDLOCA:
				code_bounds_check (3);
				push_local (&ctx, read16 (ip + 1), *ip == CEE_LDLOCA);
				ip += 3;
				break;

			case CEE_LOCALLOC:
				do_localloc (&ctx);
				++ip;
				break;

			case CEE_UNUSED56:
			case CEE_UNUSED57:
			case CEE_UNUSED70:
			case CEE_UNUSED:
				ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Use of the `unused' opcode"));
				++ip;
				break;
			case CEE_ENDFILTER:
				do_endfilter (&ctx);
				start = 1;
				++ip;
				break;
			case CEE_UNALIGNED_:
				code_bounds_check (2);
				prefix |= PREFIX_UNALIGNED;
				ip += 2;
				break;
			case CEE_VOLATILE_:
				prefix |= PREFIX_VOLATILE;
				++ip;
				break;
			case CEE_TAIL_:
				prefix |= PREFIX_TAIL;
				++ip;
				if (ip < end && (*ip != CEE_CALL && *ip != CEE_CALLI && *ip != CEE_CALLVIRT))
					ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("tail prefix must be used only with call opcodes at 0x%04x", ip_offset));
				break;

			case CEE_INITOBJ:
				code_bounds_check (5);
				do_initobj (&ctx, read32 (ip + 1));
				ip += 5;
				break;

			case CEE_CONSTRAINED_:
				code_bounds_check (5);
				ctx.constrained_type = get_boxable_mono_type (&ctx, read32 (ip + 1), "constrained.");
				prefix |= PREFIX_CONSTRAINED;
				ip += 5;
				break;
	
			case CEE_READONLY_:
				prefix |= PREFIX_READONLY;
				ip++;
				break;

			case CEE_CPBLK:
				CLEAR_PREFIX (&ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
				if (!check_underflow (&ctx, 3))
					break;
				CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Instruction cpblk is not verifiable at 0x%04x", ctx.ip_offset));
				ip++;
				break;
				
			case CEE_INITBLK:
				CLEAR_PREFIX (&ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
				if (!check_underflow (&ctx, 3))
					break;
				CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Instruction initblk is not verifiable at 0x%04x", ctx.ip_offset));
				ip++;
				break;
				
			case CEE_NO_:
				ip += 2;
				break;
			case CEE_RETHROW:
				if (!is_correct_rethrow (ctx.header, ip_offset))
					ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("rethrow must be used inside a catch handler at 0x%04x", ctx.ip_offset));
				ctx.eval.size = 0;
				start = 1;
				++ip;
				break;

			case CEE_SIZEOF:
				code_bounds_check (5);
				do_sizeof (&ctx, read32 (ip + 1));
				ip += 5;
				break;

			case CEE_REFANYTYPE:
				do_refanytype (&ctx);
				++ip;
				break;

			default:
				ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction FE %x at 0x%04x", *ip, ctx.ip_offset));
				++ip;
			}
			break;

		default:
			ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction %x at 0x%04x", *ip, ctx.ip_offset));
			++ip;
		}

		/*TODO we can fast detect a forward branch or exception block targeting code after prefix, we should fail fast*/
		if (prefix) {
			if (!ctx.prefix_set) //first prefix
				ctx.code [ctx.ip_offset].flags |= IL_CODE_FLAG_SEEN;
			ctx.prefix_set |= prefix;
			ctx.has_flags = TRUE;
			prefix = 0;
		} else {
			if (!ctx.has_flags)
				ctx.code [ctx.ip_offset].flags |= IL_CODE_FLAG_SEEN;

			if (ctx.prefix_set & PREFIX_CONSTRAINED)
				ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction after constrained prefix at 0x%04x", ctx.ip_offset));
			if (ctx.prefix_set & PREFIX_READONLY)
				ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction after readonly prefix at 0x%04x", ctx.ip_offset));
			if (ctx.prefix_set & PREFIX_VOLATILE)
				ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction after volatile prefix at 0x%04x", ctx.ip_offset));
			if (ctx.prefix_set & PREFIX_UNALIGNED)
				ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction after unaligned prefix at 0x%04x", ctx.ip_offset));
			ctx.prefix_set = prefix = 0;
			ctx.has_flags = FALSE;
		}
	}
	/*
	 * if ip != end we overflowed: mark as error.
	 */
	if ((ip != end || !start) && ctx.verifiable && !ctx.list) {
		ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Run ahead of method code at 0x%04x", ip_offset));
	}

	/*We should guard against the last decoded opcode, otherwise we might add errors that doesn't make sense.*/
	for (i = 0; i < ctx.code_size && i < ip_offset; ++i) {
		if (ctx.code [i].flags & IL_CODE_FLAG_WAS_TARGET) {
			if (!(ctx.code [i].flags & IL_CODE_FLAG_SEEN))
				ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Branch or exception block target middle of intruction at 0x%04x", i));

			if (ctx.code [i].flags & IL_CODE_DELEGATE_SEQUENCE)
				CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Branch to delegate code sequence at 0x%04x", i));
		}
		if ((ctx.code [i].flags & IL_CODE_LDFTN_DELEGATE_NONFINAL_VIRTUAL) && ctx.has_this_store)
			CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Invalid ldftn with virtual function in method with stdarg 0 at  0x%04x", i));

		if ((ctx.code [i].flags & IL_CODE_CALL_NONFINAL_VIRTUAL) && ctx.has_this_store)
			CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Invalid call to a non-final virtual function in method with stdarg.0 or ldarga.0 at  0x%04x", i));
	}

	if (mono_method_is_constructor (ctx.method) && !ctx.super_ctor_called && !ctx.method->klass->valuetype && ctx.method->klass != mono_defaults.object_class)
		CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Constructor not calling super\n"));

cleanup:
	if (ctx.code) {
		for (i = 0; i < ctx.header->code_size; ++i) {
			if (ctx.code [i].stack)
				g_free (ctx.code [i].stack);
		}
	}

	for (tmp = ctx.funptrs; tmp; tmp = tmp->next)
		g_free (tmp->data);
	g_slist_free (ctx.funptrs);

	for (tmp = ctx.exception_types; tmp; tmp = tmp->next)
		mono_metadata_free_type (tmp->data);
	g_slist_free (ctx.exception_types);

	for (i = 0; i < ctx.num_locals; ++i) {
		if (ctx.locals [i])
			mono_metadata_free_type (ctx.locals [i]);
	}
	for (i = 0; i < ctx.max_args; ++i) {
		if (ctx.params [i])
			mono_metadata_free_type (ctx.params [i]);
	}

	if (ctx.eval.stack)
		g_free (ctx.eval.stack);
	if (ctx.code)
		g_free (ctx.code);
	g_free (ctx.locals);
	g_free (ctx.params);
	mono_basic_block_free (original_bb);

	return ctx.list;

Project: mono

mono_type_is_valid_in_context (VerifyContext *ctx, MonoType *type)
{
	MonoClass *klass;

	if (type == NULL) {
		ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid null type at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
		return FALSE;
	}

	if (!is_valid_type_in_context (ctx, type)) {
		char *str = mono_type_full_name (type);
		ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid generic type (%s%s) (argument out of range or %s is not generic) at 0x%04x",
			type->type == MONO_TYPE_VAR ? "!" : "!!",
			str,
			type->type == MONO_TYPE_VAR ? "class" : "method",
			ctx->ip_offset),
			MONO_EXCEPTION_BAD_IMAGE);		
		g_free (str);
		return FALSE;
	}

	klass = mono_class_from_mono_type (type);
	mono_class_init (klass);
	if (mono_loader_get_last_error () || klass->exception_type != MONO_EXCEPTION_NONE) {
		if (klass->generic_class && !mono_class_is_valid_generic_instantiation (NULL, klass))
			ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid generic instantiation of type %s.%s at 0x%04x", klass->name_space, klass->name, ctx->ip_offset), MONO_EXCEPTION_TYPE_LOAD);
		else
			ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Could not load type %s.%s at 0x%04x", klass->name_space, klass->name, ctx->ip_offset), MONO_EXCEPTION_TYPE_LOAD);
		return FALSE;
	}

	if (klass->generic_class && klass->generic_class->container_class->exception_type != MONO_EXCEPTION_NONE) {
		ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Could not load type %s.%s at 0x%04x", klass->name_space, klass->name, ctx->ip_offset), MONO_EXCEPTION_TYPE_LOAD);
		return FALSE;
	}

	if (!klass->generic_class)
		return TRUE;

	if (!mono_class_is_valid_generic_instantiation (ctx, klass)) {
		ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid generic type instantiation of type %s.%s at 0x%04x", klass->name_space, klass->name, ctx->ip_offset), MONO_EXCEPTION_TYPE_LOAD);
		return FALSE;
	}

	if (!mono_class_repect_method_constraints (ctx, klass)) {
		ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid generic type instantiation of type %s.%s (generic args don't respect target's constraints) at 0x%04x", klass->name_space, klass->name, ctx->ip_offset), MONO_EXCEPTION_TYPE_LOAD);
		return FALSE;
	}

	return TRUE;
}

Project: mono

verify_assembly_table (MonoImage *image, GSList *list, int level)
{
	MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
	guint32 cols [MONO_ASSEMBLY_SIZE];
	const char *p;

	if (level & MONO_VERIFY_ERROR) {
		if (t->rows > 1)
			ADD_ERROR (list, g_strdup ("Assembly table may only have 0 or 1 rows"));
		mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);

		switch (cols [MONO_ASSEMBLY_HASH_ALG]) {
		case ASSEMBLY_HASH_NONE:
		case ASSEMBLY_HASH_MD5:
		case ASSEMBLY_HASH_SHA1:
			break;
		default:
			ADD_ERROR (list, g_strdup_printf ("Hash algorithm 0x%x unknown", cols [MONO_ASSEMBLY_HASH_ALG]));
		}

		if (!is_valid_assembly_flags (cols [MONO_ASSEMBLY_FLAGS]))
			ADD_ERROR (list, g_strdup_printf ("Invalid flags in assembly: 0x%x", cols [MONO_ASSEMBLY_FLAGS]));

		if (!is_valid_blob (image, cols [MONO_ASSEMBLY_PUBLIC_KEY], FALSE))
			ADD_ERROR (list, g_strdup ("Assembly public key is an invalid index"));

		if (!(p = is_valid_string (image, cols [MONO_ASSEMBLY_NAME], TRUE))) {
			ADD_ERROR (list, g_strdup ("Assembly name is invalid"));
		} else {
			if (strpbrk (p, ":\\/."))
				ADD_ERROR (list, g_strdup_printf ("Assembly name `%s' contains invalid chars", p));
		}

		if (!(p = is_valid_string (image, cols [MONO_ASSEMBLY_CULTURE], FALSE))) {
			ADD_ERROR (list, g_strdup ("Assembly culture is an invalid index"));
		} else {
			if (!is_valid_culture (p))
				ADD_ERROR (list, g_strdup_printf ("Assembly culture `%s' is invalid", p));
		}
	}
	return list;
}

Project: mono

verify_event_table (MonoImage *image, GSList *list, int level)
{
	MonoTableInfo *t = &image->tables [MONO_TABLE_EVENT];
	guint32 cols [MONO_EVENT_SIZE];
	const char *p;
	guint32 value, i;

	for (i = 0; i < t->rows; ++i) {
		mono_metadata_decode_row (t, i, cols, MONO_EVENT_SIZE);

		if (cols [MONO_EVENT_FLAGS] & ~(EVENT_SPECIALNAME|EVENT_RTSPECIALNAME)) {
			if (level & MONO_VERIFY_ERROR)
				ADD_ERROR (list, g_strdup_printf ("Flags 0x%04x invalid in Event row %d", cols [MONO_EVENT_FLAGS], i + 1));
		}
		if (!(p = is_valid_string (image, cols [MONO_EVENT_NAME], TRUE))) {
			if (level & MONO_VERIFY_ERROR)
				ADD_ERROR (list, g_strdup_printf ("Invalid name in Event row %d", i + 1));
		} else {
			if (level & MONO_VERIFY_CLS) {
				if (!is_valid_cls_ident (p))
					ADD_WARN (list, MONO_VERIFY_CLS, g_strdup_printf ("Invalid CLS name '%s` in Event row %d", p, i + 1));
			}
		}

		if (level & MONO_VERIFY_ERROR && cols [MONO_EVENT_TYPE]) {
			value = cols [MONO_EVENT_TYPE] >> MONO_TYPEDEFORREF_BITS;
			switch (cols [MONO_EVENT_TYPE] & MONO_TYPEDEFORREF_MASK) {
			case MONO_TYPEDEFORREF_TYPEDEF:
				if (!value || value > image->tables [MONO_TABLE_TYPEDEF].rows)
					ADD_ERROR (list, g_strdup_printf ("Type invalid in Event row %d", i + 1));
				break;
			case MONO_TYPEDEFORREF_TYPEREF:
				if (!value || value > image->tables [MONO_TABLE_TYPEREF].rows)
					ADD_ERROR (list, g_strdup_printf ("Type invalid in Event row %d", i + 1));
				break;
			case MONO_TYPEDEFORREF_TYPESPEC:
				if (!value || value > image->tables [MONO_TABLE_TYPESPEC].rows)
					ADD_ERROR (list, g_strdup_printf ("Type invalid in Event row %d", i + 1));
				break;
			default:
				ADD_ERROR (list, g_strdup_printf ("Type invalid in Event row %d", i + 1));
			}
		}
		/*
		 * FIXME: check that there is 1 add and remove row in methodsemantics
		 * and 0 or 1 raise and 0 or more other (maybe it's better to check for 
		 * these while checking methodsemantics).
		 * check for duplicated names for the same type [ERROR]
		 * check for CLS duplicate names for the same type [CLS]
		 */
	}
	return list;
}

Project: mono

verify_constant_table (MonoImage *image, GSList *list, int level)
{
	MonoTableInfo *t = &image->tables [MONO_TABLE_CONSTANT];
	guint32 cols [MONO_CONSTANT_SIZE];
	guint32 value, i;
	GHashTable *dups = g_hash_table_new (NULL, NULL);

	for (i = 0; i < t->rows; ++i) {
		mono_metadata_decode_row (t, i, cols, MONO_CONSTANT_SIZE);

		if (level & MONO_VERIFY_ERROR)
			if (g_hash_table_lookup (dups, GUINT_TO_POINTER (cols [MONO_CONSTANT_PARENT])))
				ADD_ERROR (list, g_strdup_printf ("Parent 0x%08x is duplicated in Constant row %d", cols [MONO_CONSTANT_PARENT], i + 1));
		g_hash_table_insert (dups, GUINT_TO_POINTER (cols [MONO_CONSTANT_PARENT]),
				GUINT_TO_POINTER (cols [MONO_CONSTANT_PARENT]));

		switch (cols [MONO_CONSTANT_TYPE]) {
		case MONO_TYPE_U1: /* LAMESPEC: it says I1...*/
		case MONO_TYPE_U2:
		case MONO_TYPE_U4:
		case MONO_TYPE_U8:
			if (level & MONO_VERIFY_CLS)
				ADD_WARN (list, MONO_VERIFY_CLS, g_strdup_printf ("Type 0x%x not CLS compliant in Constant row %d", cols [MONO_CONSTANT_TYPE], i + 1));
		case MONO_TYPE_BOOLEAN:
		case MONO_TYPE_CHAR:
		case MONO_TYPE_I1:
		case MONO_TYPE_I2:
		case MONO_TYPE_I4:
		case MONO_TYPE_I8:
		case MONO_TYPE_R4:
		case MONO_TYPE_R8:
		case MONO_TYPE_STRING:
		case MONO_TYPE_CLASS:
			break;
		default:
			if (level & MONO_VERIFY_ERROR)
				ADD_ERROR (list, g_strdup_printf ("Type 0x%x is invalid in Constant row %d", cols [MONO_CONSTANT_TYPE], i + 1));
		}
		if (level & MONO_VERIFY_ERROR) {
			value = cols [MONO_CONSTANT_PARENT] >> MONO_HASCONSTANT_BITS;
			switch (cols [MONO_CONSTANT_PARENT] & MONO_HASCONSTANT_MASK) {
			case MONO_HASCONSTANT_FIEDDEF:
				if (value > image->tables [MONO_TABLE_FIELD].rows)
					ADD_ERROR (list, g_strdup_printf ("Parent (field) is invalid in Constant row %d", i + 1));
				break;
			case MONO_HASCONSTANT_PARAM:
				if (value > image->tables [MONO_TABLE_PARAM].rows)
					ADD_ERROR (list, g_strdup_printf ("Parent (param) is invalid in Constant row %d", i + 1));
				break;
			case MONO_HASCONSTANT_PROPERTY:
				if (value > image->tables [MONO_TABLE_PROPERTY].rows)
					ADD_ERROR (list, g_strdup_printf ("Parent (property) is invalid in Constant row %d", i + 1));
				break;
			default:
				ADD_ERROR (list, g_strdup_printf ("Parent is invalid in Constant row %d", i + 1));
				break;
			}
		}
		if (level & MONO_VERIFY_CLS) {
			/* 
			 * FIXME: verify types is consistent with the enum type
			 * is parent is an enum.
			 */
		}
	}
	g_hash_table_destroy (dups);
	return list;
}

Project: mono

is_valid_assembly_flags (guint32 flags) {
	/* Metadata: 22.1.2 */
	flags &= ~(0x8000 | 0x4000); /* ignore reserved bits 0x0030? */
	return ((flags == 1) || (flags == 0));
}

Project: mono

verifier_load_field (VerifyContext *ctx, int token, MonoClass **out_klass, const char *opcode) {
	MonoClassField *field;
	MonoClass *klass = NULL;

	if (!IS_FIELD_DEF_OR_REF (token) || !token_bounds_check (ctx->image, token)) {
		ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid field token 0x%08x for %s at 0x%04x", token, opcode, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
		return NULL;
	}

	field = mono_field_from_token (ctx->image, token, &klass, ctx->generic_context);
	if (!field || !field->parent || !klass) {
		ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Cannot load field from token 0x%08x for %s at 0x%04x", token, opcode, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
		return NULL;
	}

	if (!mono_type_is_valid_in_context (ctx, &klass->byval_arg))
		return NULL;

	*out_klass = klass;
	return field;
}

Project: mono

verify_assemblyref_table (MonoImage *image, GSList *list, int level)
{
	MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF];
	guint32 cols [MONO_ASSEMBLYREF_SIZE];
	const char *p;
	int i;

	if (level & MONO_VERIFY_ERROR) {
		for (i = 0; i < t->rows; ++i) {
			mono_metadata_decode_row (t, i, cols, MONO_ASSEMBLYREF_SIZE);
			if (!is_valid_assembly_flags (cols [MONO_ASSEMBLYREF_FLAGS]))
				ADD_ERROR (list, g_strdup_printf ("Invalid flags in assemblyref row %d: 0x%x", i + 1, cols [MONO_ASSEMBLY_FLAGS]));

			if (!is_valid_blob (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], FALSE))
				ADD_ERROR (list, g_strdup_printf ("AssemblyRef public key in row %d is an invalid index", i + 1));

			if (!(p = is_valid_string (image, cols [MONO_ASSEMBLYREF_CULTURE], FALSE))) {
				ADD_ERROR (list, g_strdup_printf ("AssemblyRef culture in row %d is invalid", i + 1));
			} else {
				if (!is_valid_culture (p))
					ADD_ERROR (list, g_strdup_printf ("AssemblyRef culture `%s' in row %d is invalid", p, i + 1));
			}

			if (cols [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob (image, cols [MONO_ASSEMBLYREF_HASH_VALUE], TRUE))
				ADD_ERROR (list, g_strdup_printf ("AssemblyRef hash value in row %d is invalid or not null and empty", i + 1));
		}
	}
	if (level & MONO_VERIFY_WARNING) {
		/* check for duplicated rows */
		for (i = 0; i < t->rows; ++i) {
		}
	}
	return list;
}

Project: mono

mono_method_body_get_object (MonoDomain *domain, MonoMethod *method)
{
	static MonoClass *System_Reflection_MethodBody = NULL;
	static MonoClass *System_Reflection_LocalVariableInfo = NULL;
	static MonoClass *System_Reflection_ExceptionHandlingClause = NULL;
	MonoReflectionMethodBody *ret;
	MonoMethodNormal *mn;
	MonoMethodHeader *header;
	MonoImage *image;
	guint32 method_rva, local_var_sig_token;
    char *ptr;
	unsigned char format, flags;
	int i;

	if (!System_Reflection_MethodBody)
		System_Reflection_MethodBody = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "MethodBody");
	if (!System_Reflection_LocalVariableInfo)
		System_Reflection_LocalVariableInfo = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "LocalVariableInfo");
	if (!System_Reflection_ExceptionHandlingClause)
		System_Reflection_ExceptionHandlingClause = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "ExceptionHandlingClause");

	CHECK_OBJECT (MonoReflectionMethodBody *, method, NULL);

	if ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
		(method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
	    (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
	    (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME))
		return NULL;

	mn = (MonoMethodNormal *)method;
	image = method->klass->image;
	header = mono_method_get_header (method);

	if (!image->dynamic) {
		/* Obtain local vars signature token */
		method_rva = mono_metadata_decode_row_col (&image->tables [MONO_TABLE_METHOD], mono_metadata_token_index (method->token) - 1, MONO_METHOD_RVA);
		ptr = mono_image_rva_map (image, method_rva);
		flags = *(const unsigned char *) ptr;
		format = flags & METHOD_HEADER_FORMAT_MASK;
		switch (format){
		case METHOD_HEADER_TINY_FORMAT:
			local_var_sig_token = 0;
			break;
		case METHOD_HEADER_FAT_FORMAT:
			ptr += 2;
			ptr += 2;
			ptr += 4;
			local_var_sig_token = read32 (ptr);
			break;
		default:
			g_assert_not_reached ();
		}
	} else
		local_var_sig_token = 0; //FIXME

	ret = (MonoReflectionMethodBody*)mono_object_new (domain, System_Reflection_MethodBody);

	ret->init_locals = header->init_locals;
	ret->max_stack = header->max_stack;
	ret->local_var_sig_token = local_var_sig_token;
	MONO_OBJECT_SETREF (ret, il, mono_array_new_cached (domain, mono_defaults.byte_class, header->code_size));
	memcpy (mono_array_addr (ret->il, guint8, 0), header->code, header->code_size);

	/* Locals */
	MONO_OBJECT_SETREF (ret, locals, mono_array_new_cached (domain, System_Reflection_LocalVariableInfo, header->num_locals));
	for (i = 0; i < header->num_locals; ++i) {
		MonoReflectionLocalVariableInfo *info = (MonoReflectionLocalVariableInfo*)mono_object_new (domain, System_Reflection_LocalVariableInfo);
		MONO_OBJECT_SETREF (info, local_type, mono_type_get_object (domain, header->locals [i]));
		info->is_pinned = header->locals [i]->pinned;
		info->local_index = i;
		mono_array_setref (ret->locals, i, info);
	}

	/* Exceptions */
	MONO_OBJECT_SETREF (ret, clauses, mono_array_new_cached (domain, System_Reflection_ExceptionHandlingClause, header->num_clauses));
	for (i = 0; i < header->num_clauses; ++i) {
		MonoReflectionExceptionHandlingClause *info = (MonoReflectionExceptionHandlingClause*)mono_object_new (domain, System_Reflection_ExceptionHandlingClause);
		MonoExceptionClause *clause = &header->clauses [i];

		info->flags = clause->flags;
		info->try_offset = clause->try_offset;
		info->try_length = clause->try_len;
		info->handler_offset = clause->handler_offset;
		info->handler_length = clause->handler_len;
		if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER)
			info->filter_offset = clause->data.filter_offset;
		else if (clause->data.catch_class)
			MONO_OBJECT_SETREF (info, catch_type, mono_type_get_object (mono_domain_get (), &clause->data.catch_class->byval_arg));

		mono_array_setref (ret->clauses, i, info);
	}

	CACHE_OBJECT (MonoReflectionMethodBody *, method, ret, NULL);
	return ret;
}

Project: mono

verifier_load_method (VerifyContext *ctx, int token, const char *opcode) {
	MonoMethod* method;
	
	if (!IS_METHOD_DEF_OR_REF_OR_SPEC (token) || !token_bounds_check (ctx->image, token)) {
		ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid method token 0x%08x for %s at 0x%04x", token, opcode, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
		return NULL;
	}

	method = mono_get_method_full (ctx->image, token, NULL, ctx->generic_context);

	if (!method) {
		ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Cannot load method from token 0x%08x for %s at 0x%04x", token, opcode, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
		return NULL;
	}
	
	if (mono_method_is_valid_in_context (ctx, method) == RESULT_INVALID)
		return NULL;

	return method;
}

Project: mono

verify_type_compatibility_full (VerifyContext *ctx, MonoType *target, MonoType *candidate, gboolean strict)
{
#define IS_ONE_OF3(T, A, B, C) (T == A || T == B || T == C)
#define IS_ONE_OF2(T, A, B) (T == A || T == B)

	MonoType *original_candidate = candidate;
	VERIFIER_DEBUG ( printf ("checking type compatibility %s x %s strict %d\n", mono_type_full_name (target), mono_type_full_name (candidate), strict); );

 	/*only one is byref */
	if (candidate->byref ^ target->byref) {
		/* converting from native int to byref*/
		if (get_stack_type (candidate) == TYPE_NATIVE_INT && target->byref) {
			CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("using byref native int at 0x%04x", ctx->ip_offset));
			return TRUE;
		}
		return FALSE;
	}
	strict |= target->byref;
	/*From now on we don't care about byref anymore, so it's ok to discard it here*/
	candidate = mono_type_get_underlying_type_any (candidate);

handle_enum:
	switch (target->type) {
	case MONO_TYPE_VOID:
		return candidate->type == MONO_TYPE_VOID;
	case MONO_TYPE_I1:
	case MONO_TYPE_U1:
	case MONO_TYPE_BOOLEAN:
		if (strict)
			return IS_ONE_OF3 (candidate->type, MONO_TYPE_I1, MONO_TYPE_U1, MONO_TYPE_BOOLEAN);
	case MONO_TYPE_I2:
	case MONO_TYPE_U2:
	case MONO_TYPE_CHAR:
		if (strict)
			return IS_ONE_OF3 (candidate->type, MONO_TYPE_I2, MONO_TYPE_U2, MONO_TYPE_CHAR);
	case MONO_TYPE_I4:
	case MONO_TYPE_U4: {
		gboolean is_native_int = IS_ONE_OF2 (candidate->type, MONO_TYPE_I, MONO_TYPE_U);
		gboolean is_int4 = IS_ONE_OF2 (candidate->type, MONO_TYPE_I4, MONO_TYPE_U4);
		if (strict)
			return is_native_int || is_int4;
		return is_native_int || get_stack_type (candidate) == TYPE_I4;
	}

	case MONO_TYPE_I8:
	case MONO_TYPE_U8:
		return IS_ONE_OF2 (candidate->type, MONO_TYPE_I8, MONO_TYPE_U8);

	case MONO_TYPE_R4:
	case MONO_TYPE_R8:
		if (strict)
			return candidate->type == target->type;
		return IS_ONE_OF2 (candidate->type, MONO_TYPE_R4, MONO_TYPE_R8);

	case MONO_TYPE_I:
	case MONO_TYPE_U: {
		gboolean is_native_int = IS_ONE_OF2 (candidate->type, MONO_TYPE_I, MONO_TYPE_U);
		gboolean is_int4 = IS_ONE_OF2 (candidate->type, MONO_TYPE_I4, MONO_TYPE_U4);
		if (strict)
			return is_native_int || is_int4;
		return is_native_int || get_stack_type (candidate) == TYPE_I4;
	}

	case MONO_TYPE_PTR:
		if (candidate->type != MONO_TYPE_PTR)
			return FALSE;
		/* check the underlying type */
		return verify_type_compatibility_full (ctx, target->data.type, candidate->data.type, TRUE);

	case MONO_TYPE_FNPTR: {
		MonoMethodSignature *left, *right;
		if (candidate->type != MONO_TYPE_FNPTR)
			return FALSE;

		left = mono_type_get_signature (target);
		right = mono_type_get_signature (candidate);
		return mono_metadata_signature_equal (left, right) && left->call_convention == right->call_convention;
	}

	case MONO_TYPE_GENERICINST: {
		MonoClass *target_klass;
		MonoClass *candidate_klass;
		if (mono_type_is_enum_type (target)) {
			target = mono_type_get_underlying_type_any (target);
			if (!target)
				return FALSE;
			goto handle_enum;
		}
		/*
		 * VAR / MVAR compatibility must be checked by verify_stack_type_compatibility
		 * to take boxing status into account.
		 */
		if (mono_type_is_generic_argument (original_candidate))
			return FALSE;

		target_klass = mono_class_from_mono_type (target);
		candidate_klass = mono_class_from_mono_type (candidate);
		if (mono_class_is_nullable (target_klass)) {
			if (!mono_class_is_nullable (candidate_klass))
				return FALSE;
			return target_klass == candidate_klass;
		}
		
		return mono_class_is_assignable_from (target_klass, candidate_klass);
	}

	case MONO_TYPE_STRING:
		return candidate->type == MONO_TYPE_STRING;

	case MONO_TYPE_CLASS:
		/*
		 * VAR / MVAR compatibility must be checked by verify_stack_type_compatibility
		 * to take boxing status into account.
		 */
		if (mono_type_is_generic_argument (original_candidate))
			return FALSE;

		if (candidate->type == MONO_TYPE_VALUETYPE)
			return FALSE;

		/* If candidate is an enum it should return true for System.Enum and supertypes.
		 * That's why here we use the original type and not the underlying type.
		 */ 
		return mono_class_is_assignable_from (target->data.klass, mono_class_from_mono_type (original_candidate));

	case MONO_TYPE_OBJECT:
		return MONO_TYPE_IS_REFERENCE (candidate);

	case MONO_TYPE_SZARRAY: {
		MonoClass *left;
		MonoClass *right;
		if (candidate->type != MONO_TYPE_SZARRAY)
			return FALSE;

		left = mono_class_from_mono_type (target)->element_class;
		right = mono_class_from_mono_type (candidate)->element_class;
		return mono_class_is_assignable_from (left, right);
	}

	case MONO_TYPE_ARRAY:
		if (candidate->type != MONO_TYPE_ARRAY)
			return FALSE;
		return is_array_type_compatible (target, candidate);

	case MONO_TYPE_TYPEDBYREF:
		return candidate->type == MONO_TYPE_TYPEDBYREF;

	case MONO_TYPE_VALUETYPE: {
		MonoClass *target_klass;
		MonoClass *candidate_klass;

		if (candidate->type == MONO_TYPE_CLASS)
			return FALSE;

		target_klass = mono_class_from_mono_type (target);
		candidate_klass = mono_class_from_mono_type (candidate);
		if (target_klass == candidate_klass)
			return TRUE;
		if (mono_type_is_enum_type (target)) {
			target = mono_type_get_underlying_type_any (target);
			if (!target)
				return FALSE;
			goto handle_enum;
		}
		return FALSE;
	}

	case MONO_TYPE_VAR:
		if (candidate->type != MONO_TYPE_VAR)
			return FALSE;
		return mono_type_get_generic_param_num (candidate) == mono_type_get_generic_param_num (target);

	case MONO_TYPE_MVAR:
		if (candidate->type != MONO_TYPE_MVAR)
			return FALSE;
		return mono_type_get_generic_param_num (candidate) == mono_type_get_generic_param_num (target);

	default:
		VERIFIER_DEBUG ( printf ("unknown store type %d\n", target->type); );
		g_assert_not_reached ();
		return FALSE;
	}
	return 1;
#undef IS_ONE_OF3
#undef IS_ONE_OF2
}

Project: mono

verify_standalonesig_table (MonoImage *image, GSList *list, int level)
{
	MonoTableInfo *t = &image->tables [MONO_TABLE_STANDALONESIG];
	guint32 cols [MONO_STAND_ALONE_SIGNATURE_SIZE];
	const char *p;
	guint32 i;

	for (i = 0; i < t->rows; ++i) {
		mono_metadata_decode_row (t, i, cols, MONO_STAND_ALONE_SIGNATURE_SIZE);
		if (level & MONO_VERIFY_ERROR) {
			if (!is_valid_blob (image, cols [MONO_STAND_ALONE_SIGNATURE], TRUE)) {
				ADD_ERROR (list, g_strdup_printf ("Signature is invalid in StandAloneSig row %d", i + 1));
			} else {
				p = mono_metadata_blob_heap (image, cols [MONO_STAND_ALONE_SIGNATURE]);
				/* FIXME: check it's a valid locals or method sig.*/
			}
		}
	}
	return list;
}

Project: mono

verify_field_table (MonoImage *image, GSList *list, int level)
{
	MonoTableInfo *t = &image->tables [MONO_TABLE_FIELD];
	guint32 cols [MONO_FIELD_SIZE];
	const char *p;
	guint32 i, flags;

	for (i = 0; i < t->rows; ++i) {
		mono_metadata_decode_row (t, i, cols, MONO_FIELD_SIZE);
		/*
		 * Check this field has only one owner and that the owner is not 
		 * an interface (done in verify_typedef_table() )
		 */
		flags = cols [MONO_FIELD_FLAGS];
		switch (flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) {
		case FIELD_ATTRIBUTE_COMPILER_CONTROLLED:
		case FIELD_ATTRIBUTE_PRIVATE:
		case FIELD_ATTRIBUTE_FAM_AND_ASSEM:
		case FIELD_ATTRIBUTE_ASSEMBLY:
		case FIELD_ATTRIBUTE_FAMILY:
		case FIELD_ATTRIBUTE_FAM_OR_ASSEM:
		case FIELD_ATTRIBUTE_PUBLIC:
			break;
		default:
			if (level & MONO_VERIFY_ERROR)
				ADD_ERROR (list, g_strdup_printf ("Invalid access mask in Field row %d", i + 1));
			break;
		}
		if (level & MONO_VERIFY_ERROR) {
			if ((flags & FIELD_ATTRIBUTE_LITERAL) && (flags & FIELD_ATTRIBUTE_INIT_ONLY))
				ADD_ERROR (list, g_strdup_printf ("Literal and InitOnly cannot be both set in Field row %d", i + 1));
			if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
				ADD_ERROR (list, g_strdup_printf ("Literal needs also Static set in Field row %d", i + 1));
			if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
				ADD_ERROR (list, g_strdup_printf ("RTSpecialName needs also SpecialName set in Field row %d", i + 1));
			/*
			 * FIXME: check there is only one owner in the respective table.
			 * if (flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL)
			 * if (flags & FIELD_ATTRIBUTE_HAS_DEFAULT)
			 * if (flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA)
			 */
		}
		if (!(p = is_valid_string (image, cols [MONO_FIELD_NAME], TRUE))) {
			if (level & MONO_VERIFY_ERROR)
				ADD_ERROR (list, g_strdup_printf ("Invalid name in Field row %d", i + 1));
		} else {
			if (level & MONO_VERIFY_CLS) {
				if (!is_valid_cls_ident (p))
					ADD_WARN (list, MONO_VERIFY_CLS, g_strdup_printf ("Invalid CLS name '%s` in Field row %d", p, i + 1));
			}
		}
		/*
		 * check signature.
		 * if owner is module needs to be static, access mask needs to be compilercontrolled,
		 * public or private (not allowed in cls mode).
		 * if owner is an enum ...
		 */


	}
	return list;
}

Project: mono

is_valid_filename (const char *p)
{
	if (!*p)
		return 0;
	return strpbrk (p, "\\//:")? 0: 1;
}

Project: mono

do_stobj (VerifyContext *ctx, int token) 
{
	ILStackDesc *dest, *src;
	MonoType *type = get_boxable_mono_type (ctx, token, "stobj");
	CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);

	if (!type)
		return;

	if (!check_underflow (ctx, 2))
		return;

	src = stack_pop (ctx);
	dest = stack_pop (ctx);

	if (stack_slot_is_managed_mutability_pointer (dest))
		CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with stobj at 0x%04x", ctx->ip_offset));

	if (!stack_slot_is_managed_pointer (dest)) 
		CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid destination of stobj operation at 0x%04x", ctx->ip_offset));

	if (stack_slot_is_boxed_value (src) && !MONO_TYPE_IS_REFERENCE (src->type) && !MONO_TYPE_IS_REFERENCE (type))
		CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use stobj with a boxed source value that is not a reference type at 0x%04x", ctx->ip_offset));

	if (!verify_stack_type_compatibility (ctx, type, src))
		CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Token and source types of stobj don't match at 0x%04x", ctx->ip_offset));

	if (!verify_type_compatibility (ctx, mono_type_get_type_byval (dest->type), type))
		CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Destination and token types of stobj don't match at 0x%04x", ctx->ip_offset));
}

Project: mono

is_valid_culture (const char *cname)
{
	int i;
	int found;

	found = *cname == 0;
	for (i = 0; i < G_N_ELEMENTS (valid_cultures); ++i) {
		if (g_ascii_strcasecmp (valid_cultures [i], cname)) {
			found = 1;
			break;
		}
	}
	return found;
}

Project: mono

mono_class_is_constraint_compatible (MonoClass *candidate, MonoClass *target)
{
	if (candidate == target)
		return TRUE;
	if (target == mono_defaults.object_class)
			return TRUE;

	//setup_supertypes don't mono_class_init anything
	mono_class_setup_supertypes (candidate);
	mono_class_setup_supertypes (target);

	if (mono_class_has_parent (candidate, target))
		return TRUE;

	//if target is not a supertype it must be an interface
	if (!MONO_CLASS_IS_INTERFACE (target))
			return FALSE;

	if (candidate->image->dynamic && !candidate->wastypebuilder) {
		MonoReflectionTypeBuilder *tb = candidate->reflection_info;
		int j;
		if (tb->interfaces) {
			for (j = mono_array_length (tb->interfaces) - 1; j >= 0; --j) {
				MonoReflectionType *iface = mono_array_get (tb->interfaces, MonoReflectionType*, j);
				MonoClass *ifaceClass = mono_class_from_mono_type (iface->type);
				if (mono_class_is_constraint_compatible (ifaceClass, target)) {
					return TRUE;
				}
			}
		}
		return FALSE;
	}
	return mono_class_interface_implements_interface (candidate, target);
}

Project: mono

stack_copy (ILCodeDesc *to, ILCodeDesc *from)
{
	to->size = from->size;
	memcpy (to->stack, from->stack, sizeof (ILStackDesc) * from->size);
}

Project: mono

do_store_static_field (VerifyContext *ctx, int token) {
	MonoClassField *field;
	MonoClass *klass;
	ILStackDesc *value;
	CLEAR_PREFIX (ctx, PREFIX_VOLATILE);

	if (!check_underflow (ctx, 1))
		return;

	value = stack_pop (ctx);

	if (!(field = verifier_load_field (ctx, token, &klass, "stsfld")))
		return;

	if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) { 
		ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot store non static field at 0x%04x", ctx->ip_offset));
		return;
	}

	if (field->type->type == MONO_TYPE_TYPEDBYREF) {
		ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Typedbyref field is an unverfiable type in store static field at 0x%04x", ctx->ip_offset));
		return;
	}

	if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, NULL))
		CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);

	if (!verify_stack_type_compatibility (ctx, field->type, value))
		CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type %s in static field store at 0x%04x", stack_slot_get_name (value), ctx->ip_offset));	
}

Project: mono

is_valid_cls_ident (const char *p)
{
	/*
	 * FIXME: we need the full unicode glib support for this.
	 * Check: http://www.unicode.org/unicode/reports/tr15/Identifier.java
	 * We do the lame thing for now.
	 */
	if (!isalpha (*p))
		return 0;
	++p;
	while (*p) {
		if (!isalnum (*p) && *p != '_')
			return 0;
		++p;
	}
	return 1;
}

Project: mono

mono_type_create_fnptr_from_mono_method (VerifyContext *ctx, MonoMethod *method)
{
	MonoType *res = g_new0 (MonoType, 1);
	//FIXME use mono_method_get_signature_full
	res->data.method = mono_method_signature (method);
	res->type = MONO_TYPE_FNPTR;
	ctx->funptrs = g_slist_prepend (ctx->funptrs, res);
	return res;
}

Project: mono

verify_event_map_table (MonoImage *image, GSList *list, int level)
{
	MonoTableInfo *t = &image->tables [MONO_TABLE_EVENTMAP];
	guint32 cols [MONO_EVENT_MAP_SIZE];
	guint32 i, last_event;
	GHashTable *dups = g_hash_table_new (NULL, NULL);

	last_event = 0;

	for (i = 0; i < t->rows; ++i) {
		mono_metadata_decode_row (t, i, cols, MONO_EVENT_MAP_SIZE);
		if (level & MONO_VERIFY_ERROR)
			if (g_hash_table_lookup (dups, GUINT_TO_POINTER (cols [MONO_EVENT_MAP_PARENT])))
				ADD_ERROR (list, g_strdup_printf ("Parent 0x%08x is duplicated in Event Map row %d", cols [MONO_EVENT_MAP_PARENT], i + 1));
		g_hash_table_insert (dups, GUINT_TO_POINTER (cols [MONO_EVENT_MAP_PARENT]),
				GUINT_TO_POINTER (cols [MONO_EVENT_MAP_PARENT]));
		if (level & MONO_VERIFY_ERROR) {
			if (cols [MONO_EVENT_MAP_PARENT] > image->tables [MONO_TABLE_TYPEDEF].rows)
				ADD_ERROR (list, g_strdup_printf ("Parent 0x%08x is invalid in Event Map row %d", cols [MONO_EVENT_MAP_PARENT], i + 1));
			if (cols [MONO_EVENT_MAP_EVENTLIST] > image->tables [MONO_TABLE_EVENT].rows)
				ADD_ERROR (list, g_strdup_printf ("EventList 0x%08x is invalid in Event Map row %d", cols [MONO_EVENT_MAP_EVENTLIST], i + 1));

			if (cols [MONO_EVENT_MAP_EVENTLIST] <= last_event)
				ADD_ERROR (list, g_strdup_printf ("EventList overlap in Event Map row %d", i + 1));
			last_event = cols [MONO_EVENT_MAP_EVENTLIST];
		}
	}

	g_hash_table_destroy (dups);
	return list;
}

Project: mono

stack_push (VerifyContext *ctx)
{
	g_assert (ctx->eval.size < ctx->max_stack);
	return & ctx->eval.stack [ctx->eval.size++];
}

Project: mono

gboolean
mono_verifier_is_enabled_for_class (MonoClass *klass)
{
	return verify_all || (verifier_mode > MONO_VERIFIER_MODE_OFF && !klass->image->assembly->in_gac && klass->image != mono_defaults.corlib);

Project: mono

verify_moduleref_table (MonoImage *image, GSList *list, int level)
{
	MonoTableInfo *t = &image->tables [MONO_TABLE_MODULEREF];
	MonoTableInfo *tfile = &image->tables [MONO_TABLE_FILE];
	guint32 cols [MONO_MODULEREF_SIZE];
	const char *p, *pf;
	guint32 found, i, j, value;
	GHashTable *dups = g_hash_table_new (g_str_hash, g_str_equal);

	for (i = 0; i < t->rows; ++i) {
		mono_metadata_decode_row (t, i, cols, MONO_MODULEREF_SIZE);
		if (!(p = is_valid_string (image, cols [MONO_MODULEREF_NAME], TRUE))) {
			if (level & MONO_VERIFY_ERROR)
				ADD_ERROR (list, g_strdup_printf ("Invalid name in ModuleRef row %d", i + 1));
		} else {
			if (level & MONO_VERIFY_ERROR) {
				if (!is_valid_filename (p))
					ADD_ERROR (list, g_strdup_printf ("Invalid name '%s` in ModuleRef row %d", p, i + 1));
				else if (g_hash_table_lookup (dups, p)) {
					ADD_WARN (list, MONO_VERIFY_WARNING, g_strdup_printf ("Duplicate name '%s` in ModuleRef row %d", p, i + 1));
					g_hash_table_insert (dups, (gpointer)p, (gpointer)p);
					found = 0;
					for (j = 0; j < tfile->rows; ++j) {
						value = mono_metadata_decode_row_col (tfile, j, MONO_FILE_NAME);
						if ((pf = is_valid_string (image, value, TRUE)))
							if (strcmp (p, pf) == 0) {
								found = 1;
								break;
							}
					}
					if (!found)
						ADD_ERROR (list, g_strdup_printf ("Name '%s` in ModuleRef row %d doesn't have a match in File table", p, i + 1));
				}
			}
		}
	}
	g_hash_table_destroy (dups);
	return list;
}

Project: mono

do_invoke_method (VerifyContext *ctx, int method_token, gboolean virtual)
{
	int param_count, i;
	MonoMethodSignature *sig;
	ILStackDesc *value;
	MonoMethod *method;
	gboolean virt_check_this = FALSE;
	gboolean constrained = ctx->prefix_set & PREFIX_CONSTRAINED;

	if (!(method = verifier_load_method (ctx, method_token, virtual ? "callvirt" : "call")))
		return;

	if (virtual) {
		CLEAR_PREFIX (ctx, PREFIX_CONSTRAINED);

		if (method->klass->valuetype) // && !constrained ???
			CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use callvirtual with valuetype method at 0x%04x", ctx->ip_offset));

		if ((method->flags & METHOD_ATTRIBUTE_STATIC))
			CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use callvirtual with static method at 0x%04x", ctx->ip_offset));

	} else {
		if (method->flags & METHOD_ATTRIBUTE_ABSTRACT) 
			CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use call with an abstract method at 0x%04x", ctx->ip_offset));
		
		if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !(method->flags & METHOD_ATTRIBUTE_FINAL) && !(method->klass->flags & TYPE_ATTRIBUTE_SEALED)) {
			virt_check_this = TRUE;
			ctx->code [ctx->ip_offset].flags |= IL_CODE_CALL_NONFINAL_VIRTUAL;
		}
	}

	if (!(sig = mono_method_get_signature_full (method, ctx->image, method_token, ctx->generic_context)))
		sig = mono_method_get_signature (method, ctx->image, method_token);

	if (!sig) {
		char *name = mono_type_get_full_name (method->klass);
		ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Could not resolve signature of %s:%s at 0x%04x", name, method->name, ctx->ip_offset));
		g_free (name);
		return;
	}

	param_count = sig->param_count + sig->hasthis;
	if (!check_underflow (ctx, param_count))
		return;

	for (i = sig->param_count - 1; i >= 0; --i) {
		VERIFIER_DEBUG ( printf ("verifying argument %d\n", i); );
		value = stack_pop (ctx);
		if (!verify_stack_type_compatibility (ctx, sig->params[i], value)) {
			char *stack_name = stack_slot_full_name (value);
			char *sig_name = mono_type_full_name (sig->params [i]);
			CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible parameter with function signature: Calling method with signature (%s) but for argument %d there is a (%s) on stack at 0x%04x", sig_name, i, stack_name, ctx->ip_offset));
			g_free (stack_name);
			g_free (sig_name);
		}

		if (stack_slot_is_managed_mutability_pointer (value))
			CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer as argument of %s at 0x%04x", virtual ? "callvirt" : "call",  ctx->ip_offset));

		if ((ctx->prefix_set & PREFIX_TAIL) && stack_slot_is_managed_pointer (value)) {
			ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot  pass a byref argument to a tail %s at 0x%04x", virtual ? "callvirt" : "call",  ctx->ip_offset));
			return;
		}
	}

	if (sig->hasthis) {
		MonoType *type = &method->klass->byval_arg;
		ILStackDesc copy;

		if (mono_method_is_constructor (method) && !method->klass->valuetype) {
			if (!mono_method_is_constructor (ctx->method))
				CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot call a constructor outside one at 0x%04x", ctx->ip_offset));
			if (method->klass != ctx->method->klass->parent && method->klass != ctx->method->klass)
				CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot call a constructor to a type diferent that this or super at 0x%04x", ctx->ip_offset));

			ctx->super_ctor_called = TRUE;
			value = stack_pop_safe (ctx);
			if ((value->stype & THIS_POINTER_MASK) != THIS_POINTER_MASK)
				CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid 'this ptr' argument for constructor at 0x%04x", ctx->ip_offset));
		} else {
			value = stack_pop (ctx);
		}
			
		copy_stack_value (&copy, value);
		//TODO we should extract this to a 'drop_byref_argument' and use everywhere
		//Other parts of the code suffer from the same issue of 
		copy.type = mono_type_get_type_byval (copy.type);
		copy.stype &= ~POINTER_MASK;

		if (virt_check_this && !stack_slot_is_this_pointer (value) && !(method->klass->valuetype || stack_slot_is_boxed_value (value)))
			CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot call a non-final virtual method from an objet diferent thant the this pointer at 0x%04x", ctx->ip_offset));

		if (constrained && virtual) {
			if (!stack_slot_is_managed_pointer (value))
				CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Object is not a managed pointer for a constrained call at 0x%04x", ctx->ip_offset));
			if (!mono_metadata_type_equal_full (mono_type_get_type_byval (value->type), ctx->constrained_type, TRUE))
				CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Object not compatible with constrained type at 0x%04x", ctx->ip_offset));
			copy.stype |= BOXED_MASK;
		} else {
			if (stack_slot_is_managed_pointer (value) && !mono_class_from_mono_type (value->type)->valuetype)
				CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot call a reference type using a managed pointer to the this arg at 0x%04x", ctx->ip_offset));
	
			if (!virtual && mono_class_from_mono_type (value->type)->valuetype && !method->klass->valuetype && !stack_slot_is_boxed_value (value))
				CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot call a valuetype baseclass at 0x%04x", ctx->ip_offset));
	
			if (virtual && mono_class_from_mono_type (value->type)->valuetype && !stack_slot_is_boxed_value (value))
				CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a valuetype with callvirt at 0x%04x", ctx->ip_offset));
	
			if (method->klass->valuetype && (stack_slot_is_boxed_value (value) || !stack_slot_is_managed_pointer (value)))
				CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a boxed or literal valuetype to call a valuetype method at 0x%04x", ctx->ip_offset));
		}
		if (!verify_stack_type_compatibility (ctx, type, &copy)) {
			char *expected = mono_type_full_name (type);
			char *effective = stack_slot_full_name (&copy);
			char *method_name = mono_method_full_name (method, TRUE);
			CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible this argument on stack with method signature expected '%s' but got '%s' for a call to '%s' at 0x%04x",
					expected, effective, method_name, ctx->ip_offset));
			g_free (method_name);
			g_free (effective);
			g_free (expected);
		}

		if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, mono_class_from_mono_type (value->type))) {
			char *name = mono_method_full_name (method, TRUE);
			CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Method %s is not accessible at 0x%04x", name, ctx->ip_offset), MONO_EXCEPTION_METHOD_ACCESS);
			g_free (name);
		}

	} else if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, NULL)) {
		char *name = mono_method_full_name (method, TRUE);
		CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Method %s is not accessible at 0x%04x", name, ctx->ip_offset), MONO_EXCEPTION_METHOD_ACCESS);
		g_free (name);
	}

	if (sig->ret->type != MONO_TYPE_VOID) {
		if (check_overflow (ctx)) {
			value = stack_push (ctx);
			set_stack_value (ctx, value, sig->ret, FALSE);
			if ((ctx->prefix_set & PREFIX_READONLY) && method->klass->rank && !strcmp (method->name, "Address")) {
				ctx->prefix_set &= ~PREFIX_READONLY;
				value->stype |= CMMP_MASK;
			}
		}
	}

	if ((ctx->prefix_set & PREFIX_TAIL)) {
		if (!mono_delegate_ret_equal (mono_method_signature (ctx->method)->ret, sig->ret))
			CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Tail call with incompatible return type at 0x%04x", ctx->ip_offset));
		if (ctx->header->code [ctx->ip_offset + 5] != CEE_RET)
			CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Tail call not followed by ret at 0x%04x", ctx->ip_offset));
	}

}

Project: mono

is_valid_blob (MonoImage *image, guint32 blob_index, int notnull)
{
	guint32 size;
	const char *p, *blob_end;

	if (blob_index >= image->heap_blob.size)
		return 0;
	p = mono_metadata_blob_heap (image, blob_index);
	size = mono_metadata_decode_blob_size (p, &blob_end);
	if (blob_index + size + (blob_end-p) > image->heap_blob.size)
		return 0;
	if (notnull && !size)
		return 0;
	return 1;
}

Project: mono

verify_file_table (MonoImage *image, GSList *list, int level)
{
	MonoTableInfo *t = &image->tables [MONO_TABLE_FILE];
	guint32 cols [MONO_FILE_SIZE];
	const char *p;
	guint32 i;
	GHashTable *dups = g_hash_table_new (g_str_hash, g_str_equal);

	for (i = 0; i < t->rows; ++i) {
		mono_metadata_decode_row (t, i, cols, MONO_FILE_SIZE);
		if (level & MONO_VERIFY_ERROR) {
			if (cols [MONO_FILE_FLAGS] != FILE_CONTAINS_METADATA && cols [MONO_FILE_FLAGS] != FILE_CONTAINS_NO_METADATA)
				ADD_ERROR (list, g_strdup_printf ("Invalid flags in File row %d", i + 1));
			if (!is_valid_blob (image, cols [MONO_FILE_HASH_VALUE], TRUE))
				ADD_ERROR (list, g_strdup_printf ("File hash value in row %d is invalid or not null and empty", i + 1));
		}
		if (!(p = is_valid_string (image, cols [MONO_FILE_NAME], TRUE))) {
			if (level & MONO_VERIFY_ERROR)
				ADD_ERROR (list, g_strdup_printf ("Invalid name in File row %d", i + 1));
		} else {
			if (level & MONO_VERIFY_ERROR) {
				if (!is_valid_filename (p))
					ADD_ERROR (list, g_strdup_printf ("Invalid name '%s` in File row %d", p, i + 1));
				else if (g_hash_table_lookup (dups, p)) {
					ADD_ERROR (list, g_strdup_printf ("Duplicate name '%s` in File row %d", p, i + 1));
				}
				g_hash_table_insert (dups, (gpointer)p, (gpointer)p);
			}
		}
		/*
		 * FIXME: I don't understand what this means:
		 * If this module contains a row in the Assembly table (that is, if this module "holds the manifest") 
		 * then there shall not be any row in the File table for this module - i.e., no self-reference  [ERROR]
		 */

	}
	if (level & MONO_VERIFY_WARNING) {
		if (!t->rows && image->tables [MONO_TABLE_EXPORTEDTYPE].rows)
			ADD_WARN (list, MONO_VERIFY_WARNING, g_strdup ("ExportedType table should be empty if File table is empty"));
	}
	g_hash_table_destroy (dups);
	return list;
}

Project: mono

init_stack_with_value_at_exception_boundary (VerifyContext *ctx, ILCodeDesc *code, MonoClass *klass)
{
	MonoError error;
	MonoType *type = mono_class_inflate_generic_type_checked (&klass->byval_arg, ctx->generic_context, &error);

	if (!mono_error_ok (&error)) {
		char *name = mono_type_get_full_name (klass);
		ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid class %s used for exception", name));
		g_free (name);
		mono_error_cleanup (&error);
		return;
	}

	if (!ctx->max_stack) {
		ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Stack overflow at 0x%04x", ctx->ip_offset));
		return;
	}

	stack_init (ctx, code);
	set_stack_value (ctx, code->stack, type, FALSE);
	ctx->exception_types = g_slist_prepend (ctx->exception_types, type);
	code->size = 1;
	code->flags |= IL_CODE_FLAG_WAS_TARGET;
	if (mono_type_is_generic_argument (type))
		code->stack->stype |= BOXED_MASK;
}

Project: mono

GSList*
mono_image_verify_tables (MonoImage *image, int level)
{
	/* The verifier was disabled at compile time */
	return NULL;

Project: mono

is_valid_string (MonoImage *image, guint32 str_index, int notnull)
{
	const char *p, *blob_end, *res;

	if (str_index >= image->heap_strings.size)
		return NULL;
	res = p = mono_metadata_string_heap (image, str_index);
	blob_end = mono_metadata_string_heap (image, image->heap_strings.size - 1);
	if (notnull && !*p)
		return 0;
	/* 
	 * FIXME: should check it's a valid utf8 string, too.
	 */
	while (p <= blob_end) {
		if (!*p)
			return res;
		++p;
	}
	return *p? NULL: res;
}

Project: mono

gboolean
mono_verifier_is_class_full_trust (MonoClass *klass)
{
	/* under CoreCLR code is trusted if it is part of the "platform" otherwise all code inside the GAC is trusted */
	gboolean trusted_location = (mono_security_get_mode () != MONO_SECURITY_MODE_CORE_CLR) ? 
		klass->image->assembly->in_gac : mono_security_core_clr_is_platform_image (klass->image);

	if (verify_all && verifier_mode == MONO_VERIFIER_MODE_OFF)
		return trusted_location || klass->image == mono_defaults.corlib;
	return verifier_mode < MONO_VERIFIER_MODE_VERIFIABLE || trusted_location || klass->image == mono_defaults.corlib;

Project: mono

verifier_load_type (VerifyContext *ctx, int token, const char *opcode) {
	MonoType* type;
	
	if (!IS_TYPE_DEF_OR_REF_OR_SPEC (token) || !token_bounds_check (ctx->image, token)) {
		ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid type token 0x%08x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
		return NULL;
	}

	type = mono_type_get_full (ctx->image, token, ctx->generic_context);

	if (!type) {
		ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Cannot load type from token 0x%08x for %s at 0x%04x", token, opcode, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
		return NULL;
	}

	if (!mono_type_is_valid_in_context (ctx, type))
		return NULL;

	return type;
}