Skip to content

Instantly share code, notes, and snippets.

@afish

afish/Makeref.cs Secret

Created Feb 12, 2016
Embed
What would you like to do?
Allocating reference type on a stack in C#
// This application stores managed object on stack
// See https://blog.adamfurmanek.pl/2016/04/23/custom-memory-allocation-in-c-part-1
// Windbg internals:
/*
Load SOS:
.load C:\Windows\Microsoft.NET\Framework\v4.0.30319\sos.dll
Select proper thread:
~0s
Present all values:
!clrstack -i -a
Examine values of heapPoco and stack
Observe 0x0BADF00D on stack
Find EE Method of Poco class
heapPocoAddress: 0x2e13120
stackAddress: 0117f034
dd 0x2e13120 ; heapPocoAddress
!do 0x2e13120 ; heapPocoAddress
dd 0117f034 ; stack address
*/
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Makeref
{
class Poco
{
public int Field;
public void WriteField()
{
Console.WriteLine(Field);
}
public override string ToString()
{
return Field.ToString();
}
~Poco()
{
Console.WriteLine("Cleaning: " + Field);
}
}
class Program
{
static void Main(string[] args)
{
Poco heapPoco = new Poco {Field = 5};
Poco originalPoco = heapPoco;
unsafe
{
var space = stackalloc int[10];
for (int i = 0; i < 10; ++i)
{
space[i] = 0xBADF00D;
}
TypedReference typedReference = __makeref(heapPoco);
int* poco1Address = (int*)(*(int*)(*(int*)(&typedReference)) - 4);
Console.WriteLine($"Got address of EE method: {((int) (poco1Address + 1)).ToString("X")} Value: {(*(poco1Address + 1)).ToString("X")}");
Console.ReadLine();
for (int i = 0; i < 3; ++i)
{
Console.WriteLine($"Address {((int) poco1Address).ToString("X")} Value {(*poco1Address).ToString("X")}");
space[i] = *poco1Address;
poco1Address = poco1Address + 1;
}
Console.WriteLine("Rewritten values");
Console.ReadLine();
*((int*)*((int*)&typedReference)) = (int)(&(space[1]));
Console.WriteLine($"Set reference to stack: {(int)&(space[1])}");
Console.ReadLine();
Poco stackPoco = __refvalue(typedReference, Poco);
//Poco stackPoco = heapPoco; - This is the same
Console.WriteLine("Got poco on stack. Displaying values:");
Console.Write("Heap: ");
originalPoco.WriteField();
Console.Write("Stack: ");
stackPoco.WriteField();
Console.WriteLine("Modifying values using references. Displaying values:");
originalPoco.Field = 555;
stackPoco.Field = 444;
Console.Write("Heap: ");
originalPoco.WriteField();
Console.Write("Stack: ");
stackPoco.WriteField();
Console.WriteLine("Modifying value using array on a stack. Displaying values:");
space[2] = 333;
Console.Write("Heap: ");
originalPoco.WriteField();
Console.Write("Stack: ");
stackPoco.WriteField();
Console.ReadLine();
Console.WriteLine("Calling virtual method:");
Console.WriteLine("Heap: " + originalPoco.ToString());
Console.WriteLine("Stack: " + stackPoco.ToString());
Console.ReadLine();
Console.WriteLine("Displaying object types:");
Console.WriteLine(originalPoco.GetType());
Console.WriteLine(stackPoco.GetType());
Console.ReadLine();
Console.WriteLine("Displaying GC generations:");
Console.WriteLine(GC.GetGeneration(originalPoco));
Console.WriteLine(GC.GetGeneration(stackPoco));
//GC.ReRegisterForFinalize(stackPoco); - bad idea
Console.ReadLine();
Console.WriteLine("Threading:");
Console.WriteLine($"Taking lock in base: {DateTime.Now}");
lock (stackPoco)
{
Console.WriteLine($"Lock in base aquired: {DateTime.Now}");
Task.Factory.StartNew(() =>
{
Console.WriteLine($"Taking lock in child: {DateTime.Now}");
lock (stackPoco)
{
Console.WriteLine($"Lock in child aquired: {DateTime.Now}");
}
Console.WriteLine($"Lock in child released: {DateTime.Now}");
});
Thread.Sleep(2000);
}
Console.WriteLine($"Lock in base released: {DateTime.Now}");
Console.ReadLine();
Console.WriteLine("End");
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment