Author: Danny Milosavljevic <dannym@friendly-machines.com>
Date: 10 Jun 2025
Subject: Fix sources of non-reproducibility.

diff -ru orig/mono-1.9.1-checkout/mcs/class/corlib/System.Reflection.Emit/ModuleBuilder.cs mono-1.9.1-checkout/mcs/class/corlib/System.Reflection.Emit/ModuleBuilder.cs
--- orig/mono-1.9.1-checkout/mcs/class/corlib/System.Reflection.Emit/ModuleBuilder.cs	2025-06-09 11:58:58.679365113 +0200
+++ mono-1.9.1-checkout/mcs/class/corlib/System.Reflection.Emit/ModuleBuilder.cs	2025-06-09 19:10:46.839764717 +0200
@@ -80,7 +80,7 @@
 			this.assembly = this.assemblyb = assb;
 			this.transient = transient;
 			// to keep mcs fast we do not want CryptoConfig wo be involved to create the RNG
-			guid = Guid.FastNewGuidArray ();
+			guid = new byte[16]; // = Guid.Empty.ToByteArray();
 			// guid = Guid.NewGuid().ToByteArray ();
 			table_idx = get_next_table_index (this, 0x00, true);
 			name_cache = new Hashtable ();
diff -ru orig/mono-1.9.1-checkout/mcs/class/Mono.Cecil/Mono.Cecil.Binary/ImageInitializer.cs mono-1.9.1-checkout/mcs/class/Mono.Cecil/Mono.Cecil.Binary/ImageInitializer.cs
--- orig/mono-1.9.1-checkout/mcs/class/Mono.Cecil/Mono.Cecil.Binary/ImageInitializer.cs	2025-06-09 11:58:58.233978153 +0200
+++ mono-1.9.1-checkout/mcs/class/Mono.Cecil/Mono.Cecil.Binary/ImageInitializer.cs	2025-06-09 16:46:46.086454131 +0200
@@ -132,6 +132,15 @@
 
 		public static uint TimeDateStampFromEpoch ()
 		{
+			string sourceDateEpoch = Environment.GetEnvironmentVariable("SOURCE_DATE_EPOCH");
+			if (sourceDateEpoch != null && sourceDateEpoch != "") {
+				try {
+					return uint.Parse(sourceDateEpoch);
+				} catch {
+					// fallthrough
+				}
+			}
+
 			return (uint) DateTime.UtcNow.Subtract (
 				new DateTime (1970, 1, 1)).TotalSeconds;
 		}
diff -ru orig/mono-1.9.1-checkout/mcs/mcs/anonymous.cs mono-1.9.1-checkout/mcs/mcs/anonymous.cs
--- orig/mono-1.9.1-checkout/mcs/mcs/anonymous.cs	2025-06-09 11:58:58.814338639 +0200
+++ mono-1.9.1-checkout/mcs/mcs/anonymous.cs	2025-06-09 22:27:26.049258977 +0200
@@ -21,6 +21,7 @@
 
 namespace Mono.CSharp {
 
+
 	public abstract class CompilerGeneratedClass : Class
 	{
 		GenericMethod generic_method;
@@ -174,6 +175,61 @@
 				throw new InternalErrorException ("Helper class already defined!");
 		}
 
+//
+// A comparer for all types that inherit from the abstract class 'Variable'.
+// Uses only C# 2.0 compatible syntax.
+//
+//
+public class VariableComparer : System.Collections.IComparer
+{
+    // Helper method to safely get a comparable name from any Variable type.
+    private string GetVariableName(object obj)
+    {
+        // Case 1: The object is a 'CapturedVariable' or any of its children.
+        if (obj is ScopeInfo.CapturedVariable)
+        {
+
+            ScopeInfo.CapturedVariable cv = (ScopeInfo.CapturedVariable)obj;
+            return cv.Name;
+        }
+
+        // Case 2: The object is a 'LocalVariable'
+        if (obj is LocalInfo.LocalVariable)
+        {
+            // Explicit cast required for C# 2.0
+            LocalInfo.LocalVariable lv = (LocalInfo.LocalVariable)obj;
+            return lv.LocalInfo.Name;
+        }
+
+        //
+        // Fallback for any other unknown 'Variable' subtype.
+        //
+        return obj.GetType().FullName;
+    }
+
+    // The single method required by the IComparer interface.
+    public int Compare(object x, object y)
+    {
+        // Handle nulls gracefully.
+        if (x == null && y == null) return 0;
+        if (x == null) return -1;
+        if (y == null) return 1;
+
+        string name_x = GetVariableName(x);
+        string name_y = GetVariableName(y);
+
+        // Primary Sort Key: The extracted variable name.
+        int name_compare = string.CompareOrdinal(name_x, name_y);
+        if (name_compare != 0)
+        {
+            return name_compare;
+        }
+
+        // Secondary Sort Key (Tie-breaker): The full type name.
+        return string.CompareOrdinal(x.GetType().FullName, y.GetType().FullName);
+    }
+}
+
 		protected class CapturedVariableField : Field
 		{
 			public CapturedVariableField (CompilerGeneratedClass helper, string name,
@@ -264,9 +320,11 @@
 
 		protected CapturedScope[] CapturedScopes {
 			get {
-				CapturedScope[] list = new CapturedScope [captured_scopes.Count];
-				captured_scopes.Values.CopyTo (list, 0);
-				return list;
+                ArrayList list = new ArrayList(captured_scopes.Values);
+                list.Sort(new VariableComparer());
+                CapturedScope[] result = new CapturedScope[list.Count];
+                list.CopyTo(result, 0);
+                return result;
 			}
 		}
 
@@ -420,7 +478,7 @@
 			return new ScopeInitializer (this);
 		}
 
-		protected abstract class CapturedVariable : Variable
+		public abstract class CapturedVariable : Variable
 		{
 			public readonly ScopeInfo Scope;
 			public readonly string Name;
@@ -493,7 +551,7 @@
 			}
 		}
 
-		protected class CapturedParameter : CapturedVariable {
+		public class CapturedParameter : CapturedVariable {
 			public readonly Parameter Parameter;
 			public readonly int Idx;
 
@@ -511,7 +569,7 @@
 			}
 		}
 
-		protected class CapturedLocal : CapturedVariable {
+		public class CapturedLocal : CapturedVariable {
 			public readonly LocalInfo Local;
 
 			public CapturedLocal (ScopeInfo scope, LocalInfo local)
@@ -527,7 +585,7 @@
 			}
 		}
 
-		protected class CapturedThis : CapturedVariable {
+		public class CapturedThis : CapturedVariable {
 			public CapturedThis (RootScopeInfo host)
 				: base (host, "<>THIS", host.ParentType)
 			{ }
@@ -646,7 +704,9 @@
 				} else
 					scope_instance = ec.ig.DeclareLocal (type);
 
-				foreach (CapturedLocal local in Scope.locals.Values) {
+				ArrayList sorted_locals = new ArrayList(Scope.locals.Values);
+				sorted_locals.Sort(new VariableComparer());
+				foreach (CapturedLocal local in sorted_locals) {
 					FieldExpr fe = (FieldExpr) Expression.MemberLookup (
 						ec.ContainerType, type, local.Field.Name, loc);
 					Report.Debug (64, "RESOLVE SCOPE INITIALIZER #2", this, Scope,
@@ -660,7 +720,9 @@
 				}
 
 				if (Scope.HostsParameters) {
-					foreach (CapturedParameter cp in Scope.captured_params.Values) {
+                    ArrayList sorted_params = new ArrayList(Scope.captured_params.Values);
+					sorted_params.Sort(new VariableComparer());
+					foreach (CapturedParameter cp in sorted_params) {
 						FieldExpr fe = (FieldExpr) Expression.MemberLookup (
 							ec.ContainerType, type, cp.Field.Name, loc);
 						if (fe == null)
@@ -775,7 +837,9 @@
 					captured_scope.EmitAssign (ec);
 
 				if (Scope.HostsParameters) {
-					foreach (CapturedParameter cp in Scope.captured_params.Values) {
+                    ArrayList sorted_params = new ArrayList(Scope.captured_params.Values);
+					sorted_params.Sort(new VariableComparer());
+					foreach (CapturedParameter cp in sorted_params) {
 						Report.Debug (128, "EMIT SCOPE INIT #6", this,
 							      ec, ec.IsStatic, Scope, cp, cp.Field.Name);
 						DoEmitInstance (ec);
diff -ru orig/mono-1.9.1-checkout/mcs/mcs/statement.cs mono-1.9.1-checkout/mcs/mcs/statement.cs
--- orig/mono-1.9.1-checkout/mcs/mcs/statement.cs	2025-06-09 11:58:58.816851529 +0200
+++ mono-1.9.1-checkout/mcs/mcs/statement.cs	2025-06-09 22:07:10.441563853 +0200
@@ -1392,7 +1392,7 @@
 			get { return Location; }
 		}
 
-		protected class LocalVariable : Variable
+		public class LocalVariable : Variable
 		{
 			public readonly LocalInfo LocalInfo;
 			LocalBuilder builder;
diff -ru orig/mono-1.9.1-checkout/mono/metadata/reflection.c mono-1.9.1-checkout/mono/metadata/reflection.c
--- orig/mono-1.9.1-checkout/mono/metadata/reflection.c	2025-06-09 11:58:58.903462701 +0200
+++ mono-1.9.1-checkout/mono/metadata/reflection.c	2025-06-09 18:44:58.063693593 +0200
@@ -4851,7 +4851,7 @@
 	
 	header->coff.coff_machine = GUINT16_FROM_LE (assemblyb->machine);
 	header->coff.coff_sections = GUINT16_FROM_LE (nsections);
-	header->coff.coff_time = GUINT32_FROM_LE (time (NULL));
+	header->coff.coff_time = GUINT32_FROM_LE (getenv("SOURCE_DATE_EPOCH") ? atoi(getenv("SOURCE_DATE_EPOCH")) : time (NULL));
 	header->coff.coff_opt_header_size = GUINT16_FROM_LE (sizeof (MonoDotNetHeader) - sizeof (MonoCOFFHeader) - 4);
 	if (assemblyb->pekind == 1) {
 		/* it's a dll */
--- orig/mono-1.9.1-checkout/mono/metadata/reflection.c	2025-07-06 21:51:39.127926599 +0200
+++ mono-1.9.1-checkout/mono/metadata/reflection.c	2025-07-06 21:54:27.468828555 +0200
@@ -4485,12 +4485,24 @@
 	int nsections = 0;
 
 	/* alignment constraints */
-	assembly->code.index += 3;
-	assembly->code.index &= ~3;
+	guint32 old_code_index = assembly->code.index;
+	guint32 new_code_index = (old_code_index + 3) & ~3;
+	if (new_code_index > old_code_index) {
+		guint32 padding_needed = new_code_index - old_code_index;
+		make_room_in_stream (&assembly->code, new_code_index);
+		memset (assembly->code.data + old_code_index, 0, padding_needed);
+		assembly->code.index = new_code_index;
+	}
 	assembly->meta_size += 3;
 	assembly->meta_size &= ~3;
-	assembly->resources.index += 3;
-	assembly->resources.index &= ~3;
+	guint32 old_res_index = assembly->resources.index;
+	guint32 new_res_index = (old_res_index + 3) & ~3;
+	if (new_res_index > old_res_index) {
+		guint32 padding_needed = new_res_index - old_res_index;
+		make_room_in_stream (&assembly->resources, new_res_index);
+		memset (assembly->resources.data + old_res_index, 0, padding_needed);
+		assembly->resources.index = new_res_index;
+	}
 
 	assembly->sections [MONO_SECTION_TEXT].size = assembly->meta_size + assembly->code.index + assembly->resources.index + assembly->strong_name_size;
 	assembly->sections [MONO_SECTION_TEXT].attrs = SECT_FLAGS_HAS_CODE | SECT_FLAGS_MEM_EXECUTE | SECT_FLAGS_MEM_READ;
