1b1994897Sopenharmony_ci/** 2b1994897Sopenharmony_ci * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 3b1994897Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4b1994897Sopenharmony_ci * you may not use this file except in compliance with the License. 5b1994897Sopenharmony_ci * You may obtain a copy of the License at 6b1994897Sopenharmony_ci * 7b1994897Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8b1994897Sopenharmony_ci * 9b1994897Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10b1994897Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11b1994897Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12b1994897Sopenharmony_ci * See the License for the specific language governing permissions and 13b1994897Sopenharmony_ci * limitations under the License. 14b1994897Sopenharmony_ci */ 15b1994897Sopenharmony_ci 16b1994897Sopenharmony_ci#include <ctime> 17b1994897Sopenharmony_ci#include "utils/hash.h" 18b1994897Sopenharmony_ci 19b1994897Sopenharmony_ci#include "gtest/gtest.h" 20b1994897Sopenharmony_ci#include "utils/logger.h" 21b1994897Sopenharmony_ci#include "mem/mem.h" 22b1994897Sopenharmony_ci#include "os/mem.h" 23b1994897Sopenharmony_ci#include "utils/asan_interface.h" 24b1994897Sopenharmony_ci 25b1994897Sopenharmony_cinamespace panda { 26b1994897Sopenharmony_ci 27b1994897Sopenharmony_ciclass HashTest : public testing::Test { 28b1994897Sopenharmony_cipublic: 29b1994897Sopenharmony_ci HashTest() 30b1994897Sopenharmony_ci { 31b1994897Sopenharmony_ci#ifdef PANDA_NIGHTLY_TEST_ON 32b1994897Sopenharmony_ci seed_ = std::time(NULL); 33b1994897Sopenharmony_ci#else 34b1994897Sopenharmony_ci seed_ = 0xDEADBEEF; 35b1994897Sopenharmony_ci#endif 36b1994897Sopenharmony_ci } 37b1994897Sopenharmony_ci ~HashTest() {} 38b1994897Sopenharmony_ci 39b1994897Sopenharmony_ciprotected: 40b1994897Sopenharmony_ci template <class T> 41b1994897Sopenharmony_ci void OneObject32bitsHashTest(); 42b1994897Sopenharmony_ci template <class T> 43b1994897Sopenharmony_ci void OneStringHashTest(); 44b1994897Sopenharmony_ci template <class T> 45b1994897Sopenharmony_ci void StringMemHashTest(); 46b1994897Sopenharmony_ci template <class T> 47b1994897Sopenharmony_ci void EndOfPageStringHashTest(); 48b1994897Sopenharmony_ci static constexpr size_t KEY40INBYTES = 5; 49b1994897Sopenharmony_ci static constexpr size_t KEY32INBYTES = 4; 50b1994897Sopenharmony_ci static constexpr size_t KEY8INBYTES = 1; 51b1994897Sopenharmony_ci 52b1994897Sopenharmony_ci// Some platforms have this macro so do not redefine it. 53b1994897Sopenharmony_ci#ifndef PAGE_SIZE 54b1994897Sopenharmony_ci static constexpr size_t PAGE_SIZE = SIZE_1K * 4; 55b1994897Sopenharmony_ci#endif 56b1994897Sopenharmony_ci 57b1994897Sopenharmony_ci unsigned seed_; 58b1994897Sopenharmony_ci}; 59b1994897Sopenharmony_ci 60b1994897Sopenharmony_citemplate <class T> 61b1994897Sopenharmony_civoid HashTest::OneObject32bitsHashTest() 62b1994897Sopenharmony_ci{ 63b1994897Sopenharmony_ci srand(seed_); 64b1994897Sopenharmony_ci 65b1994897Sopenharmony_ci uint32_t object32 = rand(); 66b1994897Sopenharmony_ci uint32_t first_hash = T::GetHash32(reinterpret_cast<uint8_t *>(&object32), KEY32INBYTES); 67b1994897Sopenharmony_ci uint32_t second_hash = T::GetHash32(reinterpret_cast<uint8_t *>(&object32), KEY32INBYTES); 68b1994897Sopenharmony_ci if (first_hash != second_hash) { 69b1994897Sopenharmony_ci std::cout << "Failed 32bit key hash on seed = 0x" << std::hex << seed_ << std::endl; 70b1994897Sopenharmony_ci } 71b1994897Sopenharmony_ci ASSERT_EQ(first_hash, second_hash); 72b1994897Sopenharmony_ci 73b1994897Sopenharmony_ci uint8_t object8 = rand(); 74b1994897Sopenharmony_ci first_hash = T::GetHash32(reinterpret_cast<uint8_t *>(&object8), KEY8INBYTES); 75b1994897Sopenharmony_ci second_hash = T::GetHash32(reinterpret_cast<uint8_t *>(&object8), KEY8INBYTES); 76b1994897Sopenharmony_ci if (first_hash != second_hash) { 77b1994897Sopenharmony_ci std::cout << "Failed 32bit key hash on seed = 0x" << std::hex << seed_ << std::endl; 78b1994897Sopenharmony_ci } 79b1994897Sopenharmony_ci ASSERT_EQ(first_hash, second_hash); 80b1994897Sopenharmony_ci 81b1994897Sopenharmony_ci // Set up 64 bits value and use only 40 bits from it 82b1994897Sopenharmony_ci uint64_t object40 = rand(); 83b1994897Sopenharmony_ci first_hash = T::GetHash32(reinterpret_cast<uint8_t *>(&object40), KEY40INBYTES); 84b1994897Sopenharmony_ci second_hash = T::GetHash32(reinterpret_cast<uint8_t *>(&object40), KEY40INBYTES); 85b1994897Sopenharmony_ci if (first_hash != second_hash) { 86b1994897Sopenharmony_ci std::cout << "Failed 32bit key hash on seed = 0x" << std::hex << seed_ << std::endl; 87b1994897Sopenharmony_ci } 88b1994897Sopenharmony_ci ASSERT_EQ(first_hash, second_hash); 89b1994897Sopenharmony_ci} 90b1994897Sopenharmony_ci 91b1994897Sopenharmony_citemplate <class T> 92b1994897Sopenharmony_civoid HashTest::OneStringHashTest() 93b1994897Sopenharmony_ci{ 94b1994897Sopenharmony_ci char string[] = "Over 1000!\0"; 95b1994897Sopenharmony_ci // Dummy check. Don't ask me why... 96b1994897Sopenharmony_ci if (sizeof(char) != sizeof(uint8_t)) { 97b1994897Sopenharmony_ci return; 98b1994897Sopenharmony_ci } 99b1994897Sopenharmony_ci uint8_t *mutf8_string = reinterpret_cast<uint8_t *>(string); 100b1994897Sopenharmony_ci uint32_t first_hash = T::GetHash32String(mutf8_string); 101b1994897Sopenharmony_ci uint32_t second_hash = T::GetHash32String(mutf8_string); 102b1994897Sopenharmony_ci ASSERT_EQ(first_hash, second_hash); 103b1994897Sopenharmony_ci} 104b1994897Sopenharmony_ci 105b1994897Sopenharmony_citemplate <class T> 106b1994897Sopenharmony_civoid HashTest::StringMemHashTest() 107b1994897Sopenharmony_ci{ 108b1994897Sopenharmony_ci char string[] = "COULD YOU CREATE MORE COMPLEX TESTS,OK?\0"; 109b1994897Sopenharmony_ci size_t string_size = strlen(string); 110b1994897Sopenharmony_ci uint8_t *mutf8_string = reinterpret_cast<uint8_t *>(string); 111b1994897Sopenharmony_ci uint32_t second_hash = T::GetHash32(mutf8_string, string_size); 112b1994897Sopenharmony_ci uint32_t first_hash = T::GetHash32String(mutf8_string); 113b1994897Sopenharmony_ci ASSERT_EQ(first_hash, second_hash); 114b1994897Sopenharmony_ci} 115b1994897Sopenharmony_ci 116b1994897Sopenharmony_citemplate <class T> 117b1994897Sopenharmony_civoid HashTest::EndOfPageStringHashTest() 118b1994897Sopenharmony_ci{ 119b1994897Sopenharmony_ci constexpr const int64_t immTwo = 2; 120b1994897Sopenharmony_ci size_t string_size = 3; 121b1994897Sopenharmony_ci constexpr size_t ALLOC_SIZE = PAGE_SIZE * 2; 122b1994897Sopenharmony_ci void *mem = panda::os::mem::MapRWAnonymousRaw(ALLOC_SIZE); 123b1994897Sopenharmony_ci ASAN_UNPOISON_MEMORY_REGION(mem, ALLOC_SIZE); 124b1994897Sopenharmony_ci panda::os::mem::MakeMemProtected(reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(mem) + PAGE_SIZE), PAGE_SIZE); 125b1994897Sopenharmony_ci char *string = 126b1994897Sopenharmony_ci reinterpret_cast<char *>((reinterpret_cast<uintptr_t>(mem) + PAGE_SIZE) - sizeof(char) * string_size); 127b1994897Sopenharmony_ci string[0] = 'O'; 128b1994897Sopenharmony_ci string[1] = 'K'; 129b1994897Sopenharmony_ci string[immTwo] = '\0'; 130b1994897Sopenharmony_ci uint8_t *mutf8_string = reinterpret_cast<uint8_t *>(string); 131b1994897Sopenharmony_ci uint32_t second_hash = T::GetHash32(mutf8_string, string_size - 1); 132b1994897Sopenharmony_ci uint32_t first_hash = T::GetHash32String(mutf8_string); 133b1994897Sopenharmony_ci ASSERT_EQ(first_hash, second_hash); 134b1994897Sopenharmony_ci auto res = panda::os::mem::UnmapRaw(mem, ALLOC_SIZE); 135b1994897Sopenharmony_ci ASSERT_FALSE(res); 136b1994897Sopenharmony_ci} 137b1994897Sopenharmony_ci 138b1994897Sopenharmony_ci// If we hash an object twice, it must return the same value 139b1994897Sopenharmony_ci// Do it for 8 bits key, 32 bits and 40 bits key. 140b1994897Sopenharmony_ciTEST_F(HashTest, OneObjectHashTest) 141b1994897Sopenharmony_ci{ 142b1994897Sopenharmony_ci HashTest::OneObject32bitsHashTest<MurmurHash32<DEFAULT_SEED>>(); 143b1994897Sopenharmony_ci} 144b1994897Sopenharmony_ci 145b1994897Sopenharmony_ci// If we hash a string twice, it must return the same value 146b1994897Sopenharmony_ciTEST_F(HashTest, OneStringHashTest) 147b1994897Sopenharmony_ci{ 148b1994897Sopenharmony_ci HashTest::OneStringHashTest<MurmurHash32<DEFAULT_SEED>>(); 149b1994897Sopenharmony_ci} 150b1994897Sopenharmony_ci 151b1994897Sopenharmony_ci// If we hash a string with out string method, 152b1994897Sopenharmony_ci// we should get the same result as we use a pointer to string as a raw memory. 153b1994897Sopenharmony_ciTEST_F(HashTest, StringMemHashTest) 154b1994897Sopenharmony_ci{ 155b1994897Sopenharmony_ci HashTest::StringMemHashTest<MurmurHash32<DEFAULT_SEED>>(); 156b1994897Sopenharmony_ci} 157b1994897Sopenharmony_ci 158b1994897Sopenharmony_ci// Try to hash the string which located at the end of allocated page. 159b1994897Sopenharmony_ci// Check that we will not have SEGERROR here. 160b1994897Sopenharmony_ciTEST_F(HashTest, EndOfPageStringHashTest) 161b1994897Sopenharmony_ci{ 162b1994897Sopenharmony_ci HashTest::EndOfPageStringHashTest<MurmurHash32<DEFAULT_SEED>>(); 163b1994897Sopenharmony_ci} 164b1994897Sopenharmony_ci 165b1994897Sopenharmony_ci} // namespace panda 166