+
+static int __use_new_interface_vtable_code = -1;
+static gboolean
+use_new_interface_vtable_code (void) {
+ if (__use_new_interface_vtable_code == -1) {
+ char *env_var = getenv ("MONO_USE_NEW_INTERFACE_VTABLE_CODE");
+ if (env_var == NULL) {
+ __use_new_interface_vtable_code = TRUE;
+ } else {
+ if ((strcmp (env_var, "0") == 0) || (strcmp (env_var, "false") == 0) || (strcmp (env_var, "FALSE") == 0)) {
+ __use_new_interface_vtable_code = FALSE;
+ } else {
+ __use_new_interface_vtable_code = TRUE;
+ }
+ }
+ }
+ return __use_new_interface_vtable_code;
+}
+
+
+#define DEBUG_INTERFACE_VTABLE_CODE 0
+#define TRACE_INTERFACE_VTABLE_CODE 0
+
+#if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
+#define DEBUG_INTERFACE_VTABLE(stmt) do {\
+ stmt;\
+} while (0)
+#else
+#define DEBUG_INTERFACE_VTABLE(stmt)
+#endif
+
+#if TRACE_INTERFACE_VTABLE_CODE
+#define TRACE_INTERFACE_VTABLE(stmt) do {\
+ stmt;\
+} while (0)
+#else
+#define TRACE_INTERFACE_VTABLE(stmt)
+#endif
+
+
+#if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
+static char*
+mono_signature_get_full_desc (MonoMethodSignature *sig, gboolean include_namespace)
+{
+ int i;
+ char *result;
+ GString *res = g_string_new ("");
+
+ g_string_append_c (res, '(');
+ for (i = 0; i < sig->param_count; ++i) {
+ if (i > 0)
+ g_string_append_c (res, ',');
+ mono_type_get_desc (res, sig->params [i], include_namespace);
+ }
+ g_string_append (res, ")=>");
+ if (sig->ret != NULL) {
+ mono_type_get_desc (res, sig->ret, include_namespace);
+ } else {
+ g_string_append (res, "NULL");
+ }
+ result = res->str;
+ g_string_free (res, FALSE);
+ return result;
+}
+static void
+print_method_signatures (MonoMethod *im, MonoMethod *cm) {
+ char *im_sig = mono_signature_get_full_desc (mono_method_signature (im), TRUE);
+ char *cm_sig = mono_signature_get_full_desc (mono_method_signature (cm), TRUE);
+ printf ("(IM \"%s\", CM \"%s\")", im_sig, cm_sig);
+ g_free (im_sig);
+ g_free (cm_sig);
+
+}
+
+#endif
+static gboolean
+check_interface_method_override (MonoClass *class, MonoMethod *im, MonoMethod *cm, gboolean require_newslot, gboolean interface_is_explicitly_implemented_by_class, gboolean slot_is_empty, gboolean security_enabled) {
+ if (strcmp (im->name, cm->name) == 0) {
+ if (! (cm->flags & METHOD_ATTRIBUTE_PUBLIC)) {
+ TRACE_INTERFACE_VTABLE (printf ("[PUBLIC CHECK FAILED]"));
+ return FALSE;
+ }
+ if (! slot_is_empty) {
+ if (require_newslot) {
+ if (! interface_is_explicitly_implemented_by_class) {
+ TRACE_INTERFACE_VTABLE (printf ("[NOT EXPLICIT IMPLEMENTATION IN FULL SLOT REFUSED]"));
+ return FALSE;
+ }
+ if (! (cm->flags & METHOD_ATTRIBUTE_NEW_SLOT)) {
+ TRACE_INTERFACE_VTABLE (printf ("[NEWSLOT CHECK FAILED]"));
+ return FALSE;
+ }
+ } else {
+ TRACE_INTERFACE_VTABLE (printf ("[FULL SLOT REFUSED]"));
+ }
+ }
+ if (! mono_metadata_signature_equal (mono_method_signature (cm), mono_method_signature (im))) {
+ TRACE_INTERFACE_VTABLE (printf ("[SIGNATURE CHECK FAILED "));
+ TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
+ TRACE_INTERFACE_VTABLE (printf ("]"));
+ return FALSE;
+ }
+ TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS]"));
+ /* CAS - SecurityAction.InheritanceDemand on interface */
+ if (security_enabled && (im->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) {
+ mono_secman_inheritancedemand_method (cm, im);
+ }
+
+ if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+ check_core_clr_override_method (class, cm, im);
+ TRACE_INTERFACE_VTABLE (printf ("[NAME CHECK OK]"));
+ return TRUE;
+ } else {
+ MonoClass *ic = im->klass;
+ const char *ic_name_space = ic->name_space;
+ const char *ic_name = ic->name;
+ char *subname;
+
+ if (! require_newslot) {
+ TRACE_INTERFACE_VTABLE (printf ("[INJECTED METHOD REFUSED]"));
+ return FALSE;
+ }
+ if (cm->klass->rank == 0) {
+ TRACE_INTERFACE_VTABLE (printf ("[RANK CHECK FAILED]"));
+ return FALSE;
+ }
+ if (! mono_metadata_signature_equal (mono_method_signature (cm), mono_method_signature (im))) {
+ TRACE_INTERFACE_VTABLE (printf ("[(INJECTED) SIGNATURE CHECK FAILED "));
+ TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
+ TRACE_INTERFACE_VTABLE (printf ("]"));
+ return FALSE;
+ }
+ if (mono_class_get_image (ic) != mono_defaults.corlib) {
+ TRACE_INTERFACE_VTABLE (printf ("[INTERFACE CORLIB CHECK FAILED]"));
+ return FALSE;
+ }
+ if ((ic_name_space == NULL) || (strcmp (ic_name_space, "System.Collections.Generic") != 0)) {
+ TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAMESPACE CHECK FAILED]"));
+ return FALSE;
+ }
+ if ((ic_name == NULL) || ((strcmp (ic_name, "IEnumerable`1") != 0) && (strcmp (ic_name, "ICollection`1") != 0) && (strcmp (ic_name, "IList`1") != 0))) {
+ TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAME CHECK FAILED]"));
+ return FALSE;
+ }
+
+ subname = strstr (cm->name, ic_name_space);
+ if (subname != cm->name) {
+ TRACE_INTERFACE_VTABLE (printf ("[ACTUAL NAMESPACE CHECK FAILED]"));
+ return FALSE;
+ }
+ subname += strlen (ic_name_space);
+ if (subname [0] != '.') {
+ TRACE_INTERFACE_VTABLE (printf ("[FIRST DOT CHECK FAILED]"));
+ return FALSE;
+ }
+ subname ++;
+ if (strstr (subname, ic_name) != subname) {
+ TRACE_INTERFACE_VTABLE (printf ("[ACTUAL CLASS NAME CHECK FAILED]"));
+ return FALSE;
+ }
+ subname += strlen (ic_name);
+ if (subname [0] != '.') {
+ TRACE_INTERFACE_VTABLE (printf ("[SECOND DOT CHECK FAILED]"));
+ return FALSE;
+ }
+ subname ++;
+ if (strcmp (subname, im->name) != 0) {
+ TRACE_INTERFACE_VTABLE (printf ("[METHOD NAME CHECK FAILED]"));
+ return FALSE;
+ }
+
+ TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS (INJECTED CASE)]"));
+ /* CAS - SecurityAction.InheritanceDemand on interface */
+ if (security_enabled && (im->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) {
+ mono_secman_inheritancedemand_method (cm, im);
+ }
+
+ if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+ check_core_clr_override_method (class, cm, im);
+
+ TRACE_INTERFACE_VTABLE (printf ("[INJECTED INTERFACE CHECK OK]"));
+ return TRUE;
+ }
+}
+
+#if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
+static void
+foreach_override (gpointer key, gpointer value, gpointer user_data) {
+ MonoMethod *method = key;
+ MonoMethod *override = value;
+ MonoClass *method_class = mono_method_get_class (method);
+ MonoClass *override_class = mono_method_get_class (override);
+
+ printf (" Method '%s.%s:%s' has override '%s.%s:%s'\n",
+ mono_class_get_namespace (method_class), mono_class_get_name (method_class), mono_method_get_name (method),
+ mono_class_get_namespace (override_class), mono_class_get_name (override_class), mono_method_get_name (override));
+}
+static void
+print_overrides (GHashTable *override_map, const char *message) {
+ if (override_map) {
+ printf ("Override map \"%s\" START:\n", message);
+ g_hash_table_foreach (override_map, foreach_override, NULL);
+ printf ("Override map \"%s\" END.\n", message);
+ } else {
+ printf ("Override map \"%s\" EMPTY.\n", message);
+ }
+}
+static void
+print_vtable_full (MonoClass *class, MonoMethod** vtable, int size, int first_non_interface_slot, const char *message, gboolean print_interfaces) {
+ char *full_name = mono_type_full_name (&class->byval_arg);
+ int i;
+ int parent_size;
+
+ printf ("*** Vtable for class '%s' at \"%s\" (size %d)\n", full_name, message, size);
+
+ if (print_interfaces) {
+ print_implemented_interfaces (class);
+ printf ("* Interfaces for class '%s' done.\nStarting vtable (size %d):\n", full_name, size);
+ }
+
+ if (class->parent) {
+ parent_size = class->parent->vtable_size;
+ } else {
+ parent_size = 0;
+ }
+ for (i = 0; i < size; ++i) {
+ MonoMethod *cm = vtable [i];
+ if (cm) {
+ char *cm_name = mono_method_full_name (cm, TRUE);
+ char newness = (i < parent_size) ? 'O' : ((i < first_non_interface_slot) ? 'I' : 'N');
+ printf (" [%c][%03d][INDEX %03d] %s\n", newness, i, cm->slot, cm_name);
+ g_free (cm_name);
+ }
+ }
+
+ g_free (full_name);
+}
+#endif
+
+static void
+print_unimplemented_interface_method_info (MonoClass *class, MonoClass *ic, MonoMethod *im, int im_slot, MonoMethod **overrides, int onum) {
+ int index;
+ char *method_signature;
+
+ for (index = 0; index < onum; ++index) {
+ g_print (" at slot %d: %s (%d) overrides %s (%d)\n", im_slot, overrides [index*2+1]->name,
+ overrides [index*2+1]->slot, overrides [index*2]->name, overrides [index*2]->slot);
+ }
+ method_signature = mono_signature_get_desc (mono_method_signature (im), FALSE);
+ printf ("no implementation for interface method %s::%s(%s) in class %s.%s\n",
+ mono_type_get_name (&ic->byval_arg), im->name, method_signature, class->name_space, class->name);
+ g_free (method_signature);
+ for (index = 0; index < class->method.count; ++index) {
+ MonoMethod *cm = class->methods [index];
+ method_signature = mono_signature_get_desc (mono_method_signature (cm), TRUE);
+
+ printf ("METHOD %s(%s)\n", cm->name, method_signature);
+ g_free (method_signature);
+ }
+}
+