-
-
Save afish/de9efe886164e9cdea74 to your computer and use it in GitHub Desktop.
Allocating reference type on a stack in C#
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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
Genial 👌