tint: Add hash randomization

Enable this in Kororo builds to ensure that output isn't dependent on
hash values.

Change-Id: Ib538385b53bebf5260186b14cea396dac15caf6c
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/113980
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
This commit is contained in:
Ben Clayton 2022-12-13 14:46:02 +00:00 committed by Dawn LUCI CQ
parent 10182c46d9
commit f2b86aaffb
20 changed files with 43 additions and 98 deletions

View File

@ -171,6 +171,7 @@ option_if_not_defined(TINT_BUILD_REMOTE_COMPILE "Build the remote-compile tool f
option_if_not_defined(TINT_ENABLE_BREAK_IN_DEBUGGER "Enable tint::debugger::Break()" OFF)
option_if_not_defined(TINT_CHECK_CHROMIUM_STYLE "Check for [chromium-style] issues during build" OFF)
option_if_not_defined(TINT_SYMBOL_STORE_DEBUG_NAME "Enable storing of name in tint::ast::Symbol to help debugging the AST" OFF)
option_if_not_defined(TINT_RANDOMIZE_HASHES "Randomize the hash seed value to detect non-deterministic output" OFF)
# Recommended setting for compability with future abseil releases.
set(ABSL_PROPAGATE_CXX_STD ON)
@ -598,6 +599,15 @@ function(tint_default_compile_options TARGET)
)
endif()
endif()
if (TINT_RANDOMIZE_HASHES)
if(NOT DEFINED TINT_HASH_SEED)
string(RANDOM LENGTH 16 ALPHABET "0123456789abcdef" seed)
set(TINT_HASH_SEED "0x${seed}" CACHE STRING "Tint hash seed value")
message("Using TINT_HASH_SEED: ${TINT_HASH_SEED}")
endif()
target_compile_definitions(${TARGET} PUBLIC "-DTINT_HASH_SEED=${TINT_HASH_SEED}")
endif()
endfunction()
################################################################################

View File

@ -129,6 +129,7 @@ if [ "$BUILD_SYSTEM" == "cmake" ]; then
COMMON_CMAKE_FLAGS+=" -DTINT_BUILD_MSL_WRITER=1"
COMMON_CMAKE_FLAGS+=" -DTINT_BUILD_SPV_WRITER=1"
COMMON_CMAKE_FLAGS+=" -DTINT_BUILD_WGSL_WRITER=1"
COMMON_CMAKE_FLAGS+=" -DTINT_RANDOMIZE_HASHES=1"
if [ "$BUILD_TOOLCHAIN" == "clang" ]; then
using clang-10.0.0

View File

@ -109,7 +109,20 @@ call :status "Configuring build system"
@echo on
mkdir %BUILD_DIR%
cd /d %BUILD_DIR%
set COMMON_CMAKE_FLAGS=-DTINT_BUILD_DOCS=O -DTINT_BUILD_BENCHMARKS=1 -DCMAKE_BUILD_TYPE=%BUILD_TYPE% -DTINT_BUILD_BENCHMARKS=1 -DTINT_BUILD_SPV_READER=1 -DTINT_BUILD_WGSL_READER=1 -DTINT_BUILD_GLSL_WRITER=1 -DTINT_BUILD_HLSL_WRITER=1 -DTINT_BUILD_MSL_WRITER=1 -DTINT_BUILD_SPV_WRITER=1 -DTINT_BUILD_WGSL_WRITER=1
set COMMON_CMAKE_FLAGS= ^
-DTINT_BUILD_DOCS=O ^
-DTINT_BUILD_BENCHMARKS=1 ^
-DCMAKE_BUILD_TYPE=%BUILD_TYPE% ^
-DTINT_BUILD_BENCHMARKS=1 ^
-DTINT_BUILD_SPV_READER=1 ^
-DTINT_BUILD_WGSL_READER=1 ^
-DTINT_BUILD_GLSL_WRITER=1 ^
-DTINT_BUILD_HLSL_WRITER=1 ^
-DTINT_BUILD_MSL_WRITER=1 ^
-DTINT_BUILD_SPV_WRITER=1 ^
-DTINT_BUILD_WGSL_WRITER=1 ^
-DTINT_RANDOMIZE_HASHES=1
@echo off
call :status "Building dawn"

View File

@ -34,17 +34,6 @@ TEST_F(SemStructTest, Creation) {
EXPECT_EQ(s->SizeNoPadding(), 16u);
}
TEST_F(SemStructTest, Hash) {
auto* a_impl = create<ast::Struct>(Sym("a"), utils::Empty, utils::Empty);
auto* a = create<sem::Struct>(a_impl, a_impl->source, a_impl->name, utils::Empty,
4u /* align */, 4u /* size */, 4u /* size_no_padding */);
auto* b_impl = create<ast::Struct>(Sym("b"), utils::Empty, utils::Empty);
auto* b = create<sem::Struct>(b_impl, b_impl->source, b_impl->name, utils::Empty,
4u /* align */, 4u /* size */, 4u /* size_no_padding */);
EXPECT_NE(a->Hash(), b->Hash());
}
TEST_F(SemStructTest, Equals) {
auto* a_impl = create<ast::Struct>(Sym("a"), utils::Empty, utils::Empty);
auto* a = create<sem::Struct>(a_impl, a_impl->source, a_impl->name, utils::Empty,

View File

@ -74,18 +74,8 @@ TEST_F(ArrayTest, CreateRuntimeArray) {
TEST_F(ArrayTest, Hash) {
auto* a = create<Array>(create<U32>(), create<ConstantArrayCount>(2u), 4u, 8u, 32u, 16u);
auto* b = create<Array>(create<U32>(), create<ConstantArrayCount>(2u), 4u, 8u, 32u, 16u);
auto* c = create<Array>(create<U32>(), create<ConstantArrayCount>(3u), 4u, 8u, 32u, 16u);
auto* d = create<Array>(create<U32>(), create<ConstantArrayCount>(2u), 5u, 8u, 32u, 16u);
auto* e = create<Array>(create<U32>(), create<ConstantArrayCount>(2u), 4u, 9u, 32u, 16u);
auto* f = create<Array>(create<U32>(), create<ConstantArrayCount>(2u), 4u, 8u, 33u, 16u);
auto* g = create<Array>(create<U32>(), create<ConstantArrayCount>(2u), 4u, 8u, 33u, 17u);
EXPECT_EQ(a->Hash(), b->Hash());
EXPECT_NE(a->Hash(), c->Hash());
EXPECT_NE(a->Hash(), d->Hash());
EXPECT_NE(a->Hash(), e->Hash());
EXPECT_NE(a->Hash(), f->Hash());
EXPECT_NE(a->Hash(), g->Hash());
}
TEST_F(ArrayTest, Equals) {

View File

@ -33,9 +33,7 @@ TEST_F(AtomicTest, Creation) {
TEST_F(AtomicTest, Hash) {
auto* a = create<Atomic>(create<I32>());
auto* b = create<Atomic>(create<I32>());
auto* c = create<Atomic>(create<U32>());
EXPECT_EQ(a->Hash(), b->Hash());
EXPECT_NE(a->Hash(), c->Hash());
}
TEST_F(AtomicTest, Equals) {

View File

@ -36,10 +36,8 @@ TEST_F(DepthTextureTest, Creation) {
TEST_F(DepthTextureTest, Hash) {
auto* a = create<DepthTexture>(ast::TextureDimension::k2d);
auto* b = create<DepthTexture>(ast::TextureDimension::k2d);
auto* c = create<DepthTexture>(ast::TextureDimension::k2dArray);
EXPECT_EQ(a->Hash(), b->Hash());
EXPECT_NE(a->Hash(), c->Hash());
}
TEST_F(DepthTextureTest, Equals) {

View File

@ -40,14 +40,8 @@ TEST_F(MatrixTest, Creation) {
TEST_F(MatrixTest, Hash) {
auto* a = create<Matrix>(create<Vector>(create<I32>(), 3u), 4u);
auto* b = create<Matrix>(create<Vector>(create<I32>(), 3u), 4u);
auto* c = create<Matrix>(create<Vector>(create<F32>(), 3u), 4u);
auto* d = create<Matrix>(create<Vector>(create<I32>(), 2u), 4u);
auto* e = create<Matrix>(create<Vector>(create<I32>(), 3u), 2u);
EXPECT_EQ(a->Hash(), b->Hash());
EXPECT_NE(a->Hash(), c->Hash());
EXPECT_NE(a->Hash(), d->Hash());
EXPECT_NE(a->Hash(), e->Hash());
}
TEST_F(MatrixTest, Equals) {

View File

@ -38,11 +38,7 @@ TEST_F(MultisampledTextureTest, Creation) {
TEST_F(MultisampledTextureTest, Hash) {
auto* a = create<MultisampledTexture>(ast::TextureDimension::k2d, create<F32>());
auto* b = create<MultisampledTexture>(ast::TextureDimension::k2d, create<F32>());
auto* c = create<MultisampledTexture>(ast::TextureDimension::k3d, create<F32>());
auto* d = create<MultisampledTexture>(ast::TextureDimension::k2d, create<I32>());
EXPECT_EQ(a->Hash(), b->Hash());
EXPECT_NE(a->Hash(), c->Hash());
EXPECT_NE(a->Hash(), d->Hash());
}
TEST_F(MultisampledTextureTest, Equals) {

View File

@ -40,14 +40,8 @@ TEST_F(PointerTest, Creation) {
TEST_F(PointerTest, Hash) {
auto* a = create<Pointer>(create<I32>(), ast::AddressSpace::kStorage, ast::Access::kReadWrite);
auto* b = create<Pointer>(create<I32>(), ast::AddressSpace::kStorage, ast::Access::kReadWrite);
auto* c = create<Pointer>(create<F32>(), ast::AddressSpace::kStorage, ast::Access::kReadWrite);
auto* d = create<Pointer>(create<I32>(), ast::AddressSpace::kPrivate, ast::Access::kReadWrite);
auto* e = create<Pointer>(create<I32>(), ast::AddressSpace::kStorage, ast::Access::kRead);
EXPECT_EQ(a->Hash(), b->Hash());
EXPECT_NE(a->Hash(), c->Hash());
EXPECT_NE(a->Hash(), d->Hash());
EXPECT_NE(a->Hash(), e->Hash());
}
TEST_F(PointerTest, Equals) {

View File

@ -46,16 +46,8 @@ TEST_F(ReferenceTest, Hash) {
create<Reference>(create<I32>(), ast::AddressSpace::kStorage, ast::Access::kReadWrite);
auto* b =
create<Reference>(create<I32>(), ast::AddressSpace::kStorage, ast::Access::kReadWrite);
auto* c =
create<Reference>(create<F32>(), ast::AddressSpace::kStorage, ast::Access::kReadWrite);
auto* d =
create<Reference>(create<I32>(), ast::AddressSpace::kPrivate, ast::Access::kReadWrite);
auto* e = create<Reference>(create<I32>(), ast::AddressSpace::kStorage, ast::Access::kRead);
EXPECT_EQ(a->Hash(), b->Hash());
EXPECT_NE(a->Hash(), c->Hash());
EXPECT_NE(a->Hash(), d->Hash());
EXPECT_NE(a->Hash(), e->Hash());
}
TEST_F(ReferenceTest, Equals) {

View File

@ -41,12 +41,8 @@ TEST_F(SampledTextureTest, Creation) {
TEST_F(SampledTextureTest, Hash) {
auto* a = create<SampledTexture>(ast::TextureDimension::kCube, create<F32>());
auto* b = create<SampledTexture>(ast::TextureDimension::kCube, create<F32>());
auto* c = create<SampledTexture>(ast::TextureDimension::k2d, create<F32>());
auto* d = create<SampledTexture>(ast::TextureDimension::kCube, create<I32>());
EXPECT_EQ(a->Hash(), b->Hash());
EXPECT_NE(a->Hash(), c->Hash());
EXPECT_NE(a->Hash(), d->Hash());
}
TEST_F(SampledTextureTest, Equals) {

View File

@ -39,10 +39,8 @@ TEST_F(SamplerTest, Creation) {
TEST_F(SamplerTest, Hash) {
auto* a = create<Sampler>(ast::SamplerKind::kSampler);
auto* b = create<Sampler>(ast::SamplerKind::kSampler);
auto* c = create<Sampler>(ast::SamplerKind::kComparisonSampler);
EXPECT_EQ(a->Hash(), b->Hash());
EXPECT_NE(a->Hash(), c->Hash());
}
TEST_F(SamplerTest, Equals) {

View File

@ -55,17 +55,8 @@ TEST_F(StorageTextureTest, Hash) {
ast::Access::kReadWrite);
auto* b = Create(ast::TextureDimension::kCube, ast::TexelFormat::kRgba32Float,
ast::Access::kReadWrite);
auto* c =
Create(ast::TextureDimension::k2d, ast::TexelFormat::kRgba32Float, ast::Access::kReadWrite);
auto* d =
Create(ast::TextureDimension::kCube, ast::TexelFormat::kR32Float, ast::Access::kReadWrite);
auto* e =
Create(ast::TextureDimension::kCube, ast::TexelFormat::kRgba32Float, ast::Access::kRead);
EXPECT_EQ(a->Hash(), b->Hash());
EXPECT_NE(a->Hash(), c->Hash());
EXPECT_NE(a->Hash(), d->Hash());
EXPECT_NE(a->Hash(), e->Hash());
}
TEST_F(StorageTextureTest, Equals) {

View File

@ -31,15 +31,6 @@ TEST_F(TypeStructTest, Creation) {
EXPECT_EQ(s->SizeNoPadding(), 16u);
}
TEST_F(TypeStructTest, Hash) {
auto* a = create<Struct>(Source{}, Sym("a"), utils::Empty, 4u /* align */, 4u /* size */,
4u /* size_no_padding */);
auto* b = create<Struct>(Source{}, Sym("b"), utils::Empty, 4u /* align */, 4u /* size */,
4u /* size_no_padding */);
EXPECT_NE(a->Hash(), b->Hash());
}
TEST_F(TypeStructTest, Equals) {
auto* a = create<Struct>(Source{}, Sym("a"), utils::Empty, 4u /* align */, 4u /* size */,
4u /* size_no_padding */);

View File

@ -37,12 +37,8 @@ TEST_F(VectorTest, Creation) {
TEST_F(VectorTest, Hash) {
auto* a = create<Vector>(create<I32>(), 2u);
auto* b = create<Vector>(create<I32>(), 2u);
auto* c = create<Vector>(create<F32>(), 2u);
auto* d = create<Vector>(create<F32>(), 3u);
EXPECT_EQ(a->Hash(), b->Hash());
EXPECT_NE(a->Hash(), c->Hash());
EXPECT_NE(a->Hash(), d->Hash());
}
TEST_F(VectorTest, Equals) {

View File

@ -192,7 +192,6 @@ TEST(EnumSetTest, InequalityEnum) {
TEST(EnumSetTest, Hash) {
auto hash = [&](EnumSet<E> s) { return std::hash<EnumSet<E>>()(s); };
EXPECT_EQ(hash(EnumSet<E>(E::A, E::B)), hash(EnumSet<E>(E::A, E::B)));
EXPECT_NE(hash(EnumSet<E>(E::A, E::B)), hash(EnumSet<E>(E::A, E::C)));
}
TEST(EnumSetTest, Value) {

View File

@ -23,6 +23,7 @@
#include <variant>
#include <vector>
#include "src/tint/utils/crc32.h"
#include "src/tint/utils/vector.h"
namespace tint::utils {
@ -37,14 +38,26 @@ struct HashCombineOffset {};
template <>
struct HashCombineOffset<4> {
/// @returns the seed bias value for HashCombine()
static constexpr inline uint32_t value() { return 0x7f4a7c16; }
static constexpr inline uint32_t value() {
constexpr uint32_t base = 0x7f4a7c16;
#ifdef TINT_HASH_SEED
return base ^ static_cast<uint32_t>(TINT_HASH_SEED);
#endif
return base;
}
};
/// Specialization of HashCombineOffset for size_t == 8.
template <>
struct HashCombineOffset<8> {
/// @returns the seed bias value for HashCombine()
static constexpr inline uint64_t value() { return 0x9e3779b97f4a7c16; }
static constexpr inline uint64_t value() {
constexpr uint64_t base = 0x9e3779b97f4a7c16;
#ifdef TINT_HASH_SEED
return base ^ static_cast<uint64_t>(TINT_HASH_SEED);
#endif
return base;
}
};
} // namespace detail
@ -76,6 +89,9 @@ struct Hasher<T*> {
/// @returns a hash of the pointer
size_t operator()(T* ptr) const {
auto hash = std::hash<T*>()(ptr);
#ifdef TINT_HASH_SEED
hash ^= static_cast<uint32_t>(TINT_HASH_SEED);
#endif
return hash ^ (hash >> 4);
}
};

View File

@ -26,28 +26,19 @@ namespace {
TEST(HashTests, Basic) {
EXPECT_EQ(Hash(123), Hash(123));
EXPECT_NE(Hash(123), Hash(321));
EXPECT_EQ(Hash(123, 456), Hash(123, 456));
EXPECT_NE(Hash(123, 456), Hash(456, 123));
EXPECT_NE(Hash(123, 456), Hash(123));
EXPECT_EQ(Hash(123, 456, false), Hash(123, 456, false));
EXPECT_NE(Hash(123, 456, false), Hash(123, 456));
EXPECT_EQ(Hash(std::string("hello")), Hash(std::string("hello")));
EXPECT_NE(Hash(std::string("hello")), Hash(std::string("world")));
}
TEST(HashTests, StdVector) {
EXPECT_EQ(Hash(std::vector<int>({})), Hash(std::vector<int>({})));
EXPECT_EQ(Hash(std::vector<int>({1, 2, 3})), Hash(std::vector<int>({1, 2, 3})));
EXPECT_NE(Hash(std::vector<int>({1, 2, 3})), Hash(std::vector<int>({1, 2, 4})));
EXPECT_NE(Hash(std::vector<int>({1, 2, 3})), Hash(std::vector<int>({1, 2, 3, 4})));
}
TEST(HashTests, TintVector) {
EXPECT_EQ(Hash(Vector<int, 0>({})), Hash(Vector<int, 0>({})));
EXPECT_EQ(Hash(Vector<int, 0>({1, 2, 3})), Hash(Vector<int, 0>({1, 2, 3})));
EXPECT_NE(Hash(Vector<int, 0>({1, 2, 3})), Hash(Vector<int, 0>({1, 2, 4})));
EXPECT_NE(Hash(Vector<int, 0>({1, 2, 3})), Hash(Vector<int, 0>({1, 2, 3, 4})));
EXPECT_EQ(Hash(Vector<int, 3>({1, 2, 3})), Hash(Vector<int, 4>({1, 2, 3})));
EXPECT_EQ(Hash(Vector<int, 3>({1, 2, 3})), Hash(Vector<int, 2>({1, 2, 3})));
}
@ -55,8 +46,6 @@ TEST(HashTests, TintVector) {
TEST(HashTests, Tuple) {
EXPECT_EQ(Hash(std::make_tuple(1)), Hash(std::make_tuple(1)));
EXPECT_EQ(Hash(std::make_tuple(1, 2, 3)), Hash(std::make_tuple(1, 2, 3)));
EXPECT_NE(Hash(std::make_tuple(1, 2, 3)), Hash(std::make_tuple(1, 2, 4)));
EXPECT_NE(Hash(std::make_tuple(1, 2, 3)), Hash(std::make_tuple(1, 2, 3, 4)));
}
TEST(HashTests, UnorderedKeyWrapper) {

View File

@ -388,11 +388,8 @@ TEST(Hashmap, HashSameSize) {
Hashmap<int, std::string, 8> b;
EXPECT_EQ(Hash(a), Hash(b));
a.Add(1, "one");
EXPECT_NE(Hash(a), Hash(b));
b.Add(2, "two");
EXPECT_NE(Hash(a), Hash(b));
a.Add(2, "two");
EXPECT_NE(Hash(a), Hash(b));
b.Add(1, "one");
EXPECT_EQ(Hash(a), Hash(b));
}
@ -402,11 +399,8 @@ TEST(Hashmap, HashDifferentSize) {
Hashmap<int, std::string, 4> b;
EXPECT_EQ(Hash(a), Hash(b));
a.Add(1, "one");
EXPECT_NE(Hash(a), Hash(b));
b.Add(2, "two");
EXPECT_NE(Hash(a), Hash(b));
a.Add(2, "two");
EXPECT_NE(Hash(a), Hash(b));
b.Add(1, "one");
EXPECT_EQ(Hash(a), Hash(b));
}