Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.

Commit 702e0c1

Browse files
committed
Fix Issue 19282 - hashOf segfaults for non-null C++ objects
1 parent 019217a commit 702e0c1

File tree

2 files changed

+29
-6
lines changed

2 files changed

+29
-6
lines changed

src/core/internal/hash.d

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,18 @@ private enum isFinalClassWithAddressBasedHash(T) = __traits(isFinalClass, T)
5757
static assert(!isFinalClassWithAddressBasedHash!C3);
5858
}
5959

60+
private template isCppClassWithoutHash(T)
61+
{
62+
static if (!is(T == class) && !is(T == interface))
63+
enum isCppClassWithoutHash = false;
64+
else
65+
{
66+
import core.internal.traits : Unqual;
67+
enum bool isCppClassWithoutHash = __traits(getLinkage, T) == "C++"
68+
&& !is(Unqual!T : Object) && !hasCallableToHash!T;
69+
}
70+
}
71+
6072
/+
6173
Is it valid to calculate a hash code for T based on the bits of its
6274
representation? Always false for interfaces, dynamic arrays, and
@@ -80,11 +92,11 @@ private template canBitwiseHash(T)
8092
enum canBitwiseHash = true;
8193
else static if (is(T == class))
8294
{
83-
enum canBitwiseHash = isFinalClassWithAddressBasedHash!T;
95+
enum canBitwiseHash = isFinalClassWithAddressBasedHash!T || isCppClassWithoutHash!T;
8496
}
8597
else static if (is(T == interface))
8698
{
87-
enum canBitwiseHash = false;
99+
enum canBitwiseHash = isCppClassWithoutHash!T;
88100
}
89101
else static if (is(T == struct))
90102
{
@@ -553,7 +565,7 @@ size_t hashOf(T)(scope const T val, size_t seed = 0) if (!is(T == enum) && is(T
553565
@nogc nothrow pure @trusted
554566
size_t hashOf(T)(scope const T val)
555567
if (!is(T == enum) && (is(T == interface) || is(T == class))
556-
&& isFinalClassWithAddressBasedHash!T)
568+
&& canBitwiseHash!T)
557569
{
558570
if (__ctfe) if (val is null) return 0;
559571
return hashOf(cast(const void*) val);
@@ -563,7 +575,7 @@ if (!is(T == enum) && (is(T == interface) || is(T == class))
563575
@nogc nothrow pure @trusted
564576
size_t hashOf(T)(scope const T val, size_t seed)
565577
if (!is(T == enum) && (is(T == interface) || is(T == class))
566-
&& isFinalClassWithAddressBasedHash!T)
578+
&& canBitwiseHash!T)
567579
{
568580
if (__ctfe) if (val is null) return hashOf(size_t(0), seed);
569581
return hashOf(cast(const void*) val, seed);
@@ -572,7 +584,7 @@ if (!is(T == enum) && (is(T == interface) || is(T == class))
572584
//class or interface hash. CTFE depends on toHash
573585
size_t hashOf(T)(T val)
574586
if (!is(T == enum) && (is(T == interface) || is(T == class))
575-
&& !isFinalClassWithAddressBasedHash!T)
587+
&& !canBitwiseHash!T)
576588
{
577589
static if (__traits(compiles, {size_t h = val.toHash();}))
578590
return val ? val.toHash() : 0;
@@ -583,7 +595,7 @@ if (!is(T == enum) && (is(T == interface) || is(T == class))
583595
//class or interface hash. CTFE depends on toHash
584596
size_t hashOf(T)(T val, size_t seed)
585597
if (!is(T == enum) && (is(T == interface) || is(T == class))
586-
&& !isFinalClassWithAddressBasedHash!T)
598+
&& !canBitwiseHash!T)
587599
{
588600
static if (__traits(compiles, {size_t h = val.toHash();}))
589601
return hashOf(val ? cast(size_t) val.toHash() : size_t(0), seed);

test/hash/src/test_hash.d

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ void main()
66
issue18918();
77
issue18925();
88
issue19005();
9+
issue19282();
910
testTypeInfoArrayGetHash1();
1011
testTypeInfoArrayGetHash2();
1112
pr2243();
@@ -85,6 +86,16 @@ void issue19005() @nogc nothrow pure @safe
8586
auto hash = date.hashOf;
8687
}
8788

89+
extern(C++) class Issue19282CppClass {}
90+
91+
/// test that hashOf doesn't crash for non-null C++ objects.
92+
void issue19282()
93+
{
94+
Issue19282CppClass c = new Issue19282CppClass();
95+
size_t h = hashOf(c);
96+
h = hashOf(c, h);
97+
}
98+
8899
/// Tests ensure TypeInfo_Array.getHash uses element hash functions instead
89100
/// of hashing array data.
90101
void testTypeInfoArrayGetHash1()

0 commit comments

Comments
 (0)