mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-19 03:33:56 +00:00
Add anonymous namespace
This commit is contained in:
@@ -17,377 +17,380 @@ using namespace std::literals;
|
||||
// to trick compiler optimizations
|
||||
__declspec(dllexport) bool do_the_task = true;
|
||||
|
||||
struct tls_struct
|
||||
namespace
|
||||
{
|
||||
DWORD num = 1337;
|
||||
|
||||
tls_struct()
|
||||
struct tls_struct
|
||||
{
|
||||
num = GetCurrentThreadId();
|
||||
}
|
||||
};
|
||||
DWORD num = 1337;
|
||||
|
||||
thread_local tls_struct tls_var{};
|
||||
tls_struct()
|
||||
{
|
||||
num = GetCurrentThreadId();
|
||||
}
|
||||
};
|
||||
|
||||
// getenv is broken right now :(
|
||||
std::string read_env(const char* env)
|
||||
{
|
||||
char buffer[0x1000] = {};
|
||||
if (!GetEnvironmentVariableA(env, buffer, sizeof(buffer)))
|
||||
thread_local tls_struct tls_var{};
|
||||
|
||||
// getenv is broken right now :(
|
||||
std::string read_env(const char* env)
|
||||
{
|
||||
return {};
|
||||
char buffer[0x1000] = {};
|
||||
if (!GetEnvironmentVariableA(env, buffer, sizeof(buffer)))
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
bool test_threads()
|
||||
{
|
||||
constexpr auto thread_count = 5ULL;
|
||||
|
||||
std::atomic<uint64_t> counter{0};
|
||||
|
||||
std::vector<std::thread> threads{};
|
||||
threads.reserve(thread_count);
|
||||
|
||||
for (auto i = 0ULL; i < thread_count; ++i)
|
||||
bool test_threads()
|
||||
{
|
||||
threads.emplace_back([&counter] {
|
||||
++counter;
|
||||
std::this_thread::yield();
|
||||
++counter;
|
||||
// Host scheduling/cpu performance can have impact on emulator scheduling
|
||||
// std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
++counter;
|
||||
});
|
||||
}
|
||||
constexpr auto thread_count = 5ULL;
|
||||
|
||||
for (auto& t : threads)
|
||||
{
|
||||
t.join();
|
||||
}
|
||||
std::atomic<uint64_t> counter{0};
|
||||
|
||||
return counter == (thread_count * 3ULL);
|
||||
}
|
||||
std::vector<std::thread> threads{};
|
||||
threads.reserve(thread_count);
|
||||
|
||||
bool test_tls()
|
||||
{
|
||||
std::atomic_bool kill{false};
|
||||
std::atomic_uint32_t successes{0};
|
||||
constexpr uint32_t thread_count = 2;
|
||||
|
||||
std::vector<std::thread> ts{};
|
||||
kill = false;
|
||||
|
||||
for (size_t i = 0; i < thread_count; ++i)
|
||||
{
|
||||
ts.emplace_back([&] {
|
||||
while (!kill)
|
||||
{
|
||||
for (auto i = 0ULL; i < thread_count; ++i)
|
||||
{
|
||||
threads.emplace_back([&counter] {
|
||||
++counter;
|
||||
std::this_thread::yield();
|
||||
}
|
||||
++counter;
|
||||
// Host scheduling/cpu performance can have impact on emulator scheduling
|
||||
// std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
++counter;
|
||||
});
|
||||
}
|
||||
|
||||
if (tls_var.num == GetCurrentThreadId())
|
||||
{
|
||||
++successes;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
LoadLibraryA("d3dcompiler_47.dll");
|
||||
LoadLibraryA("dsound.dll");
|
||||
LoadLibraryA("comctl32.dll");
|
||||
/*LoadLibraryA("d3d9.dll");
|
||||
LoadLibraryA("dxgi.dll");
|
||||
LoadLibraryA("wlanapi.dll");*/
|
||||
|
||||
kill = true;
|
||||
|
||||
for (auto& t : ts)
|
||||
{
|
||||
if (t.joinable())
|
||||
for (auto& t : threads)
|
||||
{
|
||||
t.join();
|
||||
}
|
||||
|
||||
return counter == (thread_count * 3ULL);
|
||||
}
|
||||
|
||||
return successes == thread_count;
|
||||
}
|
||||
|
||||
bool test_env()
|
||||
{
|
||||
const auto computername = read_env("COMPUTERNAME");
|
||||
|
||||
SetEnvironmentVariableA("BLUB", "LUL");
|
||||
|
||||
const auto blub = read_env("BLUB");
|
||||
|
||||
return !computername.empty() && blub == "LUL";
|
||||
}
|
||||
|
||||
bool test_file_path_io(const std::filesystem::path& filename)
|
||||
{
|
||||
std::error_code ec{};
|
||||
const auto absolute_file = std::filesystem::absolute(filename, ec);
|
||||
|
||||
if (ec)
|
||||
bool test_tls()
|
||||
{
|
||||
puts("Getting absolute path failed");
|
||||
return false;
|
||||
}
|
||||
std::atomic_bool kill{false};
|
||||
std::atomic_uint32_t successes{0};
|
||||
constexpr uint32_t thread_count = 2;
|
||||
|
||||
const auto canonical_file = std::filesystem::canonical(filename, ec);
|
||||
(void)canonical_file;
|
||||
std::vector<std::thread> ts{};
|
||||
kill = false;
|
||||
|
||||
if (ec)
|
||||
{
|
||||
puts("Getting canonical path failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test_io()
|
||||
{
|
||||
const std::filesystem::path filename1 = "a.txt";
|
||||
const std::filesystem::path filename2 = "A.tXt";
|
||||
|
||||
FILE* fp{};
|
||||
(void)fopen_s(&fp, filename1.string().c_str(), "wb");
|
||||
|
||||
if (!fp)
|
||||
{
|
||||
puts("Bad file");
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::string text = "Blub";
|
||||
|
||||
(void)fwrite(text.data(), 1, text.size(), fp);
|
||||
(void)fclose(fp);
|
||||
|
||||
if (!test_file_path_io(filename1))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::ifstream t(filename2);
|
||||
t.seekg(0, std::ios::end);
|
||||
const size_t size = t.tellg();
|
||||
std::string buffer(size, ' ');
|
||||
t.seekg(0);
|
||||
t.read(buffer.data(), static_cast<std::streamsize>(size));
|
||||
|
||||
return text == buffer;
|
||||
}
|
||||
|
||||
bool test_working_directory()
|
||||
{
|
||||
std::error_code ec{};
|
||||
|
||||
const auto current_dir = std::filesystem::current_path(ec);
|
||||
if (ec)
|
||||
{
|
||||
puts("Failed to get current path");
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::filesystem::path sys32 = "C:/windows/system32";
|
||||
current_path(sys32, ec);
|
||||
|
||||
if (ec)
|
||||
{
|
||||
puts("Failed to update working directory");
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto new_current_dir = std::filesystem::current_path();
|
||||
if (sys32 != new_current_dir)
|
||||
{
|
||||
puts("Updated directory is wrong!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!std::ifstream("ntdll.dll"))
|
||||
{
|
||||
puts("Working directory is not active!");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::filesystem::current_path(current_dir);
|
||||
return std::filesystem::current_path() == current_dir;
|
||||
}
|
||||
|
||||
bool test_dir_io()
|
||||
{
|
||||
size_t count = 0;
|
||||
|
||||
for (auto i : std::filesystem::directory_iterator(R"(C:\Windows\System32\)"))
|
||||
{
|
||||
++count;
|
||||
if (count > 30)
|
||||
for (size_t i = 0; i < thread_count; ++i)
|
||||
{
|
||||
return true;
|
||||
ts.emplace_back([&] {
|
||||
while (!kill)
|
||||
{
|
||||
std::this_thread::yield();
|
||||
}
|
||||
|
||||
if (tls_var.num == GetCurrentThreadId())
|
||||
{
|
||||
++successes;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
LoadLibraryA("d3dcompiler_47.dll");
|
||||
LoadLibraryA("dsound.dll");
|
||||
LoadLibraryA("comctl32.dll");
|
||||
/*LoadLibraryA("d3d9.dll");
|
||||
LoadLibraryA("dxgi.dll");
|
||||
LoadLibraryA("wlanapi.dll");*/
|
||||
|
||||
kill = true;
|
||||
|
||||
for (auto& t : ts)
|
||||
{
|
||||
if (t.joinable())
|
||||
{
|
||||
t.join();
|
||||
}
|
||||
}
|
||||
|
||||
return successes == thread_count;
|
||||
}
|
||||
|
||||
bool test_env()
|
||||
{
|
||||
const auto computername = read_env("COMPUTERNAME");
|
||||
|
||||
SetEnvironmentVariableA("BLUB", "LUL");
|
||||
|
||||
const auto blub = read_env("BLUB");
|
||||
|
||||
return !computername.empty() && blub == "LUL";
|
||||
}
|
||||
|
||||
bool test_file_path_io(const std::filesystem::path& filename)
|
||||
{
|
||||
std::error_code ec{};
|
||||
const auto absolute_file = std::filesystem::absolute(filename, ec);
|
||||
|
||||
if (ec)
|
||||
{
|
||||
puts("Getting absolute path failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto canonical_file = std::filesystem::canonical(filename, ec);
|
||||
(void)canonical_file;
|
||||
|
||||
if (ec)
|
||||
{
|
||||
puts("Getting canonical path failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test_io()
|
||||
{
|
||||
const std::filesystem::path filename1 = "a.txt";
|
||||
const std::filesystem::path filename2 = "A.tXt";
|
||||
|
||||
FILE* fp{};
|
||||
(void)fopen_s(&fp, filename1.string().c_str(), "wb");
|
||||
|
||||
if (!fp)
|
||||
{
|
||||
puts("Bad file");
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::string text = "Blub";
|
||||
|
||||
(void)fwrite(text.data(), 1, text.size(), fp);
|
||||
(void)fclose(fp);
|
||||
|
||||
if (!test_file_path_io(filename1))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::ifstream t(filename2);
|
||||
t.seekg(0, std::ios::end);
|
||||
const size_t size = t.tellg();
|
||||
std::string buffer(size, ' ');
|
||||
t.seekg(0);
|
||||
t.read(buffer.data(), static_cast<std::streamsize>(size));
|
||||
|
||||
return text == buffer;
|
||||
}
|
||||
|
||||
bool test_working_directory()
|
||||
{
|
||||
std::error_code ec{};
|
||||
|
||||
const auto current_dir = std::filesystem::current_path(ec);
|
||||
if (ec)
|
||||
{
|
||||
puts("Failed to get current path");
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::filesystem::path sys32 = "C:/windows/system32";
|
||||
current_path(sys32, ec);
|
||||
|
||||
if (ec)
|
||||
{
|
||||
puts("Failed to update working directory");
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto new_current_dir = std::filesystem::current_path();
|
||||
if (sys32 != new_current_dir)
|
||||
{
|
||||
puts("Updated directory is wrong!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!std::ifstream("ntdll.dll"))
|
||||
{
|
||||
puts("Working directory is not active!");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::filesystem::current_path(current_dir);
|
||||
return std::filesystem::current_path() == current_dir;
|
||||
}
|
||||
|
||||
bool test_dir_io()
|
||||
{
|
||||
size_t count = 0;
|
||||
|
||||
for (auto i : std::filesystem::directory_iterator(R"(C:\Windows\System32\)"))
|
||||
{
|
||||
++count;
|
||||
if (count > 30)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return count > 30;
|
||||
}
|
||||
|
||||
std::optional<std::string> read_registry_string(const HKEY root, const char* path, const char* value)
|
||||
{
|
||||
HKEY key{};
|
||||
if (RegOpenKeyExA(root, path, 0, KEY_READ, &key) != ERROR_SUCCESS)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
char data[MAX_PATH]{};
|
||||
DWORD length = sizeof(data);
|
||||
const auto res = RegQueryValueExA(key, value, nullptr, nullptr, reinterpret_cast<uint8_t*>(data), &length);
|
||||
|
||||
if (RegCloseKey(key) != ERROR_SUCCESS)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (res != ERROR_SUCCESS)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (length == 0)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
return {std::string(data, std::min(static_cast<size_t>(length - 1), sizeof(data)))};
|
||||
}
|
||||
|
||||
bool test_registry()
|
||||
{
|
||||
const auto val =
|
||||
read_registry_string(HKEY_LOCAL_MACHINE, R"(SOFTWARE\Microsoft\Windows\CurrentVersion)", "ProgramFilesDir");
|
||||
if (!val)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return *val == "C:\\Program Files";
|
||||
}
|
||||
|
||||
void throw_exception()
|
||||
{
|
||||
if (do_the_task)
|
||||
{
|
||||
throw std::runtime_error("OK");
|
||||
}
|
||||
}
|
||||
|
||||
return count > 30;
|
||||
}
|
||||
|
||||
std::optional<std::string> read_registry_string(const HKEY root, const char* path, const char* value)
|
||||
{
|
||||
HKEY key{};
|
||||
if (RegOpenKeyExA(root, path, 0, KEY_READ, &key) != ERROR_SUCCESS)
|
||||
bool test_exceptions()
|
||||
{
|
||||
return std::nullopt;
|
||||
try
|
||||
{
|
||||
throw_exception();
|
||||
return false;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
return e.what() == std::string("OK");
|
||||
}
|
||||
}
|
||||
|
||||
char data[MAX_PATH]{};
|
||||
DWORD length = sizeof(data);
|
||||
const auto res = RegQueryValueExA(key, value, nullptr, nullptr, reinterpret_cast<uint8_t*>(data), &length);
|
||||
|
||||
if (RegCloseKey(key) != ERROR_SUCCESS)
|
||||
bool test_socket()
|
||||
{
|
||||
return std::nullopt;
|
||||
network::udp_socket receiver{AF_INET};
|
||||
const network::udp_socket sender{AF_INET};
|
||||
const network::address destination{"127.0.0.1:28970", AF_INET};
|
||||
constexpr std::string_view send_data = "Hello World";
|
||||
|
||||
if (!receiver.bind(destination))
|
||||
{
|
||||
puts("Failed to bind socket!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!sender.send(destination, send_data))
|
||||
{
|
||||
puts("Failed to send data!");
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto response = receiver.receive();
|
||||
|
||||
if (!response)
|
||||
{
|
||||
puts("Failed to recieve data!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return send_data == response->second;
|
||||
}
|
||||
|
||||
if (res != ERROR_SUCCESS)
|
||||
void throw_access_violation()
|
||||
{
|
||||
return std::nullopt;
|
||||
if (do_the_task)
|
||||
{
|
||||
*reinterpret_cast<int*>(1) = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (length == 0)
|
||||
bool test_access_violation_exception()
|
||||
{
|
||||
return "";
|
||||
__try
|
||||
{
|
||||
throw_access_violation();
|
||||
return false;
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
return GetExceptionCode() == STATUS_ACCESS_VIOLATION;
|
||||
}
|
||||
}
|
||||
|
||||
return {std::string(data, std::min(static_cast<size_t>(length - 1), sizeof(data)))};
|
||||
}
|
||||
|
||||
bool test_registry()
|
||||
{
|
||||
const auto val =
|
||||
read_registry_string(HKEY_LOCAL_MACHINE, R"(SOFTWARE\Microsoft\Windows\CurrentVersion)", "ProgramFilesDir");
|
||||
if (!val)
|
||||
bool test_ud2_exception(void* address)
|
||||
{
|
||||
return false;
|
||||
__try
|
||||
{
|
||||
reinterpret_cast<void (*)()>(address)();
|
||||
return false;
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
return GetExceptionCode() == STATUS_ILLEGAL_INSTRUCTION;
|
||||
}
|
||||
}
|
||||
|
||||
return *val == "C:\\Program Files";
|
||||
}
|
||||
|
||||
void throw_exception()
|
||||
{
|
||||
if (do_the_task)
|
||||
bool test_illegal_instruction_exception()
|
||||
{
|
||||
throw std::runtime_error("OK");
|
||||
}
|
||||
}
|
||||
const auto address = VirtualAlloc(nullptr, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
if (!address)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool test_exceptions()
|
||||
{
|
||||
try
|
||||
{
|
||||
throw_exception();
|
||||
return false;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
return e.what() == std::string("OK");
|
||||
}
|
||||
}
|
||||
memcpy(address, "\x0F\x0B", 2); // ud2
|
||||
|
||||
bool test_socket()
|
||||
{
|
||||
network::udp_socket receiver{AF_INET};
|
||||
const network::udp_socket sender{AF_INET};
|
||||
const network::address destination{"127.0.0.1:28970", AF_INET};
|
||||
constexpr std::string_view send_data = "Hello World";
|
||||
const auto res = test_ud2_exception(address);
|
||||
|
||||
if (!receiver.bind(destination))
|
||||
{
|
||||
puts("Failed to bind socket!");
|
||||
return false;
|
||||
VirtualFree(address, 0x1000, MEM_RELEASE);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
if (!sender.send(destination, send_data))
|
||||
bool test_native_exceptions()
|
||||
{
|
||||
puts("Failed to send data!");
|
||||
return false;
|
||||
return test_access_violation_exception() && test_illegal_instruction_exception();
|
||||
}
|
||||
|
||||
const auto response = receiver.receive();
|
||||
|
||||
if (!response)
|
||||
void print_time()
|
||||
{
|
||||
puts("Failed to recieve data!");
|
||||
return false;
|
||||
const auto epoch_time = std::chrono::system_clock::now().time_since_epoch();
|
||||
printf("Time: %lld\n", std::chrono::duration_cast<std::chrono::nanoseconds>(epoch_time).count());
|
||||
}
|
||||
|
||||
return send_data == response->second;
|
||||
}
|
||||
|
||||
void throw_access_violation()
|
||||
{
|
||||
if (do_the_task)
|
||||
{
|
||||
*reinterpret_cast<int*>(1) = 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool test_access_violation_exception()
|
||||
{
|
||||
__try
|
||||
{
|
||||
throw_access_violation();
|
||||
return false;
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
return GetExceptionCode() == STATUS_ACCESS_VIOLATION;
|
||||
}
|
||||
}
|
||||
|
||||
bool test_ud2_exception(void* address)
|
||||
{
|
||||
__try
|
||||
{
|
||||
reinterpret_cast<void (*)()>(address)();
|
||||
return false;
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
return GetExceptionCode() == STATUS_ILLEGAL_INSTRUCTION;
|
||||
}
|
||||
}
|
||||
|
||||
bool test_illegal_instruction_exception()
|
||||
{
|
||||
const auto address = VirtualAlloc(nullptr, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
if (!address)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(address, "\x0F\x0B", 2); // ud2
|
||||
|
||||
const auto res = test_ud2_exception(address);
|
||||
|
||||
VirtualFree(address, 0x1000, MEM_RELEASE);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool test_native_exceptions()
|
||||
{
|
||||
return test_access_violation_exception() && test_illegal_instruction_exception();
|
||||
}
|
||||
|
||||
void print_time()
|
||||
{
|
||||
const auto epoch_time = std::chrono::system_clock::now().time_since_epoch();
|
||||
printf("Time: %lld\n", std::chrono::duration_cast<std::chrono::nanoseconds>(epoch_time).count());
|
||||
}
|
||||
|
||||
#define RUN_TEST(func, name) \
|
||||
|
||||
Reference in New Issue
Block a user