[runtime] Fix reading past the end of a string when setting the native thread name.
[mono.git] / mono / dis / get.c
old mode 100644 (file)
new mode 100755 (executable)
index c10ca0e..34f87b0
@@ -5,6 +5,7 @@
  *   Miguel de Icaza (miguel@ximian.com)
  *
  * (C) 2001 Ximian, Inc.
+ * Copyright 2012 Xamarin Inc
  */
 #include <config.h>
 #include <stdio.h>
@@ -125,12 +126,12 @@ stringify_array (guint32 rank, guint32 num_sizes, guint32 num_lo_bounds, gint32
                if (i)
                        g_string_append_c (res, ',');
                if (i < num_lo_bounds)
-                       g_string_sprintfa (res, "%d...", lo_bounds [i]);
+                       g_string_append_printf (res, "%d...", lo_bounds [i]);
                if (i < num_sizes) {
                        if (i < num_lo_bounds)
-                               g_string_sprintfa (res, "%d", lo_bounds [i] + sizes [i] - 1);
+                               g_string_append_printf (res, "%d", lo_bounds [i] + sizes [i] - 1);
                        else
-                               g_string_sprintfa (res, "%d", sizes [i]);
+                               g_string_append_printf (res, "%d", sizes [i]);
                }
 
        }
@@ -511,8 +512,8 @@ dis_stringify_modifiers (MonoImage *m, int n, MonoCustomMod *mod)
        for (i = 0; i < n; ++i) {
                char *tok = dis_stringify_token (m, mod[i].token);
                if (i > 0)
-                       g_string_sprintfa (s, " ");
-               g_string_sprintfa (s, " %s (%s)", mod[i].required ? "modreq": "modopt", tok);
+                       g_string_append_printf (s, " ");
+               g_string_append_printf (s, " %s (%s)", mod[i].required ? "modreq": "modopt", tok);
                g_free (tok);
        }
        g_string_append_c (s, ' ');
@@ -787,7 +788,8 @@ get_generic_param (MonoImage *m, MonoGenericContainer *container)
 
        g_string_append_c (result, '<');
        for (i = 0; i < container->type_argc; i++) {
-               MonoGenericParam *param = &container->type_params [i];
+               MonoGenericParam *param = mono_generic_container_get_param (container, i);
+               MonoGenericParamInfo *param_info = mono_generic_param_info (param);
                MonoClass **constr;
                int first = 1;
                guint16 flags;
@@ -795,8 +797,14 @@ get_generic_param (MonoImage *m, MonoGenericContainer *container)
 
                if (i > 0)
                        g_string_append (result, ",");
+               
+               flags = param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_VARIANCE_MASK;
+               if ((flags & GENERIC_PARAMETER_ATTRIBUTE_COVARIANT) == GENERIC_PARAMETER_ATTRIBUTE_COVARIANT)
+                       g_string_append (result, "+ ");
+               if ((flags & GENERIC_PARAMETER_ATTRIBUTE_CONTRAVARIANT) == GENERIC_PARAMETER_ATTRIBUTE_CONTRAVARIANT)
+                       g_string_append (result, "- ");
 
-               flags = param->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
+               flags = param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
                if ((flags & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) == GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT)
                        g_string_append (result, "class ");
                if ((flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) == GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT)
@@ -804,7 +812,7 @@ get_generic_param (MonoImage *m, MonoGenericContainer *container)
                if ((flags & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) == GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT)
                        g_string_append (result, ".ctor ");
 
-               for (constr = param->constraints; constr && *constr; constr++) {
+               for (constr = param_info->constraints; constr && *constr; constr++) {
                        char *sig;
 
                        if (first) {
@@ -820,7 +828,7 @@ get_generic_param (MonoImage *m, MonoGenericContainer *container)
                if (!first)
                        g_string_append (result, ") ");
 
-               esname = get_escaped_name (param->name);
+               esname = get_escaped_name (mono_generic_param_info (param)->name);
                g_string_append (result, esname);
                g_free (esname);
        }
@@ -871,8 +879,13 @@ dis_stringify_method_signature_full (MonoImage *m, MonoMethodSignature *method,
 
        if (methoddef_row) {
                mono_metadata_decode_row (&m->tables [MONO_TABLE_METHOD], methoddef_row -1, cols, MONO_METHOD_SIZE);
-               if (fully_qualified)
-                       type = get_typedef (m, mono_metadata_typedef_from_method (m, methoddef_row));
+               if (fully_qualified) {
+                       guint32 type_idx = mono_metadata_typedef_from_method (m, methoddef_row);
+                       if (type_idx)
+                               type = get_typedef (m, type_idx);
+                       else
+                               type = g_strdup ("<invalid>");
+               }
                method_name = mono_metadata_string_heap (m, cols [MONO_METHOD_NAME]);
                param_index = cols [MONO_METHOD_PARAMLIST];
                if (!method) {
@@ -920,13 +933,19 @@ dis_stringify_method_signature_full (MonoImage *m, MonoMethodSignature *method,
                                const char *tp;
                                MonoMarshalSpec *spec;
                                tp = mono_metadata_get_marshal_info (m, param_index - 1, FALSE);
-                               g_assert (tp);
-                               spec = mono_metadata_parse_marshal_spec (m, tp);
-
-                               if (i)
-                                       marshal_info = dis_stringify_marshal_spec (spec);
-                               else
-                                       ret_marshal_info = dis_stringify_marshal_spec (spec);
+                               if (tp) {
+                                       spec = mono_metadata_parse_marshal_spec (m, tp);
+       
+                                       if (i)
+                                               marshal_info = dis_stringify_marshal_spec (spec);
+                                       else
+                                               ret_marshal_info = dis_stringify_marshal_spec (spec);
+                               } else {
+                                       if (i)
+                                               marshal_info = g_strdup ("(missing)");
+                                       else
+                                               ret_marshal_info = g_strdup ("(missing)");
+                               }
                        }
                        param_index ++;
                } else {
@@ -955,11 +974,11 @@ dis_stringify_method_signature_full (MonoImage *m, MonoMethodSignature *method,
        if (method->hasthis)
                g_string_append (result_ret, "instance ");
        g_string_append (result_ret, map (method->call_convention, call_conv_type_map));
-       g_string_sprintfa (result_ret, " %s%s ", retval, ret_marshal_info ? ret_marshal_info :"");
+       g_string_append_printf (result_ret, " %s%s ", retval, ret_marshal_info ? ret_marshal_info :"");
        g_free (ret_marshal_info);
        if (type) {
                char *estype = get_escaped_name (type);
-               g_string_sprintfa (result_ret, "%s::", estype);
+               g_string_append_printf (result_ret, "%s::", estype);
                g_free (estype);
                g_free (type);
        }
@@ -1000,7 +1019,7 @@ dis_stringify_function_ptr (MonoImage *m, MonoMethodSignature *method)
        g_string_append (result, map (method->call_convention, call_conv_type_map));
 
        retval = dis_stringify_param (m, method->ret);
-       g_string_sprintfa (result, " %s ", retval);
+       g_string_append_printf (result, " %s ", retval);
        g_free (retval);
 
        g_string_append (result, " *(");
@@ -1079,14 +1098,15 @@ dis_stringify_object_with_class (MonoImage *m, MonoClass *c, gboolean prefix, gb
 
        if (c->generic_class) {
                MonoGenericClass *gclass = c->generic_class;
+               MonoGenericInst *inst = gclass->context.class_inst;
                GString *str = g_string_new ("");
                int i;
 
-               for (i = 0; i < gclass->inst->type_argc; i++){
-                       char *t = dis_stringify_type (m, gclass->inst->type_argv [i], is_def);
+               for (i = 0; i < inst->type_argc; i++){
+                       char *t = dis_stringify_type (m, inst->type_argv [i], is_def);
 
                        g_string_append (str, t);
-                       if (i+1 != gclass->inst->type_argc)
+                       if (i+1 != inst->type_argc)
                                g_string_append (str, ", ");
                        g_free (t);
                }
@@ -1178,27 +1198,28 @@ dis_stringify_type (MonoImage *m, MonoType *type, gboolean is_def)
                break;
        case MONO_TYPE_MVAR:
                if (is_def && !cant_print_generic_param_name (type->data.generic_param))
-                       bare = g_strdup_printf ("!!%s", get_escaped_name (type->data.generic_param->name));
+                       bare = g_strdup_printf ("!!%s", get_escaped_name (mono_generic_param_info (type->data.generic_param)->name));
                else
-                       bare = g_strdup_printf ("!!%d", type->data.generic_param->num);
+                       bare = g_strdup_printf ("!!%d", mono_type_get_generic_param_num (type));
                break;
        case MONO_TYPE_VAR:
                if (is_def && !cant_print_generic_param_name (type->data.generic_param))
-                       bare = g_strdup_printf ("!%s", get_escaped_name (type->data.generic_param->name));
+                       bare = g_strdup_printf ("!%s", get_escaped_name (mono_generic_param_info (type->data.generic_param)->name));
                else
-                       bare = g_strdup_printf ("!%d", type->data.generic_param->num);
+                       bare = g_strdup_printf ("!%d", mono_type_get_generic_param_num (type));
                break;
        case MONO_TYPE_GENERICINST: {
                GString *str = g_string_new ("");
+               MonoGenericInst *inst;
                int i;
                char *generic_type = dis_stringify_type (
                        m, &type->data.generic_class->container_class->byval_arg, is_def);
-
-               for (i = 0; i < type->data.generic_class->inst->type_argc; i++){
-                       char *t = dis_stringify_type (m, type->data.generic_class->inst->type_argv [i], is_def);
+               inst = type->data.generic_class->context.class_inst;
+               for (i = 0; i < inst->type_argc; i++){
+                       char *t = dis_stringify_type (m, inst->type_argv [i], is_def);
 
                        g_string_append (str, t);
-                       if (i+1 != type->data.generic_class->inst->type_argc)
+                       if (i+1 != inst->type_argc)
                                g_string_append (str, ", ");
                        g_free (t);
                }
@@ -1256,7 +1277,11 @@ get_type (MonoImage *m, const char *ptr, char **result, gboolean is_def, MonoGen
        case MONO_TYPE_CLASS: {
                guint32 token = mono_metadata_parse_typedef_or_ref (m, ptr, &ptr);
                MonoClass *klass = mono_class_get (m, token);
-               char *temp = dis_stringify_object_with_class (m, klass, TRUE, FALSE);
+               char *temp;
+               if (klass)
+                       temp = dis_stringify_object_with_class (m, klass, TRUE, FALSE);
+               else
+                       temp = g_strdup_printf ("<BROKEN CLASS token_%8x>", token);
 
                if (show_tokens) {
                        *result = g_strdup_printf ("%s/*%08x*/", temp, token);
@@ -1293,8 +1318,24 @@ get_type (MonoImage *m, const char *ptr, char **result, gboolean is_def, MonoGen
 
        default:
                t = mono_metadata_parse_type_full (m, container, MONO_PARSE_TYPE, 0, start, &ptr);
-               *result = dis_stringify_type (m, t, is_def);
-               mono_metadata_free_type (t);
+               if (t) {
+                       *result = dis_stringify_type (m, t, is_def);
+               } else {
+                       GString *err = g_string_new ("@!#$<InvalidType>$#!@");
+                       if (container)
+                               t = mono_metadata_parse_type_full (m, NULL, MONO_PARSE_TYPE, 0, start, &ptr);
+                       if (t) {
+                               char *name = dis_stringify_type (m, t, is_def);
+                               g_warning ("Encountered a generic type inappropriate for its context");
+                               g_string_append (err, " // ");
+                               g_string_append (err, name);
+                               g_free (name);
+                       } else {
+                               g_warning ("Encountered an invalid type");
+                       }
+                       *result = g_string_free (err, FALSE);
+               }
+
                break;
        }
 
@@ -1533,7 +1574,7 @@ get_escaped_name (const char *name)
 
        for (s = name; *s; s++) {
                if (isalnum (*s) || *s == '_' || *s == '$' || *s == '@' ||
-                   *s == '?' || *s == '.' || *s == 0 || *s == '!' || *s == '`')
+                   *s == '?' || (*s == '.' && s != name) || *s == 0 || *s == '!' || *s == '`')
                        continue;
 
                esc = str_escape (name, "'\\");
@@ -1582,7 +1623,15 @@ static dis_map_t field_flags_map [] = {
        { FIELD_ATTRIBUTE_SPECIAL_NAME,        "specialname " },
        { FIELD_ATTRIBUTE_PINVOKE_IMPL,        "FIXME:pinvokeimpl " },
        { FIELD_ATTRIBUTE_RT_SPECIAL_NAME,        "rtspecialname " },
-       /*{ FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL,        "hasfieldmarshal " },*/
+
+       /* This is set when a MarshalAs attribute is seen. FIXME: round-trip?  */
+       { FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL,        "" },
+
+       /* This seems to be set if LITERAL is set. FIXME: round-trip? */
+       { FIELD_ATTRIBUTE_HAS_DEFAULT,          "" },
+
+       /* This seems to be set on compiler-generated array initializer fields. FIXME: round-trip? */
+       { FIELD_ATTRIBUTE_HAS_FIELD_RVA,                "" },
        { 0, NULL }
 };
 
@@ -1596,11 +1645,12 @@ field_flags (guint32 f)
 {
        char buffer [1024];
        int access = f & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
+       int rest = f & ~access;
        
        buffer [0] = 0;
 
        strcat (buffer, map (access, field_access_map));
-       strcat (buffer, flags (f, field_flags_map));
+       strcat (buffer, flags (rest, field_flags_map));
        return g_strdup (buffer);
 }
 
@@ -1756,6 +1806,11 @@ get_field (MonoImage *m, guint32 token, MonoGenericContainer *container)
         * the TypeDef table.  LAME!
         */
        type_idx = mono_metadata_typedef_from_field (m, idx);
+       if (!type_idx) {
+               res = g_strdup_printf ("<invalid> %s", sig);
+               g_free (sig);
+               return res;
+       }
 
        type = get_typedef (m, type_idx);
        estype = get_escaped_name (type);
@@ -1852,9 +1907,8 @@ get_method_core (MonoImage *m, guint32 token, gboolean fullsig, MonoGenericConta
 
        mh = mono_get_method_full (m, token, NULL, (MonoGenericContext *) container);
        if (mh) {
-               mh = mono_get_inflated_method (mh);
                if (mono_method_signature (mh)->is_inflated)
-                       container = ((MonoMethodInflated *) mh)->declaring->generic_container;
+                       container = mono_method_get_generic_container (((MonoMethodInflated *) mh)->declaring);
                esname = get_escaped_name (mh->name);
                sig = dis_stringify_type (m, &mh->klass->byval_arg, TRUE);
                if (show_tokens)
@@ -1888,11 +1942,11 @@ get_method_core (MonoImage *m, guint32 token, gboolean fullsig, MonoGenericConta
                if (mh) {
                        int arity = 0;
 
-                       if (mh->generic_container)
-                               arity = mh->generic_container->type_argc;
+                       if (mh->is_generic)
+                               arity = mono_method_get_generic_container (mh)->type_argc;
                        else
-                       if (mh->is_inflated && ((MonoMethodInflated *)mh)->declaring->generic_container)
-                               arity = ((MonoMethodInflated*) mh)->declaring->generic_container->type_argc;
+                       if (mh->is_inflated && ((MonoMethodInflated *)mh)->declaring->is_generic)
+                               arity = mono_method_get_generic_container (((MonoMethodInflated*) mh)->declaring)->type_argc;
 
                        if (arity > 0) {
                                char *str = g_strdup_printf ("%s <[%d]>", name, arity);
@@ -2042,7 +2096,7 @@ get_methodspec (MonoImage *m, int idx, guint32 token, const char *fancy_name, Mo
        
        mh = mono_get_method_full (m, method_dor_to_token (token), NULL, (MonoGenericContext *) type_container);
        g_assert (mh);
-       container = mh->generic_container;
+       container = mono_method_get_generic_container (mh);
        if (!container)
                container = type_container;
 
@@ -2253,10 +2307,10 @@ get_constant (MonoImage *m, MonoTypeEnum t, guint32 blob_index)
                readr4 (ptr, &r);
 
                /* Crazy solaris systems doesn't have isnormal */
-#ifdef HAVE_FINITE
-               normal = finite (r);
+#ifdef HAVE_ISFINITE
+               normal = isfinite (r);
 #else
-               normal = isnormal (r);
+               normal = !dis_isinf (r) && !dis_isnan (r);
 #endif
                if (!normal) {
                        return g_strdup_printf ("float32(0x%08x)", read32 (ptr));
@@ -2273,8 +2327,8 @@ get_constant (MonoImage *m, MonoTypeEnum t, guint32 blob_index)
                readr8 (ptr, &r);
 
                /* Crazy solaris systems doesn't have isnormal */
-#ifdef HAVE_FINITE
-               normal = finite (r);
+#ifdef HAVE_ISFINITE
+               normal = isfinite (r);
 #else
                normal = isnormal (r);
 #endif
@@ -2324,6 +2378,12 @@ get_token (MonoImage *m, guint32 token, MonoGenericContainer *container)
                result = g_strdup_printf ("field %s", temp);
                g_free (temp);
                return result;
+       case MONO_TOKEN_METHOD_DEF:
+       case MONO_TOKEN_METHOD_SPEC:
+               temp = get_method (m, token, container);
+               result = g_strdup_printf ("method %s", temp);
+               g_free (temp);
+               return result;
        case MONO_TOKEN_TYPE_DEF:
                temp = get_typedef (m, idx);
                result = get_escaped_name (temp);
@@ -2491,7 +2551,7 @@ dis_get_custom_attrs (MonoImage *m, guint32 token)
                len = mono_metadata_decode_value (val, &val);
                attr = g_string_new (".custom ");
                dump = data_dump (val, len, "\t\t");
-               g_string_sprintfa (attr, "%s = %s", method, dump);
+               g_string_append_printf (attr, "%s = %s", method, dump);
                g_free (dump);
                list = g_list_append (list, attr->str);
                g_string_free (attr, FALSE);
@@ -2844,6 +2904,7 @@ init_key_table (void)
        g_hash_table_insert (key_table, (char *) "ldvirtftn", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "leave", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "leave.s", GINT_TO_POINTER (TRUE));
+       g_hash_table_insert (key_table, (char *) "legacy", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "linkcheck", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "literal", GINT_TO_POINTER (TRUE));
        g_hash_table_insert (key_table, (char *) "localloc", GINT_TO_POINTER (TRUE));
@@ -3036,7 +3097,6 @@ get_method_override (MonoImage *m, guint32 token, MonoGenericContainer *containe
                if (token == impl) {
                        MonoMethod *mh = NULL;
                        mh = mono_get_method_full (m, decl, NULL, (MonoGenericContext *) container);
-                       mh = mono_get_inflated_method (mh);
 
                        if (mh && (mh->klass && (mh->klass->generic_class || mh->klass->generic_container))) {
                                char *meth_str;
@@ -3072,12 +3132,12 @@ check_ambiguous_genparams (MonoGenericContainer *container)
 
        table = g_hash_table_new (g_str_hash, g_str_equal);
        for (i = 0; i < container->type_argc; i++) {
-               MonoGenericParam *param = &container->type_params [i];
+               MonoGenericParam *param = mono_generic_container_get_param (container, i);
 
-               if ((p = g_hash_table_lookup (table, param->name)))
+               if ((p = g_hash_table_lookup (table, mono_generic_param_info (param)->name)))
                        dup_list = g_slist_prepend (g_slist_prepend (dup_list, GUINT_TO_POINTER (i + 1)), p);
                else
-                       g_hash_table_insert (table, (char*)param->name, GUINT_TO_POINTER (i + 1));
+                       g_hash_table_insert (table, (char*)mono_generic_param_info (param)->name, GUINT_TO_POINTER (i + 1));
        }
 
        if (dup_list) {
@@ -3086,8 +3146,8 @@ check_ambiguous_genparams (MonoGenericContainer *container)
                for (l = dup_list; l; l = l->next) {
                        int param = GPOINTER_TO_UINT (l->data);
                        g_hash_table_insert (mono_generic_params_with_ambiguous_names,
-                                &container->type_params [param-1],
-                                &container->type_params [param-1]);
+                               mono_generic_container_get_param (container, param-1),
+                               mono_generic_container_get_param (container, param-1));
                }
                g_slist_free (dup_list);
        }
@@ -3102,11 +3162,56 @@ check_ambiguous_genparams (MonoGenericContainer *container)
 static gboolean
 cant_print_generic_param_name (MonoGenericParam *gparam)
 {
+       MonoGenericContainer *container;
        g_assert (gparam);
 
-       check_ambiguous_genparams (gparam->owner);
-       return (!gparam->owner || (mono_generic_params_with_ambiguous_names && 
+       container = mono_generic_param_owner (gparam);
+       check_ambiguous_genparams (container);
+       return (!container || (mono_generic_params_with_ambiguous_names &&
                        g_hash_table_lookup (mono_generic_params_with_ambiguous_names, gparam)));
 }
 
 
+static dis_map_t method_impl_map [] = {
+       { METHOD_IMPL_ATTRIBUTE_IL,              "cil " },
+       { METHOD_IMPL_ATTRIBUTE_NATIVE,          "native " },
+       { METHOD_IMPL_ATTRIBUTE_OPTIL,           "optil " },
+       { METHOD_IMPL_ATTRIBUTE_RUNTIME,         "runtime " },
+       { 0, NULL }
+};
+
+static dis_map_t managed_type_map [] = {
+       { METHOD_IMPL_ATTRIBUTE_UNMANAGED,       "unmanaged " },
+       { METHOD_IMPL_ATTRIBUTE_MANAGED,         "managed " },
+       { 0, NULL }
+};
+
+static dis_map_t managed_impl_flags [] = {
+       { METHOD_IMPL_ATTRIBUTE_FORWARD_REF,     "fwdref " },
+       { METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG,    "preservesig " },
+       { METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL,   "internalcall " },
+       { METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED,    "synchronized " },
+       { METHOD_IMPL_ATTRIBUTE_NOINLINING,      "noinlining " },
+       { METHOD_IMPL_ATTRIBUTE_NOOPTIMIZATION,  "nooptimization " },
+       { METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING,  "agressive-inlining" },
+       { 0, NULL }
+};
+
+char *
+get_method_impl_flags (guint32 f)
+{
+       GString *str = g_string_new ("");
+       char *s;
+       int code_type = f & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
+       int managed_type = f & METHOD_IMPL_ATTRIBUTE_MANAGED_MASK;
+       int rest = f & ~(code_type | managed_type);
+
+       g_string_append (str, map (code_type, method_impl_map));
+       g_string_append (str, map (managed_type, managed_type_map));
+       g_string_append (str, flags (rest, managed_impl_flags));
+       
+       s = str->str;
+       g_string_free (str, FALSE);
+       return s;
+}
+