T* data_; // Backing storage.
double min_load_factor_;
double max_load_factor_;
+
+ ART_FRIEND_TEST(InternTableTest, CrossHash);
};
template <class T, class EmptyFn, class HashFn, class Pred, class Alloc>
if (kIsDebugBuild) {
Locks::mutator_lock_->AssertSharedHeld(Thread::Current());
}
- return static_cast<size_t>(root.Read<kWithoutReadBarrier>()->GetHashCode());
+ // An additional cast to prevent undesired sign extension.
+ return static_cast<size_t>(
+ static_cast<uint32_t>(root.Read<kWithoutReadBarrier>()->GetHashCode()));
}
bool InternTable::StringHashEquals::operator()(const GcRoot<mirror::String>& a,
NO_THREAD_SAFETY_ANALYSIS;
// Utf8String can be used for lookup.
- std::size_t operator()(const Utf8String& key) const { return key.GetHash(); }
+ std::size_t operator()(const Utf8String& key) const {
+ // A cast to prevent undesired sign extension.
+ return static_cast<uint32_t>(key.GetHash());
+ }
+
bool operator()(const GcRoot<mirror::String>& a, const Utf8String& b) const
NO_THREAD_SAFETY_ANALYSIS;
};
// We call AddNewTable when we create the zygote to reduce private dirty pages caused by
// modifying the zygote intern table. The back of table is modified when strings are interned.
std::vector<UnorderedSet> tables_;
+
+ ART_FRIEND_TEST(InternTableTest, CrossHash);
};
// Insert if non null, otherwise return null. Must be called holding the mutator lock.
gc::WeakRootState weak_root_state_ GUARDED_BY(Locks::intern_table_lock_);
friend class Transaction;
+ ART_FRIEND_TEST(InternTableTest, CrossHash);
DISALLOW_COPY_AND_ASSIGN(InternTable);
};
#include "intern_table.h"
+#include "base/hash_set.h"
#include "common_runtime_test.h"
#include "mirror/object.h"
#include "handle_scope-inl.h"
EXPECT_EQ(2U, t.Size());
}
+// Check if table indexes match on 64 and 32 bit machines.
+// This is done by ensuring hash values are the same on every machine and limited to 32-bit wide.
+// Otherwise cross compilation can cause a table to be filled on host using one indexing algorithm
+// and later on a device with different sizeof(size_t) can use another indexing algorithm.
+// Thus the table may provide wrong data.
+TEST_F(InternTableTest, CrossHash) {
+ ScopedObjectAccess soa(Thread::Current());
+ InternTable t;
+
+ // A string that has a negative hash value.
+ GcRoot<mirror::String> str(mirror::String::AllocFromModifiedUtf8(soa.Self(), "00000000"));
+
+ MutexLock mu(Thread::Current(), *Locks::intern_table_lock_);
+ for (InternTable::Table::UnorderedSet& table : t.strong_interns_.tables_) {
+ // The negative hash value shall be 32-bit wide on every host.
+ ASSERT_TRUE(IsUint<32>(table.hashfn_(str)));
+ }
+}
+
class TestPredicate : public IsMarkedVisitor {
public:
mirror::Object* IsMarked(mirror::Object* s) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {