Merge pull request #5306 from lambdageek/corefx-sre-tests
authorAleksey Kliger (λgeek) <akliger@gmail.com>
Fri, 4 Aug 2017 16:40:54 +0000 (12:40 -0400)
committerGitHub <noreply@github.com>
Fri, 4 Aug 2017 16:40:54 +0000 (12:40 -0400)
[test] (corlib) Use CoreFX System.Reflection.Emit xunit tests

12 files changed:
mcs/mcs/anonymous.cs
mcs/mcs/convert.cs
mcs/mcs/ecore.cs
mcs/mcs/expression.cs
mcs/mcs/pending.cs
mcs/tests/test-947.cs [new file with mode: 0644]
mcs/tests/test-pattern-08.cs [new file with mode: 0644]
mcs/tests/test-pattern-09.cs [new file with mode: 0644]
mcs/tests/ver-il-net_4_x.xml
mono/btls/CMakeLists.txt
mono/metadata/custom-attrs.c
mono/metadata/metadata.c

index 6cec0e1da6dc57513c0af368e3ec08a8f5ac6848..3ce9b0c9f199189c703238261602f52d1acb5e33 100644 (file)
@@ -839,6 +839,11 @@ namespace Mono.CSharp {
                {
                        GetFieldExpression (ec).EmitAssign (ec, source, leave_copy, false);
                }
+
+               public void EmitAssignFromStack (EmitContext ec)
+               {
+                       GetFieldExpression (ec).EmitAssignFromStack (ec);
+               }
        }
 
        public class HoistedParameter : HoistedVariable
index a99e3fde628b60061aae8448ab3621c23a7fad9c..8fe0e2026ca5842fdc286d456bf41a536f79456b 100644 (file)
@@ -736,8 +736,6 @@ namespace Mono.CSharp {
                        var tupleLiteralElements = (source as TupleLiteral)?.Elements;
 
                        for (int i = 0; i < targetType.Arity; ++i) {
-                               var elementType = srcTypeArgument [i];
-
                                if (tupleLiteralElements != null) {
                                        if (!ImplicitStandardConversionExists (tupleLiteralElements[i].Expr, targetTypeArgument [i])) {
                                                return false;
index d15fbe5e34f6e9592987a466ff17580e9a95fbb9..7704e72b168738451687821fde3c4ddd8b26a7d9 100644 (file)
@@ -2429,7 +2429,12 @@ namespace Mono.CSharp {
 
                public override void FlowAnalysis (FlowAnalysisContext fc)
                {
-                       expr.FlowAnalysis (fc);
+                       orig_expr.FlowAnalysis (fc);
+               }
+
+               public override void FlowAnalysisConditional (FlowAnalysisContext fc)
+               {
+                       orig_expr.FlowAnalysisConditional (fc);
                }
 
                public override SLE.Expression MakeExpression (BuilderContext ctx)
index b9f47b5a361054a9b3675508668144a484c51de8..896980968d82efd168067c2664980380ecbe842c 100644 (file)
@@ -1687,8 +1687,15 @@ namespace Mono.CSharp
                                ec.Emit (OpCodes.Dup);
                                no_value_label = ec.DefineLabel ();
                                ec.Emit (OpCodes.Brfalse_S, no_value_label);
+
+                               if (Variable.HoistedVariant != null)
+                                       ec.EmitThis ();
+
                                expr_unwrap.Emit (ec);
                        } else {
+                               if (Variable?.HoistedVariant != null)
+                                       ec.EmitThis ();
+
                                expr.Emit (ec);
 
                                // Only to make verifier happy
@@ -1708,19 +1715,29 @@ namespace Mono.CSharp
                                        value_on_stack = false;
                                }
 
-                               //
-                               // It's ok to have variable builder create out of order. It simplified emit
-                               // of statements like while (condition) { }
-                               //
-                               if (!Variable.Created)
-                                       Variable.CreateBuilder (ec);
-                               
-                               Variable.EmitAssign (ec);
+                               if (Variable.HoistedVariant != null) {
+                                       Variable.HoistedVariant.EmitAssignFromStack (ec);
 
-                               if (expr_unwrap != null) {
-                                       ec.MarkLabel (no_value_label);
-                               } else if (!value_on_stack) {
-                                       Variable.Emit (ec);
+                                       if (expr_unwrap != null) {
+                                               ec.MarkLabel (no_value_label);
+                                       } else if (!value_on_stack) {
+                                               Variable.HoistedVariant.Emit (ec);
+                                       }
+                               } else {
+                                       //
+                                       // It's ok to have variable builder created out of order. It simplifies emit
+                                       // of statements like while (condition) { }
+                                       //
+                                       if (!Variable.Created)
+                                               Variable.CreateBuilder (ec);
+
+                                       Variable.EmitAssign (ec);
+
+                                       if (expr_unwrap != null) {
+                                               ec.MarkLabel (no_value_label);
+                                       } else if (!value_on_stack) {
+                                               Variable.Emit (ec);
+                                       }
                                }
                        }
                }
index 507b937e2c904310786e8798ee2196d2ef52dcb2..1de765fb4ac041eb7926c501e0aeb235c98579ad 100644 (file)
@@ -545,12 +545,15 @@ namespace Mono.CSharp {
 
                                if (new_implementation) {
                                        MemberFilter filter;
-                                       if (mi.Parameters.Count > 1) {
-                                               var indexer_params = mi.Name [0] == 'g' ? mi.Parameters : IndexerSpec.CreateParametersFromSetter (mi, mi.Parameters.Count - 1);
-                                               filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, indexer_params, null);
+                                       bool getter = mi.Name [0] == 'g';
+                                       if (mi.Parameters.Count > (getter ? 0 : 1)) {
+                                               var indexer_params = getter ? mi.Parameters : IndexerSpec.CreateParametersFromSetter (mi, mi.Parameters.Count - 1);
+                                               var ptype = getter ? mi.ReturnType : mi.Parameters.Types [mi.Parameters.Count - 1];
+                                               filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, indexer_params, ptype);
                                        } else {
                                                var pname = mi.Name.Substring (4);
-                                               filter = MemberFilter.Property (pname, null);
+                                               var ptype = getter ? mi.ReturnType : mi.Parameters.Types [0];
+                                               filter = MemberFilter.Property (pname, ptype);
                                        }
 
                                        var prop = MemberCache.FindMember (container.CurrentType, filter, BindingRestriction.DeclaredOnly | BindingRestriction.InstanceOnly);
diff --git a/mcs/tests/test-947.cs b/mcs/tests/test-947.cs
new file mode 100644 (file)
index 0000000..f2f8cbb
--- /dev/null
@@ -0,0 +1,29 @@
+interface IA
+{
+       int Prop { get; }
+       int this [int arg] { get; }
+}
+
+abstract class B : IA
+{
+    public long Prop => 4;
+
+       int IA.Prop => 1;
+
+       public long this [int arg] => 2;
+
+       int IA.this [int arg] => 4;
+}
+
+class C : B, IA
+{
+       public static void Main ()
+       {
+       }
+
+       public new string Prop {
+               get { return ""; }
+       }
+
+       public new string this [int arg] => "2";
+}
\ No newline at end of file
diff --git a/mcs/tests/test-pattern-08.cs b/mcs/tests/test-pattern-08.cs
new file mode 100644 (file)
index 0000000..22b7621
--- /dev/null
@@ -0,0 +1,32 @@
+using System.Collections.Generic;
+
+class Expr
+{
+       public int Field;
+       public Expr Next;
+}
+
+static class X
+{
+       public static IEnumerable<int> Test (this Expr expr)
+       {
+               var exprCur = expr;
+               while (exprCur != null)
+               {
+                       if (exprCur is Expr list)
+                       {
+                               yield return list.Field;
+                               exprCur = list.Next;
+                       }
+                       else
+                       {
+                               yield return 2;
+                               yield break;
+                       }
+               }
+       }
+
+       public static void Main ()
+       {
+       }
+}
\ No newline at end of file
diff --git a/mcs/tests/test-pattern-09.cs b/mcs/tests/test-pattern-09.cs
new file mode 100644 (file)
index 0000000..801469e
--- /dev/null
@@ -0,0 +1,33 @@
+using System.Collections.Generic;
+
+class Expr
+{
+       public int Field;
+}
+
+static class X
+{
+       public static IEnumerable<int> Test (Expr expr)
+       {
+               object exprCur = expr;
+               if (exprCur is Expr list) {
+                       yield return list.Field;
+               }
+       }
+
+       public static IEnumerable<string> Test2 (int? expr)
+       {
+               int? exprCur = expr;
+               while (exprCur != null) {
+                       if (exprCur is int list) {
+                               yield return list.ToString ();
+                       }
+               }
+       }       
+
+       public static void Main ()
+       {
+               Test (null);
+               Test2 (3);
+       }
+}
\ No newline at end of file
index 221283df2e4e6f62662a6dcc4d17c30a2e5428bc..eae0f275f16d50e0c382d004bd08313a90350adb 100644 (file)
       </method>
     </type>
   </test>
+  <test name="test-947.cs">
+    <type name="B">
+      <method name="Int64 get_Prop()" attrs="2182">
+        <size>10</size>
+      </method>
+      <method name="Int32 IA.get_Prop()" attrs="2529">
+        <size>9</size>
+      </method>
+      <method name="Int64 get_Item(Int32)" attrs="2182">
+        <size>10</size>
+      </method>
+      <method name="Int32 IA.get_Item(Int32)" attrs="2529">
+        <size>9</size>
+      </method>
+      <method name="Void .ctor()" attrs="6276">
+        <size>7</size>
+      </method>
+    </type>
+    <type name="C">
+      <method name="Void Main()" attrs="150">
+        <size>2</size>
+      </method>
+      <method name="System.String get_Prop()" attrs="2182">
+        <size>14</size>
+      </method>
+      <method name="System.String get_Item(Int32)" attrs="2182">
+        <size>13</size>
+      </method>
+      <method name="Void .ctor()" attrs="6278">
+        <size>7</size>
+      </method>
+    </type>
+  </test>
   <test name="test-95.cs">
     <type name="X">
       <method name="Int32 Main()" attrs="150">
       </method>
     </type>
   </test>
+  <test name="test-pattern-08.cs">
+    <type name="Expr">
+      <method name="Void .ctor()" attrs="6278">
+        <size>7</size>
+      </method>
+    </type>
+    <type name="X">
+      <method name="System.Collections.Generic.IEnumerable`1[System.Int32] Test(Expr)" attrs="150">
+        <size>30</size>
+      </method>
+      <method name="Void Main()" attrs="150">
+        <size>2</size>
+      </method>
+    </type>
+    <type name="X+&lt;Test&gt;c__Iterator0">
+      <method name="Boolean MoveNext()" attrs="486">
+        <size>184</size>
+      </method>
+      <method name="Int32 System.Collections.Generic.IEnumerator&lt;int&gt;.get_Current()" attrs="2529">
+        <size>14</size>
+      </method>
+      <method name="System.Object System.Collections.IEnumerator.get_Current()" attrs="2529">
+        <size>19</size>
+      </method>
+      <method name="Void Dispose()" attrs="486">
+        <size>15</size>
+      </method>
+      <method name="Void Reset()" attrs="486">
+        <size>6</size>
+      </method>
+      <method name="System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()" attrs="481">
+        <size>14</size>
+      </method>
+      <method name="System.Collections.Generic.IEnumerator`1[System.Int32] System.Collections.Generic.IEnumerable&lt;int&gt;.GetEnumerator()" attrs="481">
+        <size>40</size>
+      </method>
+      <method name="Void .ctor()" attrs="6278">
+        <size>7</size>
+      </method>
+    </type>
+  </test>
+  <test name="test-pattern-09.cs">
+    <type name="Expr">
+      <method name="Void .ctor()" attrs="6278">
+        <size>7</size>
+      </method>
+    </type>
+    <type name="X">
+      <method name="System.Collections.Generic.IEnumerable`1[System.Int32] Test(Expr)" attrs="150">
+        <size>30</size>
+      </method>
+      <method name="System.Collections.Generic.IEnumerable`1[System.String] Test2(System.Nullable`1[System.Int32])" attrs="150">
+        <size>30</size>
+      </method>
+      <method name="Void Main()" attrs="150">
+        <size>21</size>
+      </method>
+    </type>
+    <type name="X+&lt;Test&gt;c__Iterator0">
+      <method name="Boolean MoveNext()" attrs="486">
+        <size>124</size>
+      </method>
+      <method name="Int32 System.Collections.Generic.IEnumerator&lt;int&gt;.get_Current()" attrs="2529">
+        <size>14</size>
+      </method>
+      <method name="System.Object System.Collections.IEnumerator.get_Current()" attrs="2529">
+        <size>19</size>
+      </method>
+      <method name="Void Dispose()" attrs="486">
+        <size>15</size>
+      </method>
+      <method name="Void Reset()" attrs="486">
+        <size>6</size>
+      </method>
+      <method name="System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()" attrs="481">
+        <size>14</size>
+      </method>
+      <method name="System.Collections.Generic.IEnumerator`1[System.Int32] System.Collections.Generic.IEnumerable&lt;int&gt;.GetEnumerator()" attrs="481">
+        <size>40</size>
+      </method>
+      <method name="Void .ctor()" attrs="6278">
+        <size>7</size>
+      </method>
+    </type>
+    <type name="X+&lt;Test2&gt;c__Iterator1">
+      <method name="Boolean MoveNext()" attrs="486">
+        <size>161</size>
+      </method>
+      <method name="System.String System.Collections.Generic.IEnumerator&lt;string&gt;.get_Current()" attrs="2529">
+        <size>14</size>
+      </method>
+      <method name="System.Object System.Collections.IEnumerator.get_Current()" attrs="2529">
+        <size>14</size>
+      </method>
+      <method name="Void Dispose()" attrs="486">
+        <size>15</size>
+      </method>
+      <method name="Void Reset()" attrs="486">
+        <size>6</size>
+      </method>
+      <method name="System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()" attrs="481">
+        <size>14</size>
+      </method>
+      <method name="System.Collections.Generic.IEnumerator`1[System.String] System.Collections.Generic.IEnumerable&lt;string&gt;.GetEnumerator()" attrs="481">
+        <size>40</size>
+      </method>
+      <method name="Void .ctor()" attrs="6278">
+        <size>7</size>
+      </method>
+    </type>
+  </test>
   <test name="test-pragma-unrecognized.cs">
     <type name="C">
       <method name="Void Main()" attrs="150">
index 9f2365d3e50df411bb759a763f70a8b1f4cd038c..d33038d75cfe1fd42710c04b2c560491f96a1925 100644 (file)
@@ -31,7 +31,10 @@ set (CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} ${BTLS_CFLAGS}")
 set (CMAKE_MACOSX_RPATH 1)
 set (MONO_BTLS 1)
 
+set(BUILD_SHARED_LIBS_SAVED "${BUILD_SHARED_LIBS}")
+set(BUILD_SHARED_LIBS OFF)
 add_subdirectory (${BTLS_ROOT} boringssl)
+set(BUILD_SHARED_LIBS "${BUILD_SHARED_LIBS_SAVED}")
 
 include_directories (
        ${SRC_DIR}
index 0fecdbd66ce7415846f0609e2a095928934f0d51..a7954f721e44d8100a0fbfc3517615dac8a4dd64 100644 (file)
@@ -46,6 +46,12 @@ static GENERATE_GET_CLASS_WITH_CACHE (custom_attribute_named_argument, "System.R
 static MonoCustomAttrInfo*
 mono_custom_attrs_from_builders_handle (MonoImage *alloc_img, MonoImage *image, MonoArrayHandle cattrs);
 
+static gboolean
+bcheck_blob (const char *ptr, int bump, const char *endp, MonoError *error);
+
+static gboolean
+decode_blob_value_checked (const char *ptr, const char *endp, guint32 *size_out, const char **retp, MonoError *error);
+
 /*
  * LOCKING: Acquires the loader lock. 
  */
@@ -185,14 +191,18 @@ cattr_type_from_name (char *n, MonoImage *image, gboolean is_enum, MonoError *er
 }
 
 static MonoClass*
-load_cattr_enum_type (MonoImage *image, const char *p, const char **end, MonoError *error)
+load_cattr_enum_type (MonoImage *image, const char *p, const char *boundp, const char **end, MonoError *error)
 {
        char *n;
        MonoType *t;
-       int slen = mono_metadata_decode_value (p, &p);
-
+       guint32 slen;
        error_init (error);
 
+       if (!decode_blob_value_checked (p, boundp, &slen, &p, error))
+               return NULL;
+
+       if (boundp && slen > 0 && !bcheck_blob (p, slen - 1, boundp, error))
+               return NULL;
        n = (char *)g_memdup (p, slen + 1);
        n [slen] = 0;
        t = cattr_type_from_name (n, image, TRUE, error);
@@ -204,11 +214,13 @@ load_cattr_enum_type (MonoImage *image, const char *p, const char **end, MonoErr
 }
 
 static void*
-load_cattr_value (MonoImage *image, MonoType *t, const char *p, const char **end, MonoError *error)
+load_cattr_value (MonoImage *image, MonoType *t, const char *p, const char *boundp, const char **end, MonoError *error)
 {
-       int slen, type = t->type;
+       int type = t->type;
+       guint32 slen;
        MonoClass *tklass = t->data.klass;
 
+       g_assert (boundp);
        error_init (error);
 
 handle_enum:
@@ -217,6 +229,8 @@ handle_enum:
        case MONO_TYPE_I1:
        case MONO_TYPE_BOOLEAN: {
                MonoBoolean *bval = (MonoBoolean *)g_malloc (sizeof (MonoBoolean));
+               if (!bcheck_blob (p, 0, boundp, error))
+                       return NULL;
                *bval = *p;
                *end = p + 1;
                return bval;
@@ -225,6 +239,8 @@ handle_enum:
        case MONO_TYPE_U2:
        case MONO_TYPE_I2: {
                guint16 *val = (guint16 *)g_malloc (sizeof (guint16));
+               if (!bcheck_blob (p, 1, boundp, error))
+                       return NULL;
                *val = read16 (p);
                *end = p + 2;
                return val;
@@ -237,6 +253,8 @@ handle_enum:
        case MONO_TYPE_U4:
        case MONO_TYPE_I4: {
                guint32 *val = (guint32 *)g_malloc (sizeof (guint32));
+               if (!bcheck_blob (p, 3, boundp, error))
+                       return NULL;
                *val = read32 (p);
                *end = p + 4;
                return val;
@@ -248,12 +266,16 @@ handle_enum:
        case MONO_TYPE_U8:
        case MONO_TYPE_I8: {
                guint64 *val = (guint64 *)g_malloc (sizeof (guint64));
+               if (!bcheck_blob (p, 7, boundp, error))
+                       return NULL;
                *val = read64 (p);
                *end = p + 8;
                return val;
        }
        case MONO_TYPE_R8: {
                double *val = (double *)g_malloc (sizeof (double));
+               if (!bcheck_blob (p, 7, boundp, error))
+                       return NULL;
                readr8 (p, val);
                *end = p + 8;
                return val;
@@ -267,6 +289,8 @@ handle_enum:
                        
                        if (mono_is_corlib_image (k->image) && strcmp (k->name_space, "System") == 0 && strcmp (k->name, "DateTime") == 0){
                                guint64 *val = (guint64 *)g_malloc (sizeof (guint64));
+                               if (!bcheck_blob (p, 7, boundp, error))
+                                       return NULL;
                                *val = read64 (p);
                                *end = p + 8;
                                return val;
@@ -276,23 +300,33 @@ handle_enum:
                break;
                
        case MONO_TYPE_STRING:
+               if (!bcheck_blob (p, 0, boundp, error))
+                       return NULL;
                if (*p == (char)0xFF) {
                        *end = p + 1;
                        return NULL;
                }
-               slen = mono_metadata_decode_value (p, &p);
+               if (!decode_blob_value_checked (p, boundp, &slen, &p, error))
+                       return NULL;
+               if (slen > 0 && !bcheck_blob (p, slen - 1, boundp, error))
+                       return NULL;
                *end = p + slen;
                return mono_string_new_len_checked (mono_domain_get (), p, slen, error);
        case MONO_TYPE_CLASS: {
                MonoReflectionType *rt;
                char *n;
                MonoType *t;
+               if (!bcheck_blob (p, 0, boundp, error))
+                       return NULL;
                if (*p == (char)0xFF) {
                        *end = p + 1;
                        return NULL;
                }
 handle_type:
-               slen = mono_metadata_decode_value (p, &p);
+               if (!decode_blob_value_checked (p, boundp, &slen, &p, error))
+                       return NULL;
+               if (slen > 0 && !bcheck_blob (p, slen - 1, boundp, error))
+                       return NULL;
                n = (char *)g_memdup (p, slen + 1);
                n [slen] = 0;
                t = cattr_type_from_name (n, image, FALSE, error);
@@ -307,6 +341,8 @@ handle_type:
                return rt;
        }
        case MONO_TYPE_OBJECT: {
+               if (!bcheck_blob (p, 0, boundp, error))
+                       return NULL;
                char subt = *p++;
                MonoObject *obj;
                MonoClass *subc = NULL;
@@ -319,6 +355,8 @@ handle_type:
                        goto handle_enum;
                } else if (subt == 0x1D) {
                        MonoType simple_type = {{0}};
+                       if (!bcheck_blob (p, 0, boundp, error))
+                               return NULL;
                        int etype = *p;
                        p ++;
 
@@ -326,8 +364,8 @@ handle_type:
                        if (etype == 0x50) {
                                tklass = mono_defaults.systemtype_class;
                        } else if (etype == 0x55) {
-                               tklass = load_cattr_enum_type (image, p, &p, error);
-                               if (!mono_error_ok (error))
+                               tklass = load_cattr_enum_type (image, p, boundp, &p, error);
+                               if (!is_ok (error))
                                        return NULL;
                        } else {
                                if (etype == 0x51)
@@ -340,7 +378,10 @@ handle_type:
                } else if (subt == 0x55) {
                        char *n;
                        MonoType *t;
-                       slen = mono_metadata_decode_value (p, &p);
+                       if (!decode_blob_value_checked (p, boundp, &slen, &p, error))
+                               return NULL;
+                       if (slen > 0 && !bcheck_blob (p, slen - 1, boundp, error))
+                               return NULL;
                        n = (char *)g_memdup (p, slen + 1);
                        n [slen] = 0;
                        t = cattr_type_from_name (n, image, FALSE, error);
@@ -355,12 +396,12 @@ handle_type:
                } else {
                        g_error ("Unknown type 0x%02x for object type encoding in custom attr", subt);
                }
-               val = load_cattr_value (image, &subc->byval_arg, p, end, error);
+               val = load_cattr_value (image, &subc->byval_arg, p, boundp, end, error);
                obj = NULL;
-               if (mono_error_ok (error)) {
+               if (is_ok (error)) {
                        obj = mono_object_new_checked (mono_domain_get (), subc, error);
                        g_assert (!subc->has_references);
-                       if (mono_error_ok (error))
+                       if (is_ok (error))
                                mono_gc_memmove_atomic ((char*)obj + sizeof (MonoObject), val, mono_class_value_size (subc, NULL));
                }
 
@@ -370,6 +411,8 @@ handle_type:
        case MONO_TYPE_SZARRAY: {
                MonoArray *arr;
                guint32 i, alen, basetype;
+               if (!bcheck_blob (p, 3, boundp, error))
+                       return NULL;
                alen = read32 (p);
                p += 4;
                if (alen == 0xffffffff) {
@@ -387,6 +430,8 @@ handle_type:
                        case MONO_TYPE_I1:
                        case MONO_TYPE_BOOLEAN:
                                for (i = 0; i < alen; i++) {
+                                       if (!bcheck_blob (p, 0, boundp, error))
+                                               return NULL;
                                        MonoBoolean val = *p++;
                                        mono_array_set (arr, MonoBoolean, i, val);
                                }
@@ -395,6 +440,8 @@ handle_type:
                        case MONO_TYPE_U2:
                        case MONO_TYPE_I2:
                                for (i = 0; i < alen; i++) {
+                                       if (!bcheck_blob (p, 1, boundp, error))
+                                               return NULL;
                                        guint16 val = read16 (p);
                                        mono_array_set (arr, guint16, i, val);
                                        p += 2;
@@ -404,6 +451,8 @@ handle_type:
                        case MONO_TYPE_U4:
                        case MONO_TYPE_I4:
                                for (i = 0; i < alen; i++) {
+                                       if (!bcheck_blob (p, 3, boundp, error))
+                                               return NULL;
                                        guint32 val = read32 (p);
                                        mono_array_set (arr, guint32, i, val);
                                        p += 4;
@@ -411,6 +460,8 @@ handle_type:
                                break;
                        case MONO_TYPE_R8:
                                for (i = 0; i < alen; i++) {
+                                       if (!bcheck_blob (p, 7, boundp, error))
+                                               return NULL;
                                        double val;
                                        readr8 (p, &val);
                                        mono_array_set (arr, double, i, val);
@@ -420,6 +471,8 @@ handle_type:
                        case MONO_TYPE_U8:
                        case MONO_TYPE_I8:
                                for (i = 0; i < alen; i++) {
+                                       if (!bcheck_blob (p, 7, boundp, error))
+                                               return NULL;
                                        guint64 val = read64 (p);
                                        mono_array_set (arr, guint64, i, val);
                                        p += 8;
@@ -430,8 +483,8 @@ handle_type:
                        case MONO_TYPE_STRING:
                        case MONO_TYPE_SZARRAY:
                                for (i = 0; i < alen; i++) {
-                                       MonoObject *item = (MonoObject *)load_cattr_value (image, &tklass->byval_arg, p, &p, error);
-                                       if (!mono_error_ok (error))
+                                       MonoObject *item = (MonoObject *)load_cattr_value (image, &tklass->byval_arg, p, boundp, &p, error);
+                                       if (!is_ok (error))
                                                return NULL;
                                        mono_array_setref (arr, i, item);
                                }
@@ -449,13 +502,13 @@ handle_type:
 }
 
 static MonoObject*
-load_cattr_value_boxed (MonoDomain *domain, MonoImage *image, MonoType *t, const char* p, const char** end, MonoError *error)
+load_cattr_value_boxed (MonoDomain *domain, MonoImage *image, MonoType *t, const char* p, const char *boundp, const char** end, MonoError *error)
 {
        error_init (error);
 
        gboolean is_ref = type_is_reference (t);
 
-       void *val = load_cattr_value (image, t, p, end, error);
+       void *val = load_cattr_value (image, t, p, boundp, end, error);
        if (!is_ok (error)) {
                if (is_ref)
                        g_free (val);
@@ -576,11 +629,100 @@ mono_custom_attrs_from_builders (MonoImage *alloc_img, MonoImage *image, MonoArr
        return ainfo;
 }
 
+static void
+set_custom_attr_fmt_error (MonoError *error)
+{
+       error_init (error);
+       mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Binary format of the specified custom attribute was invalid.");
+}
+
+/**
+ * bcheck_blob:
+ * \param ptr a pointer into a blob
+ * \param bump how far we plan on reading past \p ptr.
+ * \param endp upper bound for \p ptr - one past the last valid value for \p ptr.
+ * \param error set on error
+ *
+ * Check that ptr+bump is below endp.  Returns TRUE on success, or FALSE on
+ * failure and sets \p error.
+ */
+static gboolean
+bcheck_blob (const char *ptr, int bump, const char *endp, MonoError *error)
+{
+       error_init (error);
+       if (ADDP_IS_GREATER_OR_OVF (ptr, bump, endp - 1)) {
+               set_custom_attr_fmt_error (error);
+               return FALSE;
+       } else
+               return TRUE;
+}
+
+/**
+ * decode_blob_size_checked:
+ * \param ptr a pointer into a blob
+ * \param endp upper bound for \p ptr - one pas the last valid value for \p ptr
+ * \param size_out on success set to the decoded size
+ * \param retp on success set to the next byte after the encoded size
+ * \param error set on error
+ *
+ * Decode an encoded size value which takes 1, 2, or 4 bytes and set \p
+ * size_out to the decoded size and \p retp to the next byte after the encoded
+ * size.  Returns TRUE on success, or FALASE on failure and sets \p error.
+ */
+static gboolean
+decode_blob_size_checked (const char *ptr, const char *endp, guint32 *size_out, const char **retp, MonoError *error)
+{
+       error_init (error);
+       if (endp && !bcheck_blob (ptr, 0, endp, error))
+               goto leave;
+       if ((*ptr & 0x80) != 0) {
+               if ((*ptr & 0x40) == 0 && !bcheck_blob (ptr, 1, endp, error))
+                       goto leave;
+               else if (!bcheck_blob (ptr, 3, endp, error))
+                       goto leave;
+       }
+       *size_out = mono_metadata_decode_blob_size (ptr, retp);
+leave:
+       return is_ok (error);
+}
+
+/**
+ * decode_blob_value_checked:
+ * \param ptr a pointer into a blob
+ * \param endp upper bound for \p ptr - one pas the last valid value for \p ptr
+ * \param value_out on success set to the decoded value
+ * \param retp on success set to the next byte after the encoded size
+ * \param error set on error
+ *
+ * Decode an encoded uint32 value which takes 1, 2, or 4 bytes and set \p
+ * value_out to the decoded value and \p retp to the next byte after the
+ * encoded value.  Returns TRUE on success, or FALASE on failure and sets \p
+ * error.
+ */
+static gboolean
+decode_blob_value_checked (const char *ptr, const char *endp, guint32 *value_out, const char **retp, MonoError *error)
+{
+       /* This similar to decode_blob_size_checked, above but delegates to
+        * mono_metadata_decode_value which is semantically different. */
+       error_init (error);
+       if (!bcheck_blob (ptr, 0, endp, error))
+               goto leave;
+       if ((*ptr & 0x80) != 0) {
+               if ((*ptr & 0x40) == 0 && !bcheck_blob (ptr, 1, endp, error))
+                       goto leave;
+               else if (!bcheck_blob (ptr, 3, endp, error))
+                       goto leave;
+       }
+       *value_out = mono_metadata_decode_value (ptr, retp);
+leave:
+       return is_ok (error);
+}
 
 static MonoObject*
 create_custom_attr (MonoImage *image, MonoMethod *method, const guchar *data, guint32 len, MonoError *error)
 {
        const char *p = (const char*)data;
+       const char *data_end = (const char*)data + len;
        const char *named;
        guint32 i, j, num_named;
        MonoObject *attr;
@@ -593,7 +735,7 @@ create_custom_attr (MonoImage *image, MonoMethod *method, const guchar *data, gu
        mono_class_init (method->klass);
 
        if (!mono_verifier_verify_cattr_content (image, method, data, len, NULL)) {
-               mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Binary format of the specified custom attribute was invalid.");
+               set_custom_attr_fmt_error (error);
                return NULL;
        }
 
@@ -625,8 +767,8 @@ create_custom_attr (MonoImage *image, MonoMethod *method, const guchar *data, gu
        /* skip prolog */
        p += 2;
        for (i = 0; i < mono_method_signature (method)->param_count; ++i) {
-               params [i] = load_cattr_value (image, mono_method_signature (method)->params [i], p, &p, error);
-               if (!mono_error_ok (error))
+               params [i] = load_cattr_value (image, mono_method_signature (method)->params [i], p, data_end, &p, error);
+               if (!is_ok (error))
                        goto fail;
        }
 
@@ -643,19 +785,37 @@ create_custom_attr (MonoImage *image, MonoMethod *method, const guchar *data, gu
                goto fail;
        }
 
-       num_named = read16 (named);
-       named += 2;
+       if (named + 1 < data_end) {
+               num_named = read16 (named);
+               named += 2;
+       } else {
+               /* CoreCLR allows p == data + len */
+               if (named == data_end)
+                       num_named = 0;
+               else {
+                       set_custom_attr_fmt_error (error);
+                       goto fail;
+               }
+       }
        for (j = 0; j < num_named; j++) {
-               gint name_len;
+               guint32 name_len;
                char *name, named_type, data_type;
+               if (!bcheck_blob (named, 1, data_end, error))
+                       goto fail;
                named_type = *named++;
                data_type = *named++; /* type of data */
-               if (data_type == MONO_TYPE_SZARRAY)
+               if (data_type == MONO_TYPE_SZARRAY) {
+                       if (!bcheck_blob (named, 0, data_end, error))
+                               goto fail;
                        data_type = *named++;
+               }
                if (data_type == MONO_TYPE_ENUM) {
-                       gint type_len;
+                       guint32 type_len;
                        char *type_name;
-                       type_len = mono_metadata_decode_blob_size (named, &named);
+                       if (!decode_blob_size_checked (named, data_end, &type_len, &named, error))
+                               goto fail;
+                       if (type_len > 0 && !bcheck_blob (named, type_len - 1, data_end, error))
+                               goto fail;
                        type_name = (char *)g_malloc (type_len + 1);
                        memcpy (type_name, named, type_len);
                        type_name [type_len] = 0;
@@ -663,7 +823,10 @@ create_custom_attr (MonoImage *image, MonoMethod *method, const guchar *data, gu
                        /* FIXME: lookup the type and check type consistency */
                        g_free (type_name);
                }
-               name_len = mono_metadata_decode_blob_size (named, &named);
+               if (!decode_blob_size_checked (named, data_end, &name_len, &named, error))
+                       goto fail;
+               if (name_len > 0 && !bcheck_blob (named, name_len - 1, data_end, error))
+                       goto fail;
                name = (char *)g_malloc (name_len + 1);
                memcpy (name, named, name_len);
                name [name_len] = 0;
@@ -680,8 +843,8 @@ create_custom_attr (MonoImage *image, MonoMethod *method, const guchar *data, gu
                                goto fail;
                        }
 
-                       val = load_cattr_value (image, field->type, named, &named, error);
-                       if (!mono_error_ok (error)) {
+                       val = load_cattr_value (image, field->type, named, data_end, &named, error);
+                       if (!is_ok (error)) {
                                g_free (name);
                                if (!type_is_reference (field->type))
                                        g_free (val);
@@ -714,8 +877,8 @@ create_custom_attr (MonoImage *image, MonoMethod *method, const guchar *data, gu
                        prop_type = prop->get? mono_method_signature (prop->get)->ret :
                             mono_method_signature (prop->set)->params [mono_method_signature (prop->set)->param_count - 1];
 
-                       pparams [0] = load_cattr_value (image, prop_type, named, &named, error);
-                       if (!mono_error_ok (error)) {
+                       pparams [0] = load_cattr_value (image, prop_type, named, data_end, &named, error);
+                       if (!is_ok (error)) {
                                g_free (name);
                                if (!type_is_reference (prop_type))
                                        g_free (pparams [0]);
@@ -761,6 +924,7 @@ mono_reflection_create_custom_attr_data_args (MonoImage *image, MonoMethod *meth
        MonoClass *attrklass;
        MonoDomain *domain;
        const char *p = (const char*)data;
+       const char *data_end = p + len;
        const char *named;
        guint32 i, j, num_named;
        CattrNamedArg *arginfo = NULL;
@@ -782,21 +946,28 @@ mono_reflection_create_custom_attr_data_args (MonoImage *image, MonoMethod *meth
 
        if (len < 2 || read16 (p) != 0x0001) /* Prolog */
                return;
+       /* skip prolog */
+       p += 2;
 
+       /* Parse each argument corresponding to the signature's parameters from
+        * the blob and store in typedargs.
+        */
        typedargs = mono_array_new_checked (domain, mono_get_object_class (), mono_method_signature (method)->param_count, error);
        return_if_nok (error);
 
-       /* skip prolog */
-       p += 2;
        for (i = 0; i < mono_method_signature (method)->param_count; ++i) {
                MonoObject *obj;
 
-               obj = load_cattr_value_boxed (domain, image, mono_method_signature (method)->params [i], p, &p, error);
+               obj = load_cattr_value_boxed (domain, image, mono_method_signature (method)->params [i], p, data_end, &p, error);
                return_if_nok (error);
                mono_array_setref (typedargs, i, obj);
        }
 
        named = p;
+
+       /* Parse mandatory count of named arguments (could be zero) */
+       if (!bcheck_blob (named, 1, data_end, error))
+               return;
        num_named = read16 (named);
        namedargs = mono_array_new_checked (domain, mono_get_object_class (), num_named, error);
        return_if_nok (error);
@@ -806,17 +977,25 @@ mono_reflection_create_custom_attr_data_args (MonoImage *image, MonoMethod *meth
        arginfo = g_new0 (CattrNamedArg, num_named);
        *named_arg_info = arginfo;
 
+       /* Parse each named arg, and add to arginfo.  Each named argument could
+        * be a field name or a property name followed by a value. */
        for (j = 0; j < num_named; j++) {
-               gint name_len;
+               guint32 name_len;
                char *name, named_type, data_type;
-               named_type = *named++;
+               if (!bcheck_blob (named, 1, data_end, error))
+                       return;
+               named_type = *named++; /* field or property? */
                data_type = *named++; /* type of data */
-               if (data_type == MONO_TYPE_SZARRAY)
+               if (data_type == MONO_TYPE_SZARRAY) {
+                       if (!bcheck_blob (named, 0, data_end, error))
+                               return;
                        data_type = *named++;
+               }
                if (data_type == MONO_TYPE_ENUM) {
-                       gint type_len;
+                       guint32 type_len;
                        char *type_name;
-                       type_len = mono_metadata_decode_blob_size (named, &named);
+                       if (!decode_blob_size_checked (named, data_end, &type_len, &named, error))
+                               return;
                        if (ADDP_IS_GREATER_OR_OVF ((const guchar*)named, type_len, data + len))
                                goto fail;
 
@@ -827,7 +1006,9 @@ mono_reflection_create_custom_attr_data_args (MonoImage *image, MonoMethod *meth
                        /* FIXME: lookup the type and check type consistency */
                        g_free (type_name);
                }
-               name_len = mono_metadata_decode_blob_size (named, &named);
+               /* named argument name: length, then name */
+               if (!decode_blob_size_checked(named, data_end, &name_len, &named, error))
+                       return;
                if (ADDP_IS_GREATER_OR_OVF ((const guchar*)named, name_len, data + len))
                        goto fail;
                name = (char *)g_malloc (name_len + 1);
@@ -835,6 +1016,7 @@ mono_reflection_create_custom_attr_data_args (MonoImage *image, MonoMethod *meth
                name [name_len] = 0;
                named += name_len;
                if (named_type == 0x53) {
+                       /* Named arg is a field. */
                        MonoObject *obj;
                        MonoClassField *field = mono_class_get_field_from_name (attrklass, name);
 
@@ -846,7 +1028,7 @@ mono_reflection_create_custom_attr_data_args (MonoImage *image, MonoMethod *meth
                        arginfo [j].type = field->type;
                        arginfo [j].field = field;
 
-                       obj = load_cattr_value_boxed (domain, image, field->type, named, &named, error);
+                       obj = load_cattr_value_boxed (domain, image, field->type, named, data_end, &named, error);
                        if (!is_ok (error)) {
                                g_free (name);
                                return;
@@ -854,6 +1036,7 @@ mono_reflection_create_custom_attr_data_args (MonoImage *image, MonoMethod *meth
                        mono_array_setref (namedargs, j, obj);
 
                } else if (named_type == 0x54) {
+                       /* Named arg is a property */
                        MonoObject *obj;
                        MonoType *prop_type;
                        MonoProperty *prop = mono_class_get_property_from_name (attrklass, name);
@@ -869,7 +1052,7 @@ mono_reflection_create_custom_attr_data_args (MonoImage *image, MonoMethod *meth
                        arginfo [j].type = prop_type;
                        arginfo [j].prop = prop;
 
-                       obj = load_cattr_value_boxed (domain, image, prop_type, named, &named, error);
+                       obj = load_cattr_value_boxed (domain, image, prop_type, named, data_end, &named, error);
                        if (!is_ok (error)) {
                                g_free (name);
                                return;
@@ -1668,7 +1851,9 @@ mono_reflection_get_custom_attrs_info_checked (MonoObjectHandle obj, MonoError *
                MonoReflectionAssemblyBuilderHandle assemblyb = MONO_HANDLE_CAST (MonoReflectionAssemblyBuilder, obj);
                MonoReflectionAssemblyHandle assembly = MONO_HANDLE_CAST (MonoReflectionAssembly, assemblyb);
                MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, assemblyb, cattrs);
-               cinfo = mono_custom_attrs_from_builders_handle (NULL, MONO_HANDLE_GETVAL (assembly, assembly)->image, cattrs);
+               MonoImage * image = MONO_HANDLE_GETVAL (assembly, assembly)->image;
+               g_assert (image);
+               cinfo = mono_custom_attrs_from_builders_handle (NULL, image, cattrs);
        } else if (strcmp ("TypeBuilder", klass->name) == 0) {
                MonoReflectionTypeBuilderHandle tb = MONO_HANDLE_CAST (MonoReflectionTypeBuilder, obj);
                MonoReflectionModuleBuilderHandle module = MONO_HANDLE_NEW_GET (MonoReflectionModuleBuilder, tb, module);
index aea1343df99c5dac29b3945222b080ea19b6b481..b41dbf4e8186eff36f490f2a4d4844b032c73295 100644 (file)
@@ -1180,7 +1180,7 @@ mono_metadata_decode_row_col (const MonoTableInfo *t, int idx, guint col)
  * \param ptr pointer to a blob object
  * \param rptr the new position of the pointer
  *
- * This decodes a compressed size as described by 23.1.4 (a blob or user string object)
+ * This decodes a compressed size as described by 24.2.4 (#US and #Blob a blob or user string object)
  *
  * \returns the size of the blob object
  */