Last active
October 2, 2017 21:56
-
-
Save Porges/4b5fb3f0d66093105422e9892177754f to your computer and use it in GitHub Desktop.
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
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); | |
} |
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
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