Skip to content

Instantly share code, notes, and snippets.

@Porges
Last active October 2, 2017 21:56
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Porges/4b5fb3f0d66093105422e9892177754f to your computer and use it in GitHub Desktop.
Save Porges/4b5fb3f0d66093105422e9892177754f to your computer and use it in GitHub Desktop.
unsafe void Main()
{
var s = "hello world";
Console.WriteLine($"String hash code: {s.GetHashCode()}");
var hashCode = RuntimeHelpers.GetHashCode(s);
Console.WriteLine($"Object hash code: {hashCode}");
Console.WriteLine("Poking string...");
fixed (char* cs = s)
{
int* iptr = (int*)cs;
// String layout is [4 bytes for size][size*data...]:
var strlen = *(iptr - 1);
Console.WriteLine($"...string length is: {strlen}");
// Object is preceded by the type code:
var typeCodePtr = iptr - 2;
Console.WriteLine($"...string type code: {*typeCodePtr}");
// Then the sync block:
var syncBlockPtr = iptr - 3;
var syncBlockIndex = *syncBlockPtr;
Console.WriteLine($"...sync block index: {syncBlockIndex}");
const int hashOrSyncBlockBit = 0x08000000;
const int hashCodeBit = 0x04000000;
const int hashCodeMask = (1 << 26) - 1;
if ((syncBlockIndex & hashOrSyncBlockBit) == hashOrSyncBlockBit)
{
if ((syncBlockIndex & hashCodeBit) == hashCodeBit)
{
// if we get here, the sync block index contains the hash code
Console.WriteLine($"Found object hash code: {syncBlockIndex & hashCodeMask}");
Console.WriteLine("Putting object into (reference equality) set...");
var set = new HashSet<object>(new ReferenceEqualityComparer());
set.Add(s);
Console.WriteLine($"...in set? {set.Contains(s)}");
Console.WriteLine($"Updating hash code...");
*syncBlockPtr = syncBlockIndex + 1; // evil
Console.WriteLine($"...still in set? {set.Contains(s)}");
}
}
Console.WriteLine("Turning the string into a float...");
*typeCodePtr = GetFloatTypeCode(); // pure evil
}
Console.WriteLine($"Cthulhu fhtagn! ia ia {s}");
}
unsafe static int GetFloatTypeCode()
{
object f = 1.0;
var gcHandle = GCHandle.Alloc(f, GCHandleType.Pinned);
var ptr = (int*)gcHandle.AddrOfPinnedObject();
var floatTypeCode = *(ptr - 1);
gcHandle.Free();
Console.WriteLine($"...got float type code: {floatTypeCode}");
return floatTypeCode;
}
class ReferenceEqualityComparer : IEqualityComparer<object>
{
public new bool Equals(object l, object r) => ReferenceEquals(l, r);
public int GetHashCode(object o) => RuntimeHelpers.GetHashCode(o);
}
String hash code: -1660775320
Object hash code: 52253787
Poking string...
...string length is: 11
...string type code: 1906534512
...sync block index: -1893903269
Found object hash code: 52253787
Putting object into (reference equality) set...
...in set? True
Updating hash code...
...still in set? False
Turning the string into a float...
...got float type code: 1906530124
Cthulhu fhtagn! ia ia 9.3460164059295E-307
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment