Skip to content

Commit

Permalink
Fix case where WindowFilter could deadlock upon injection
Browse files Browse the repository at this point in the history
  • Loading branch information
praydog committed Sep 12, 2023
1 parent 7199a9f commit 28f6122
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 42 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -876,6 +876,7 @@ list(APPEND ue4poc_SOURCES
"src/Main.cpp"
"src/Mod.cpp"
"src/Mods.cpp"
"src/WindowFilter.cpp"
"src/hooks/D3D11Hook.cpp"
"src/hooks/D3D12Hook.cpp"
"src/hooks/WindowsMessageHook.cpp"
Expand Down Expand Up @@ -1029,6 +1030,7 @@ list(APPEND ue4poc-nolog_SOURCES
"src/Main.cpp"
"src/Mod.cpp"
"src/Mods.cpp"
"src/WindowFilter.cpp"
"src/hooks/D3D11Hook.cpp"
"src/hooks/D3D12Hook.cpp"
"src/hooks/WindowsMessageHook.cpp"
Expand Down
81 changes: 81 additions & 0 deletions src/WindowFilter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#include "WindowFilter.hpp"

// To prevent usage of statics (TLS breaks the present thread...?)
WindowFilter g_window_filter{};

WindowFilter& WindowFilter::get() {
return g_window_filter;
}

WindowFilter::WindowFilter() {
// We create a job thread because GetWindowTextA can actually deadlock inside
// the present thread...
m_job_thread = std::make_unique<std::jthread>([this](std::stop_token s){
while (!s.stop_requested()) {
std::this_thread::sleep_for(std::chrono::milliseconds{100});

if (m_window_jobs.empty()) {
return;
}

std::vector<HWND> window_jobs{};

{
std::scoped_lock _{m_mutex};
window_jobs = std::move(m_window_jobs);
}

for (const auto hwnd : window_jobs) {
if (is_filtered_nocache(hwnd)) {
filter_window(hwnd);
}
}
}
});
}

WindowFilter::~WindowFilter() {
m_job_thread->request_stop();
m_job_thread->join();
}

bool WindowFilter::is_filtered(HWND hwnd) {
if (hwnd == nullptr) {
return true;
}

std::scoped_lock _{m_mutex};

if (m_filtered_windows.find(hwnd) != m_filtered_windows.end()) {
return true;
}

// if we havent even seen this window yet, add it to the job queue
// and return true;
if (m_seen_windows.find(hwnd) == m_seen_windows.end()) {
m_seen_windows.insert(hwnd);
m_window_jobs.push_back(hwnd);
return true;
}

return false;
}

bool WindowFilter::is_filtered_nocache(HWND hwnd) {
// get window name
char window_name[256]{};
GetWindowTextA(hwnd, window_name, sizeof(window_name));

const auto sv = std::string_view{window_name};

if (sv.find("UE4SS") != std::string_view::npos) {
return true;
}

if (sv.find("PimaxXR") != std::string_view::npos) {
return true;
}

// TODO: more problematic windows
return false;
}
54 changes: 12 additions & 42 deletions src/WindowFilter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,61 +4,31 @@

#include <string_view>
#include <unordered_set>
#include <thread>
#include <vector>
#include <mutex>

class WindowFilter {
public:
static WindowFilter& get() {
static WindowFilter instance{};
return instance;
}
static WindowFilter& get();

public:
bool is_filtered(HWND hwnd) {
if (hwnd == nullptr) {
return true;
}

if (m_filtered_windows.find(hwnd) != m_filtered_windows.end()) {
return true;
}

if (m_seen_windows.find(hwnd) != m_seen_windows.end()) {
return false;
}

m_seen_windows.insert(hwnd);

if (is_filtered_nocache(hwnd)) {
filter_window(hwnd);
return true;
}
WindowFilter();
virtual ~WindowFilter();

return false;
}
bool is_filtered(HWND hwnd);

void filter_window(HWND hwnd) {
std::scoped_lock _{m_mutex};
m_filtered_windows.insert(hwnd);
}

private:
bool is_filtered_nocache(HWND hwnd) {
// get window name
char window_name[256]{};
GetWindowTextA(hwnd, window_name, sizeof(window_name));

const auto sv = std::string_view{window_name};

if (sv.find("UE4SS") != std::string_view::npos) {
return true;
}
bool is_filtered_nocache(HWND hwnd);

if (sv.find("PimaxXR") != std::string_view::npos) {
return true;
}

// TODO: more problematic windows
return false;
}
std::recursive_mutex m_mutex{};
std::vector<HWND> m_window_jobs{};
std::unique_ptr<std::jthread> m_job_thread{};

std::unordered_set<HWND> m_seen_windows{};
std::unordered_set<HWND> m_filtered_windows{};
Expand Down

0 comments on commit 28f6122

Please sign in to comment.