fix: replace remaining QList::append({}) in plugins and tests

Missed plugin and test directories in the previous Qt 6.8 compat fix.
This commit is contained in:
IChooseYou
2026-03-14 12:11:08 -06:00
committed by IChooseYou
parent 1501a1542c
commit 6a30e0a402
12 changed files with 1140 additions and 46 deletions

View File

@@ -222,7 +222,7 @@ QVector<rcx::Provider::ThreadInfo> KernelProcessProvider::tebs() const
auto* entries = reinterpret_cast<const RcxDrvTebEntry*>(outBuf.constData()); auto* entries = reinterpret_cast<const RcxDrvTebEntry*>(outBuf.constData());
for (int i = 0; i < count; ++i) for (int i = 0; i < count; ++i)
result.append({entries[i].tebAddress, entries[i].threadId}); result.push_back(ThreadInfo{entries[i].tebAddress, entries[i].threadId});
#endif #endif
return result; return result;
} }
@@ -253,7 +253,7 @@ void KernelProcessProvider::cacheModules()
if (i == 0) if (i == 0)
m_base = entries[i].base; m_base = entries[i].base;
m_modules.append({modName, entries[i].base, entries[i].size}); m_modules.push_back(ModuleInfo{modName, entries[i].base, entries[i].size});
} }
#endif #endif
} }

View File

@@ -190,7 +190,7 @@ void ProcessMemoryProvider::cacheModules()
if (GetModuleFileNameExW(m_handle, mods[i], modPath, MAX_PATH)) if (GetModuleFileNameExW(m_handle, mods[i], modPath, MAX_PATH))
fullPath = QString::fromWCharArray(modPath); fullPath = QString::fromWCharArray(modPath);
m_modules.append({ m_modules.push_back(ModuleInfo{
QString::fromWCharArray(modName), QString::fromWCharArray(modName),
fullPath, fullPath,
(uint64_t)mi.lpBaseOfDll, (uint64_t)mi.lpBaseOfDll,
@@ -205,7 +205,7 @@ QVector<rcx::Provider::ModuleEntry> ProcessMemoryProvider::enumerateModules() co
QVector<ModuleEntry> result; QVector<ModuleEntry> result;
result.reserve(m_modules.size()); result.reserve(m_modules.size());
for (const auto& m : m_modules) for (const auto& m : m_modules)
result.append({m.name, m.fullPath, m.base, m.size}); result.push_back(ModuleEntry{m.name, m.fullPath, m.base, m.size});
return result; return result;
} }
@@ -415,8 +415,9 @@ void ProcessMemoryProvider::cacheModules()
for (auto it = moduleRanges.begin(); it != moduleRanges.end(); ++it) for (auto it = moduleRanges.begin(); it != moduleRanges.end(); ++it)
{ {
QFileInfo fi(it.key()); QFileInfo fi(it.key());
m_modules.append({ m_modules.push_back(ModuleInfo{
fi.fileName(), fi.fileName(),
it.key(),
it->base, it->base,
it->end - it->base it->end - it->base
}); });
@@ -545,7 +546,7 @@ QVector<rcx::Provider::ThreadInfo> ProcessMemoryProvider::tebs() const
ULONG tbiLen = 0; ULONG tbiLen = 0;
NTSTATUS qitSt = pNtQIT(hThread, 0, &tbi, sizeof(tbi), &tbiLen); NTSTATUS qitSt = pNtQIT(hThread, 0, &tbi, sizeof(tbi), &tbiLen);
if (qitSt >= 0 && tbi.TebBaseAddress) if (qitSt >= 0 && tbi.TebBaseAddress)
result.append({(uint64_t)(uintptr_t)tbi.TebBaseAddress, tid}); result.push_back(ThreadInfo{(uint64_t)(uintptr_t)tbi.TebBaseAddress, tid});
CloseHandle(hThread); CloseHandle(hThread);
} }
break; break;

View File

@@ -244,7 +244,7 @@ struct IpcClient {
reinterpret_cast<const char*>(data + entry->nameOffset), reinterpret_cast<const char*>(data + entry->nameOffset),
(int)entry->nameLength); (int)entry->nameLength);
#endif #endif
result.append({modName, entry->base, entry->size}); result.push_back(RemoteProcessProvider::ModuleInfo{modName, entry->base, entry->size});
} }
return result; return result;
} }

View File

@@ -202,7 +202,7 @@ void BenchProject::benchBuildWorkspaceModel()
// Build TabInfo array // Build TabInfo array
QVector<TabInfo> tabs; QVector<TabInfo> tabs;
for (const auto& t : trees) for (const auto& t : trees)
tabs.append({ &t, QStringLiteral("test"), nullptr }); tabs.push_back(TabInfo{ &t, QStringLiteral("test"), nullptr });
QStandardItemModel model; QStandardItemModel model;
const int ITERS = 20; const int ITERS = 20;
@@ -244,7 +244,7 @@ void BenchProject::benchWorkspaceSearch()
QVector<TabInfo> tabs; QVector<TabInfo> tabs;
for (const auto& t : trees) for (const auto& t : trees)
tabs.append({ &t, QStringLiteral("test"), nullptr }); tabs.push_back(TabInfo{ &t, QStringLiteral("test"), nullptr });
QStandardItemModel model; QStandardItemModel model;
buildProjectExplorer(&model, tabs); buildProjectExplorer(&model, tabs);

222
tests/grab_tabs.cpp Normal file
View File

@@ -0,0 +1,222 @@
#include <QtTest/QTest>
#include <QApplication>
#include <QMainWindow>
#include <QDockWidget>
#include <QTabBar>
#include <QTextEdit>
#include <QPixmap>
#include <QToolButton>
#include <QHBoxLayout>
#include <QProxyStyle>
#include <QStyleOptionTab>
#include <QSettings>
#include <QPainter>
#include "../src/themes/thememanager.h"
// Minimal replica of the real app's MenuBarStyle for dock tab painting
class TestTabStyle : public QProxyStyle {
public:
using QProxyStyle::QProxyStyle;
QSize sizeFromContents(ContentsType type, const QStyleOption* opt,
const QSize& sz, const QWidget* w) const override {
QSize s = QProxyStyle::sizeFromContents(type, opt, sz, w);
if (type == CT_TabBarTab) {
if (auto* tabBar = qobject_cast<const QTabBar*>(w)) {
if (tabBar->parent() && qobject_cast<const QMainWindow*>(tabBar->parent()))
s.setHeight(28);
}
}
return s;
}
void drawControl(ControlElement element, const QStyleOption* opt,
QPainter* p, const QWidget* w) const override {
// Tab shape — background, accent line, borders
if (element == CE_TabBarTabShape) {
if (auto* tab = qstyleoption_cast<const QStyleOptionTab*>(opt)) {
auto* tabBar = qobject_cast<const QTabBar*>(w);
if (tabBar && tabBar->parent() && qobject_cast<QMainWindow*>(tabBar->parent())) {
bool selected = tab->state & State_Selected;
bool hovered = tab->state & State_MouseOver;
QColor bg = tab->palette.color(QPalette::Window);
if (hovered && !selected)
bg = tab->palette.color(QPalette::Mid);
p->fillRect(tab->rect, bg);
if (selected)
p->fillRect(QRect(tab->rect.left(), tab->rect.top(),
tab->rect.width(), 2),
tab->palette.color(QPalette::Link));
p->setPen(tab->palette.color(QPalette::Dark));
p->drawLine(tab->rect.bottomLeft(), tab->rect.bottomRight());
return;
}
}
}
// Tab label — middle-elide long names, editor font
if (element == CE_TabBarTabLabel) {
if (auto* tab = qstyleoption_cast<const QStyleOptionTab*>(opt)) {
auto* tabBar = qobject_cast<const QTabBar*>(w);
if (tabBar && tabBar->parent() && qobject_cast<QMainWindow*>(tabBar->parent())) {
int tabIdx = -1;
for (int i = 0; i < tabBar->count(); ++i) {
if (tabBar->tabRect(i).contains(tab->rect.center())) { tabIdx = i; break; }
}
int btnWidth = 0;
if (tabIdx >= 0) {
auto* btn = tabBar->tabButton(tabIdx, QTabBar::RightSide);
if (btn) btnWidth = btn->sizeHint().width() + 4;
}
QRect textRect = tab->rect.adjusted(8, 0, -(8 + btnWidth), 0);
QFont f("JetBrains Mono", 10);
f.setFixedPitch(true);
p->setFont(f);
QFontMetrics fm(f);
QString text = (tabIdx >= 0) ? tabBar->tabText(tabIdx) : tab->text;
int maxW = textRect.width();
if (fm.horizontalAdvance(text) > maxW) {
int ellW = fm.horizontalAdvance(QStringLiteral("\u2026"));
int avail = maxW - ellW;
if (avail > 0) {
int half = avail / 2;
QString left, right;
for (int i = 0; i < text.size(); ++i)
if (fm.horizontalAdvance(text.left(i+1)) > half) { left = text.left(i); break; }
if (left.isEmpty()) left = text.left(1);
for (int i = text.size()-1; i >= 0; --i)
if (fm.horizontalAdvance(text.mid(i)) > half) { right = text.mid(i+1); break; }
if (right.isEmpty()) right = text.right(1);
text = left + QStringLiteral("\u2026") + right;
} else {
text = QStringLiteral("\u2026");
}
}
bool selected = tab->state & QStyle::State_Selected;
p->setPen(selected ? tab->palette.color(QPalette::Text)
: tab->palette.color(QPalette::WindowText));
p->drawText(textRect, Qt::AlignVCenter | Qt::AlignLeft, text);
return;
}
}
}
QProxyStyle::drawControl(element, opt, p, w);
}
};
class TabBtns : public QWidget {
public:
explicit TabBtns(const QColor& hover, QWidget* parent = nullptr) : QWidget(parent) {
auto* hl = new QHBoxLayout(this);
hl->setContentsMargins(2, 0, 0, 0);
hl->setSpacing(0);
QString style = QStringLiteral(
"QToolButton { border: none; padding: 1px; border-radius: 0px; }"
"QToolButton:hover { background: %1; }").arg(hover.name());
auto* pin = new QToolButton(this);
pin->setFixedSize(16, 16);
pin->setAutoRaise(true);
pin->setIcon(QIcon(":/vsicons/pin.svg"));
pin->setIconSize(QSize(12, 12));
pin->setStyleSheet(style);
hl->addWidget(pin);
auto* close = new QToolButton(this);
close->setFixedSize(16, 16);
close->setAutoRaise(true);
close->setIcon(QIcon(":/vsicons/close.svg"));
close->setIconSize(QSize(12, 12));
close->setStyleSheet(style);
hl->addWidget(close);
}
};
class GrabTabs : public QObject {
Q_OBJECT
private slots:
void grab() {
const auto& t = rcx::ThemeManager::instance().current();
// Install custom style (no stylesheet — all painting via style)
QApplication::setStyle(new TestTabStyle("Fusion"));
// Apply dark palette globally
QPalette pal;
pal.setColor(QPalette::Window, t.background);
pal.setColor(QPalette::WindowText, t.textDim);
pal.setColor(QPalette::Base, t.background);
pal.setColor(QPalette::Text, t.text);
pal.setColor(QPalette::Mid, t.hover);
pal.setColor(QPalette::Dark, t.border);
pal.setColor(QPalette::Link, t.indHoverSpan);
QApplication::setPalette(pal);
auto* win = new QMainWindow;
win->resize(700, 500);
win->setDockNestingEnabled(true);
win->setTabPosition(Qt::TopDockWidgetArea, QTabWidget::North);
auto* central = new QWidget(win);
central->setMaximumSize(0, 0);
central->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
win->setCentralWidget(central);
win->setStyleSheet(QStringLiteral(
"QMainWindow::separator { width: 0px; height: 0px; background: transparent; }"));
QStringList names = {
"shader_color_helper.hpp",
"shader_crypt.cpp",
"EPROCESS (class)",
"very_long_struct_name_that_should_elide.h"
};
QVector<QDockWidget*> docks;
for (const auto& name : names) {
auto* dock = new QDockWidget(name, win);
dock->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable);
auto* emptyTitle = new QWidget(dock);
emptyTitle->setFixedHeight(0);
dock->setTitleBarWidget(emptyTitle);
dock->setWidget(new QTextEdit(dock));
if (!docks.isEmpty())
win->tabifyDockWidget(docks.last(), dock);
else
win->addDockWidget(Qt::TopDockWidgetArea, dock);
docks.append(dock);
}
// Select first tab
docks.first()->raise();
win->show();
QVERIFY(QTest::qWaitForWindowExposed(win));
QApplication::processEvents();
// No stylesheet on dock tab bars — painting handled by TestTabStyle
for (auto* tabBar : win->findChildren<QTabBar*>()) {
if (tabBar->parent() != win) continue;
tabBar->setStyleSheet(QString());
tabBar->setElideMode(Qt::ElideNone);
tabBar->setExpanding(false);
QPalette tp = tabBar->palette();
tp.setColor(QPalette::WindowText, t.textDim);
tp.setColor(QPalette::Text, t.text);
tp.setColor(QPalette::Window, t.background);
tp.setColor(QPalette::Mid, t.hover);
tp.setColor(QPalette::Dark, t.border);
tp.setColor(QPalette::Link, t.indHoverSpan);
tabBar->setPalette(tp);
for (int i = 0; i < tabBar->count(); ++i)
tabBar->setTabButton(i, QTabBar::RightSide, new TabBtns(t.hover, tabBar));
}
QApplication::processEvents();
QApplication::processEvents();
QPixmap shot = win->grab(QRect(0, 0, win->width(), 50));
shot.save(QStringLiteral("tab_screenshot.png"));
qDebug() << "Saved" << shot.size();
delete win;
}
};
QTEST_MAIN(GrabTabs)
#include "grab_tabs.moc"

View File

@@ -382,6 +382,30 @@ private slots:
QCOMPARE(r.value, 0x140000000ULL); QCOMPARE(r.value, 0x140000000ULL);
} }
// -- Bare module.dll identifier --
void bareModuleDll() {
AddressParserCallbacks cbs;
cbs.resolveIdentifier = [](const QString& name, bool* ok) -> uint64_t {
*ok = (name == "client.dll");
return *ok ? 0x7FF600000000ULL : 0;
};
auto r = AddressParser::evaluate("client.dll + 0xFF", 8, &cbs);
QVERIFY(r.ok);
QCOMPARE(r.value, 0x7FF6000000FFULL);
}
void bareModuleExe() {
AddressParserCallbacks cbs;
cbs.resolveIdentifier = [](const QString& name, bool* ok) -> uint64_t {
*ok = (name == "cs2.exe");
return *ok ? 0x140000000ULL : 0;
};
auto r = AddressParser::evaluate("cs2.exe + 0xDE", 8, &cbs);
QVERIFY(r.ok);
QCOMPARE(r.value, 0x1400000DEULL);
}
// -- Validate with new syntax -- // -- Validate with new syntax --
void validateIdentifier() { void validateIdentifier() {

View File

@@ -230,7 +230,7 @@ private slots:
// Only include the pointer-expanded ones (near vtable at 0x100) // Only include the pointer-expanded ones (near vtable at 0x100)
if (lm.offsetAddr >= 0x100 && lm.offsetAddr < 0x200) { if (lm.offsetAddr >= 0x100 && lm.offsetAddr < 0x200) {
int nodeIdx = lm.nodeIdx; int nodeIdx = lm.nodeIdx;
funcPtrs.append({i, lm.offsetAddr, lm.nodeKind, funcPtrs.push_back(FuncInfo{i, lm.offsetAddr, lm.nodeKind,
nodeIdx >= 0 ? tree.nodes[nodeIdx].name : QString()}); nodeIdx >= 0 ? tree.nodes[nodeIdx].name : QString()});
} }
} }

View File

@@ -0,0 +1,397 @@
#include <QTest>
#include <QSignalSpy>
#include <QByteArray>
#include <cstring>
#include "providers/provider.h"
#include "scanner.h"
#include "../plugins/KernelMemory/KernelMemoryPlugin.h"
#ifdef _WIN32
#include <windows.h>
#include <tlhelp32.h>
#endif
using namespace rcx;
class TestKernelProvider : public QObject {
Q_OBJECT
private:
bool m_driverAvailable = false;
KernelMemoryPlugin* m_plugin = nullptr;
std::unique_ptr<Provider> m_provider;
uint32_t m_selfPid = 0;
private slots:
// ── Setup: try to load driver, skip tests if unavailable ──
void initTestCase()
{
m_plugin = new KernelMemoryPlugin();
#ifdef _WIN32
m_selfPid = GetCurrentProcessId();
// Try to open driver directly to see if it's available
HANDLE h = CreateFileA(RCX_DRV_USERMODE_PATH,
GENERIC_READ | GENERIC_WRITE,
0, nullptr, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, nullptr);
if (h != INVALID_HANDLE_VALUE) {
CloseHandle(h);
m_driverAvailable = true;
} else {
// Try loading via plugin
QString errorMsg;
QString target = QStringLiteral("km:%1:self").arg(m_selfPid);
m_provider = m_plugin->createProvider(target, &errorMsg);
if (m_provider && m_provider->isValid()) {
m_driverAvailable = true;
} else {
qWarning("Kernel driver not available: %s", qPrintable(errorMsg));
qWarning("Tests requiring the driver will be skipped.");
}
}
if (m_driverAvailable && !m_provider) {
QString target = QStringLiteral("km:%1:self").arg(m_selfPid);
m_provider = m_plugin->createProvider(target, nullptr);
}
#endif
}
void cleanupTestCase()
{
m_provider.reset();
delete m_plugin;
m_plugin = nullptr;
}
// ── 1. Plugin metadata (no driver needed) ──
void plugin_name()
{
QCOMPARE(QString::fromStdString(m_plugin->Name()), QStringLiteral("Kernel Memory"));
}
void plugin_loadType()
{
QCOMPARE(m_plugin->LoadType(), IPlugin::k_ELoadTypeManual);
}
void plugin_canHandle()
{
QVERIFY(m_plugin->canHandle(QStringLiteral("km:1234:test.exe")));
QVERIFY(m_plugin->canHandle(QStringLiteral("phys:0")));
QVERIFY(m_plugin->canHandle(QStringLiteral("msr:")));
QVERIFY(!m_plugin->canHandle(QStringLiteral("1234:test.exe")));
QVERIFY(!m_plugin->canHandle(QStringLiteral("file:test.bin")));
}
void provider_noDriver_invalid()
{
// Creating provider with invalid target should fail gracefully
QString err;
auto prov = m_plugin->createProvider(QStringLiteral("km:0:invalid"), &err);
// Either nullptr or invalid -- both are acceptable
if (prov) QVERIFY(!prov->isValid() || prov->size() == 0);
}
// ── 2. KUSER_SHARED_DATA validation (at 0x7FFE0000) ──
void kusd_ntMajorVersion()
{
if (!m_driverAvailable) QSKIP("Driver not loaded");
QVERIFY(m_provider);
// KUSER_SHARED_DATA.NtMajorVersion at offset 0x26C
uint32_t major = m_provider->readU32(0x7FFE0000 + 0x26C);
QCOMPARE(major, (uint32_t)10); // Windows 10/11
}
void kusd_ntMinorVersion()
{
if (!m_driverAvailable) QSKIP("Driver not loaded");
uint32_t minor = m_provider->readU32(0x7FFE0000 + 0x270);
QCOMPARE(minor, (uint32_t)0); // Windows 10+ has minor = 0
}
void kusd_ntBuildNumber()
{
if (!m_driverAvailable) QSKIP("Driver not loaded");
#ifdef _WIN32
// Cross-validate with RtlGetVersion
typedef NTSTATUS(NTAPI* RtlGetVersion_t)(PRTL_OSVERSIONINFOW);
auto pRtlGetVersion = (RtlGetVersion_t)GetProcAddress(
GetModuleHandleA("ntdll.dll"), "RtlGetVersion");
QVERIFY(pRtlGetVersion);
RTL_OSVERSIONINFOW osvi{};
osvi.dwOSVersionInfoSize = sizeof(osvi);
QCOMPARE(pRtlGetVersion(&osvi), (NTSTATUS)0);
uint32_t buildFromDriver = m_provider->readU32(0x7FFE0000 + 0x260);
QCOMPARE(buildFromDriver, (uint32_t)osvi.dwBuildNumber);
#endif
}
void kusd_systemTime_nonZero()
{
if (!m_driverAvailable) QSKIP("Driver not loaded");
uint64_t sysTime = m_provider->readU64(0x7FFE0000 + 0x14);
QVERIFY(sysTime != 0);
}
void kusd_tickCount_increasing()
{
if (!m_driverAvailable) QSKIP("Driver not loaded");
// TickCountMultiplier at 0x4, TickCount at 0x320
uint64_t tick1 = m_provider->readU64(0x7FFE0000 + 0x320);
QTest::qWait(120);
uint64_t tick2 = m_provider->readU64(0x7FFE0000 + 0x320);
QVERIFY2(tick2 > tick1,
qPrintable(QStringLiteral("tick1=%1 tick2=%2").arg(tick1).arg(tick2)));
}
void kusd_crossValidate_readProcessMemory()
{
if (!m_driverAvailable) QSKIP("Driver not loaded");
#ifdef _WIN32
// Read same KUSD page through driver and ReadProcessMemory
QByteArray driverBuf(256, 0);
m_provider->read(0x7FFE0000, driverBuf.data(), 256);
QByteArray rpmBuf(256, 0);
SIZE_T bytesRead = 0;
HANDLE self = GetCurrentProcess();
ReadProcessMemory(self, (LPCVOID)0x7FFE0000, rpmBuf.data(), 256, &bytesRead);
// NtMajorVersion (offset 0x26C relative = not in first 256 bytes, so compare what we have)
// Compare first 256 bytes -- should be identical
QCOMPARE(driverBuf, rpmBuf);
#endif
}
// ── 3. Self-read integration ──
void selfRead_mzHeader()
{
if (!m_driverAvailable) QSKIP("Driver not loaded");
#ifdef _WIN32
uint64_t selfBase = (uint64_t)GetModuleHandleA(nullptr);
QVERIFY(selfBase != 0);
uint8_t mz[2] = {};
m_provider->read(selfBase, mz, 2);
QCOMPARE(mz[0], (uint8_t)'M');
QCOMPARE(mz[1], (uint8_t)'Z');
#endif
}
void selfRead_peSignature()
{
if (!m_driverAvailable) QSKIP("Driver not loaded");
#ifdef _WIN32
uint64_t selfBase = (uint64_t)GetModuleHandleA(nullptr);
// PE offset at +0x3C
uint32_t peOffset = m_provider->readU32(selfBase + 0x3C);
QVERIFY(peOffset > 0 && peOffset < 0x1000);
// PE signature = "PE\0\0" = 0x00004550
uint32_t peSig = m_provider->readU32(selfBase + peOffset);
QCOMPARE(peSig, (uint32_t)0x00004550);
#endif
}
// ── 4. Scanner integration ──
void scanner_mzSigScan()
{
if (!m_driverAvailable) QSKIP("Driver not loaded");
#ifdef _WIN32
auto shared = std::shared_ptr<Provider>(m_provider.get(), [](Provider*){});
ScanRequest req;
req.pattern = QByteArray("\x4D\x5A", 2);
req.mask = QByteArray("\xFF\xFF", 2);
req.alignment = 1;
req.maxResults = 10;
// Constrain to our own module for speed
uint64_t selfBase = (uint64_t)GetModuleHandleA(nullptr);
req.startAddress = selfBase;
req.endAddress = selfBase + 0x1000;
ScanEngine engine;
QSignalSpy spy(&engine, &ScanEngine::finished);
engine.start(shared, req);
QVERIFY(spy.wait(5000));
auto results = spy.at(0).at(0).value<QVector<ScanResult>>();
QVERIFY(results.size() >= 1);
QCOMPARE(results[0].address, selfBase);
#endif
}
// ── 5. Region enumeration ──
void regions_selfProcess()
{
if (!m_driverAvailable) QSKIP("Driver not loaded");
auto regions = m_provider->enumerateRegions();
QVERIFY(regions.size() > 0);
// Should have at least one executable region (our code)
bool hasExec = false;
for (const auto& r : regions) {
if (r.executable) { hasExec = true; break; }
}
QVERIFY(hasExec);
}
// ── 6. PEB / modules ──
void peb_nonZero()
{
if (!m_driverAvailable) QSKIP("Driver not loaded");
QVERIFY(m_provider->peb() != 0);
}
void symbol_selfModule()
{
if (!m_driverAvailable) QSKIP("Driver not loaded");
#ifdef _WIN32
uint64_t selfBase = (uint64_t)GetModuleHandleA(nullptr);
QString sym = m_provider->getSymbol(selfBase + 0x100);
QVERIFY(!sym.isEmpty());
QVERIFY(sym.contains(QStringLiteral("+0x")));
#endif
}
// ── 7. CR3 / address translation ──
void cr3_nonZero()
{
if (!m_driverAvailable) QSKIP("Driver not loaded");
auto* kprov = dynamic_cast<KernelProcessProvider*>(m_provider.get());
QVERIFY(kprov);
uint64_t cr3 = kprov->getCr3();
QVERIFY2(cr3 != 0, "CR3 should be non-zero for a running process");
// CR3 should be page-aligned (low 12 bits cleared)
QCOMPARE(cr3 & 0xFFF, (uint64_t)0);
}
void vtop_kusd()
{
if (!m_driverAvailable) QSKIP("Driver not loaded");
auto* kprov = dynamic_cast<KernelProcessProvider*>(m_provider.get());
QVERIFY(kprov);
// KUSER_SHARED_DATA is at VA 0x7FFE0000 in every process
auto result = kprov->translateAddress(0x7FFE0000);
QVERIFY2(result.valid, "KUSER_SHARED_DATA should be mapped");
QVERIFY(result.physical != 0);
// PML4E and PDPTE should be present
QVERIFY(result.pml4e & 1); // Present bit
QVERIFY(result.pdpte & 1); // Present bit
}
void vtop_selfModule()
{
if (!m_driverAvailable) QSKIP("Driver not loaded");
#ifdef _WIN32
auto* kprov = dynamic_cast<KernelProcessProvider*>(m_provider.get());
QVERIFY(kprov);
uint64_t selfBase = (uint64_t)GetModuleHandleA(nullptr);
auto result = kprov->translateAddress(selfBase);
QVERIFY2(result.valid, "Own module base should be mapped");
QVERIFY(result.physical != 0);
// Cross-validate: read MZ header via physical address
// Read the first 2 bytes at the physical address using physical provider
auto physEntries = kprov->readPageTable(kprov->getCr3(), 0, 16);
QVERIFY(physEntries.size() > 0); // Should get at least some PML4 entries
#endif
}
void vtop_unmapped()
{
if (!m_driverAvailable) QSKIP("Driver not loaded");
auto* kprov = dynamic_cast<KernelProcessProvider*>(m_provider.get());
QVERIFY(kprov);
// Address 0 should not be mapped in user mode
auto result = kprov->translateAddress(0);
QVERIFY2(!result.valid, "Address 0 should not be mapped");
}
void readPageTable_cr3()
{
if (!m_driverAvailable) QSKIP("Driver not loaded");
auto* kprov = dynamic_cast<KernelProcessProvider*>(m_provider.get());
QVERIFY(kprov);
uint64_t cr3 = kprov->getCr3();
QVERIFY(cr3 != 0);
// Read the full PML4 table (512 entries)
auto entries = kprov->readPageTable(cr3, 0, 512);
QCOMPARE(entries.size(), 512);
// At least some entries should be present (kernel maps upper half)
int presentCount = 0;
for (const auto& e : entries) {
if (e & 1) presentCount++;
}
QVERIFY2(presentCount > 0,
qPrintable(QStringLiteral("Expected present PML4 entries, got 0")));
}
// ── 8. Ping ──
void ping_version()
{
if (!m_driverAvailable) QSKIP("Driver not loaded");
#ifdef _WIN32
HANDLE h = CreateFileA(RCX_DRV_USERMODE_PATH,
GENERIC_READ | GENERIC_WRITE,
0, nullptr, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, nullptr);
if (h == INVALID_HANDLE_VALUE) QSKIP("Cannot open driver handle");
RcxDrvPingResponse ping{};
DWORD br = 0;
BOOL ok = DeviceIoControl(h, IOCTL_RCX_PING, nullptr, 0,
&ping, sizeof(ping), &br, nullptr);
CloseHandle(h);
QVERIFY(ok);
QCOMPARE(ping.version, (uint32_t)RCX_DRV_VERSION);
#endif
}
};
QTEST_MAIN(TestKernelProvider)
#include "test_kernel_provider.moc"

View File

@@ -26,7 +26,7 @@ public:
if (!m_server->listen(name)) return false; if (!m_server->listen(name)) return false;
connect(m_server, &QLocalServer::newConnection, this, [this]() { connect(m_server, &QLocalServer::newConnection, this, [this]() {
while (auto* s = m_server->nextPendingConnection()) { while (auto* s = m_server->nextPendingConnection()) {
m_clients.append({s, {}, false}); m_clients.push_back(Client{s, {}, false});
connect(s, &QLocalSocket::readyRead, this, [this, s]() { processSocket(s); }); connect(s, &QLocalSocket::readyRead, this, [this, s]() { processSocket(s); });
connect(s, &QLocalSocket::disconnected, this, [this, s]() { connect(s, &QLocalSocket::disconnected, this, [this, s]() {
for (int i = 0; i < m_clients.size(); i++) for (int i = 0; i < m_clients.size(); i++)

143
tests/test_project_dock.cpp Normal file
View File

@@ -0,0 +1,143 @@
#include <QtTest/QTest>
#include <QApplication>
#include <QMainWindow>
#include <QDockWidget>
#include <QTabWidget>
#include <QTextEdit>
// Replicates the real app layout: QTabWidget central widget, project dock in LeftDockWidgetArea.
class TestProjectDock : public QObject {
Q_OBJECT
private:
struct AppLayout {
QMainWindow* win;
QTabWidget* tabs;
QDockWidget* project;
};
AppLayout buildApp() {
auto* win = new QMainWindow;
win->resize(1280, 800);
// QTabWidget as central widget — same as real app
auto* tabs = new QTabWidget(win);
tabs->setTabsClosable(true);
tabs->setMovable(true);
tabs->setDocumentMode(true);
tabs->addTab(new QTextEdit(tabs), "Untitled");
win->setCentralWidget(tabs);
// Project dock — same as real app
auto* project = new QDockWidget("Project", win);
project->setObjectName("WorkspaceDock");
project->setAllowedAreas(Qt::AllDockWidgetAreas);
project->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable);
project->setWidget(new QTextEdit(project));
win->addDockWidget(Qt::LeftDockWidgetArea, project);
project->hide();
return {win, tabs, project};
}
void showProject(AppLayout& a) {
if (a.project->isHidden() && !a.project->isFloating()) {
a.win->addDockWidget(Qt::LeftDockWidgetArea, a.project);
a.project->show();
a.win->resizeDocks({a.project}, {qMax(200, a.win->width() / 5)}, Qt::Horizontal);
} else {
a.project->show();
}
}
private slots:
void dockStartsLeft();
void dockWidthIsReasonable();
void dockStaysLeftAfterHideShow();
void dockRespectsDragAfterShow();
};
void TestProjectDock::dockStartsLeft()
{
auto app = buildApp();
app.win->show();
QTest::qWaitForWindowExposed(app.win);
showProject(app);
QApplication::processEvents();
// Project should be to the left of the central tab widget
QVERIFY2(app.project->x() < app.tabs->x(),
qPrintable(QString("Project x=%1, Tabs x=%2")
.arg(app.project->x()).arg(app.tabs->x())));
delete app.win;
}
void TestProjectDock::dockWidthIsReasonable()
{
auto app = buildApp();
app.win->show();
QTest::qWaitForWindowExposed(app.win);
showProject(app);
QApplication::processEvents();
int dockWidth = app.project->width();
int winWidth = app.win->width();
double ratio = (double)dockWidth / winWidth;
qDebug() << "Dock width:" << dockWidth << "Window width:" << winWidth
<< "Ratio:" << QString::number(ratio * 100, 'f', 1) + "%";
QVERIFY2(ratio < 0.40,
qPrintable(QString("Dock too wide: %1% of window").arg(ratio * 100, 0, 'f', 1)));
QVERIFY2(ratio > 0.10,
qPrintable(QString("Dock too narrow: %1% of window").arg(ratio * 100, 0, 'f', 1)));
delete app.win;
}
void TestProjectDock::dockStaysLeftAfterHideShow()
{
auto app = buildApp();
app.win->show();
QTest::qWaitForWindowExposed(app.win);
showProject(app);
QApplication::processEvents();
QVERIFY(app.project->x() < app.tabs->x());
app.project->hide();
QApplication::processEvents();
showProject(app);
QApplication::processEvents();
QVERIFY2(app.project->x() < app.tabs->x(),
qPrintable(QString("After re-show: Project x=%1, Tabs x=%2")
.arg(app.project->x()).arg(app.tabs->x())));
delete app.win;
}
void TestProjectDock::dockRespectsDragAfterShow()
{
auto app = buildApp();
app.win->show();
QTest::qWaitForWindowExposed(app.win);
showProject(app);
QApplication::processEvents();
QVERIFY(app.project->x() < app.tabs->x());
// Simulate user dragging to right
app.win->addDockWidget(Qt::RightDockWidgetArea, app.project);
QApplication::processEvents();
QCOMPARE(app.win->dockWidgetArea(app.project), Qt::RightDockWidgetArea);
// Dock is visible — showProject should NOT force it back to left
showProject(app);
QApplication::processEvents();
QCOMPARE(app.win->dockWidgetArea(app.project), Qt::RightDockWidgetArea);
delete app.win;
}
QTEST_MAIN(TestProjectDock)
#include "test_project_dock.moc"

View File

@@ -0,0 +1,307 @@
#include <QtTest/QTest>
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <algorithm>
#include <random>
#include "core.h"
#include "imports/import_source.h"
#include "generator.h"
using namespace rcx;
class TestRoundtripWinSdk : public QObject {
Q_OBJECT
private:
NodeTree fullTree;
QVector<int> rootIndices;
private slots:
void initTestCase();
void importCount();
void pebOffsets();
void roundTrip30();
void generateRcx();
};
void TestRoundtripWinSdk::initTestCase()
{
QString path = QStringLiteral(WINSDK_HEADER_PATH);
QFile file(path);
QVERIFY2(file.open(QIODevice::ReadOnly | QIODevice::Text),
qPrintable("Cannot open " + path));
QString source = QString::fromUtf8(file.readAll());
QVERIFY(!source.isEmpty());
QString err;
fullTree = importFromSource(source, &err, 8);
for (int i = 0; i < fullTree.nodes.size(); i++) {
const auto& n = fullTree.nodes[i];
if (n.parentId == 0 && n.kind == NodeKind::Struct)
rootIndices.append(i);
}
qDebug() << "Imported" << fullTree.nodes.size() << "total nodes,"
<< rootIndices.size() << "root structs";
}
void TestRoundtripWinSdk::importCount()
{
QVERIFY2(rootIndices.size() >= 3000,
qPrintable(QString("Expected >= 3000 roots, got %1").arg(rootIndices.size())));
}
void TestRoundtripWinSdk::pebOffsets()
{
// Verify _PEB field offsets match WinDbg dt ntdll!_PEB
int pebIdx = -1;
for (int i = 0; i < fullTree.nodes.size(); i++) {
if (fullTree.nodes[i].parentId == 0 &&
fullTree.nodes[i].structTypeName == QStringLiteral("_PEB")) {
pebIdx = i;
break;
}
}
QVERIFY2(pebIdx >= 0, "Could not find _PEB root struct");
uint64_t pebId = fullTree.nodes[pebIdx].id;
// Collect direct children with offsets and sizes
struct ChildInfo { QString name; int offset; int size; NodeKind kind; };
QVector<ChildInfo> children;
for (int i = 0; i < fullTree.nodes.size(); i++) {
if (fullTree.nodes[i].parentId == pebId) {
int sz = sizeForKind(fullTree.nodes[i].kind);
if (sz == 0) sz = fullTree.structSpan(fullTree.nodes[i].id);
if (sz == 0) sz = 1;
children.push_back(ChildInfo{fullTree.nodes[i].name, fullTree.nodes[i].offset, sz, fullTree.nodes[i].kind});
}
}
// Sort by offset
std::sort(children.begin(), children.end(),
[](const ChildInfo& a, const ChildInfo& b) { return a.offset < b.offset; });
// Dump all children for diagnostics
for (const auto& c : children) {
qDebug() << " " << Qt::hex << c.offset << c.name
<< "kind=" << kindToString(c.kind) << "size=" << c.size;
}
// Check for overlaps
int overlapCount = 0;
for (int i = 1; i < children.size(); i++) {
int prevEnd = children[i-1].offset + children[i-1].size;
if (children[i].offset < prevEnd && children[i-1].kind != NodeKind::Struct) {
// Only flag overlaps where previous field has a known size (not struct references)
overlapCount++;
if (overlapCount <= 10)
qDebug() << " OVERLAP:" << children[i].name << "at" << Qt::hex << children[i].offset
<< "overlaps" << children[i-1].name << "(ends at" << Qt::hex << prevEnd << ")";
}
}
// Build name→offset map for field checks
QHash<QString, int> offsets;
QHash<QString, NodeKind> kinds;
for (const auto& c : children) {
offsets[c.name] = c.offset;
kinds[c.name] = c.kind;
}
int failCount = 0;
auto checkField = [&](const QString& name, int expected, bool mustBePointer = false) {
if (!offsets.contains(name)) {
qDebug() << " MISSING:" << name;
failCount++;
return;
}
if (offsets[name] != expected) {
qDebug() << " OFFSET MISMATCH:" << name << "got" << Qt::hex << offsets[name]
<< "expected" << Qt::hex << expected;
failCount++;
return;
}
if (mustBePointer) {
NodeKind k = kinds[name];
if (k != NodeKind::Pointer64 && k != NodeKind::Pointer32) {
qDebug() << " NOT POINTER:" << name << "kind=" << kindToString(k);
failCount++;
}
}
};
// Expected offsets computed from the source header layout (Vergilius-style)
// Note: This header has union ALIGN(8) { KernelCallbackTable; UserSharedInfoPtr; }
// after CrossProcessFlags, which shifts fields +0xC compared to some WinDbg versions.
checkField(QStringLiteral("InheritedAddressSpace"), 0x000);
checkField(QStringLiteral("ReadImageFileExecOptions"), 0x001);
checkField(QStringLiteral("BeingDebugged"), 0x002);
checkField(QStringLiteral("Mutant"), 0x008, true);
checkField(QStringLiteral("ImageBaseAddress"), 0x010, true);
checkField(QStringLiteral("Ldr"), 0x018, true);
checkField(QStringLiteral("ProcessParameters"), 0x020, true);
checkField(QStringLiteral("SubSystemData"), 0x028, true);
checkField(QStringLiteral("ProcessHeap"), 0x030, true);
checkField(QStringLiteral("FastPebLock"), 0x038, true);
checkField(QStringLiteral("AtlThunkSListPtr"), 0x040, true);
checkField(QStringLiteral("IFEOKey"), 0x048, true);
checkField(QStringLiteral("SystemReserved"), 0x060);
checkField(QStringLiteral("AtlThunkSListPtr32"), 0x064);
checkField(QStringLiteral("ApiSetMap"), 0x068, true);
checkField(QStringLiteral("TlsExpansionCounter"), 0x070);
checkField(QStringLiteral("TlsBitmap"), 0x078, true);
checkField(QStringLiteral("TlsBitmapBits"), 0x080);
checkField(QStringLiteral("ReadOnlySharedMemoryBase"), 0x088, true);
checkField(QStringLiteral("SharedData"), 0x090, true);
checkField(QStringLiteral("ReadOnlyStaticServerData"), 0x098, true);
checkField(QStringLiteral("AnsiCodePageData"), 0x0A0, true);
checkField(QStringLiteral("OemCodePageData"), 0x0A8, true);
checkField(QStringLiteral("UnicodeCaseTableData"), 0x0B0, true);
checkField(QStringLiteral("NumberOfProcessors"), 0x0B8);
checkField(QStringLiteral("NtGlobalFlag"), 0x0BC);
checkField(QStringLiteral("HeapSegmentReserve"), 0x0C8);
checkField(QStringLiteral("NumberOfHeaps"), 0x0E8);
checkField(QStringLiteral("MaximumNumberOfHeaps"), 0x0EC);
checkField(QStringLiteral("ProcessHeaps"), 0x0F0, true);
checkField(QStringLiteral("OSMajorVersion"), 0x118);
checkField(QStringLiteral("OSMinorVersion"), 0x11C);
checkField(QStringLiteral("OSBuildNumber"), 0x120);
checkField(QStringLiteral("SessionId"), 0x2C0);
checkField(QStringLiteral("CsrServerReadOnlySharedMemoryBase"), 0x380);
checkField(QStringLiteral("TppWorkerpListLock"), 0x388, true);
checkField(QStringLiteral("WaitOnAddressHashTable"), 0x3A0);
checkField(QStringLiteral("TelemetryCoverageHeader"), 0x7A0, true);
checkField(QStringLiteral("CloudFileFlags"), 0x7A8);
checkField(QStringLiteral("CloudFileDiagFlags"), 0x7AC);
checkField(QStringLiteral("PlaceholderCompatibilityMode"), 0x7B0);
checkField(QStringLiteral("LeapSecondData"), 0x7B8, true);
checkField(QStringLiteral("NtGlobalFlag2"), 0x7C4);
QVERIFY2(failCount == 0,
qPrintable(QString("%1 PEB field(s) have wrong offsets or are missing").arg(failCount)));
}
void TestRoundtripWinSdk::roundTrip30()
{
const int kRequired = 30;
// Deterministic shuffle
QVector<int> shuffled = rootIndices;
std::mt19937 rng(42);
std::shuffle(shuffled.begin(), shuffled.end(), rng);
int passCount = 0;
int failCount = 0;
int skipCount = 0;
for (int ri : shuffled) {
uint64_t rootId = fullTree.nodes[ri].id;
QString structName = fullTree.nodes[ri].structTypeName;
// Pass 1: export from full tree
QString cpp1 = renderCpp(fullTree, rootId, nullptr, true);
if (cpp1.isEmpty()) {
skipCount++;
continue;
}
// Pass 2: re-import
QString err;
NodeTree tree2 = importFromSource(cpp1, &err);
if (tree2.nodes.isEmpty()) {
skipCount++;
continue;
}
// Find the root in re-imported tree
int rootIdx2 = -1;
for (int i = 0; i < tree2.nodes.size(); i++) {
if (tree2.nodes[i].parentId == 0 && tree2.nodes[i].kind == NodeKind::Struct) {
if (tree2.nodes[i].structTypeName == structName) {
rootIdx2 = i;
break;
}
}
}
if (rootIdx2 < 0) {
// Take first root
for (int i = 0; i < tree2.nodes.size(); i++) {
if (tree2.nodes[i].parentId == 0 && tree2.nodes[i].kind == NodeKind::Struct) {
rootIdx2 = i;
break;
}
}
}
if (rootIdx2 < 0) {
skipCount++;
continue;
}
// Pass 3: re-export
QString cpp2 = renderCpp(tree2, tree2.nodes[rootIdx2].id, nullptr, true);
if (cpp1 == cpp2) {
passCount++;
if (passCount <= kRequired)
qDebug() << " PASS" << passCount << structName;
} else {
failCount++;
if (failCount <= 5) {
// Log first few failures for diagnostics
QStringList lines1 = cpp1.split('\n');
QStringList lines2 = cpp2.split('\n');
int diffLine = -1;
for (int i = 0; i < qMin(lines1.size(), lines2.size()); i++) {
if (lines1[i] != lines2[i]) { diffLine = i; break; }
}
if (diffLine >= 0) {
qDebug() << " FAIL" << structName << "first diff at line" << diffLine;
qDebug() << " cpp1:" << lines1[diffLine].left(120);
qDebug() << " cpp2:" << lines2[diffLine].left(120);
} else {
qDebug() << " FAIL" << structName << "line count differs:"
<< lines1.size() << "vs" << lines2.size();
}
}
}
if (passCount >= kRequired && failCount > 5)
break; // found enough passes and logged enough failures
}
qDebug() << "Round-trip results: pass=" << passCount
<< "fail=" << failCount << "skip=" << skipCount;
QVERIFY2(passCount >= kRequired,
qPrintable(QString("Need %1 stable round-trips, got %2")
.arg(kRequired).arg(passCount)));
}
void TestRoundtripWinSdk::generateRcx()
{
// Set all root structs collapsed
for (int ri : rootIndices)
fullTree.nodes[ri].collapsed = true;
fullTree.baseAddress = 0xFFFFF80000000000ULL;
QJsonObject json = fullTree.toJson();
QJsonDocument jdoc(json);
QByteArray data = jdoc.toJson(QJsonDocument::Indented);
QVERIFY2(data.size() > 1000000,
qPrintable(QString("RCX too small: %1 bytes").arg(data.size())));
QString outPath = QStringLiteral(WINSDK_RCX_OUTPUT);
QFile file(outPath);
QVERIFY2(file.open(QIODevice::WriteOnly | QIODevice::Truncate),
qPrintable("Cannot write " + outPath));
file.write(data);
file.close();
qDebug() << "Wrote" << data.size() << "bytes to" << outPath;
}
QTEST_MAIN(TestRoundtripWinSdk)
#include "test_roundtrip_winsdk.moc"

View File

@@ -644,8 +644,8 @@ private slots:
data[16] = 0xAA; // in region 1 (executable) data[16] = 0xAA; // in region 1 (executable)
QVector<MemoryRegion> regions; QVector<MemoryRegion> regions;
regions.append({0, 16, true, true, false, "heap"}); regions.push_back(MemoryRegion{0, 16, true, true, false, "heap"});
regions.append({16, 16, true, false, true, "code"}); regions.push_back(MemoryRegion{16, 16, true, false, true, "code"});
auto prov = std::make_shared<RegionProvider>(data, regions); auto prov = std::make_shared<RegionProvider>(data, regions);
ScanEngine engine; ScanEngine engine;
@@ -671,8 +671,8 @@ private slots:
data[16] = 0xBB; // region 1 (not writable) data[16] = 0xBB; // region 1 (not writable)
QVector<MemoryRegion> regions; QVector<MemoryRegion> regions;
regions.append({0, 16, true, true, false, "data"}); regions.push_back(MemoryRegion{0, 16, true, true, false, "data"});
regions.append({16, 16, true, false, true, "code"}); regions.push_back(MemoryRegion{16, 16, true, false, true, "code"});
auto prov = std::make_shared<RegionProvider>(data, regions); auto prov = std::make_shared<RegionProvider>(data, regions);
ScanEngine engine; ScanEngine engine;
@@ -698,9 +698,9 @@ private slots:
data[32] = 0xCC; // region 2: +w +x data[32] = 0xCC; // region 2: +w +x
QVector<MemoryRegion> regions; QVector<MemoryRegion> regions;
regions.append({0, 16, true, true, false, "data"}); regions.push_back(MemoryRegion{0, 16, true, true, false, "data"});
regions.append({16, 16, true, false, true, "code"}); regions.push_back(MemoryRegion{16, 16, true, false, true, "code"});
regions.append({32, 16, true, true, true, "rwx"}); regions.push_back(MemoryRegion{32, 16, true, true, true, "rwx"});
auto prov = std::make_shared<RegionProvider>(data, regions); auto prov = std::make_shared<RegionProvider>(data, regions);
ScanEngine engine; ScanEngine engine;
@@ -726,7 +726,7 @@ private slots:
data[0] = 0xDD; data[0] = 0xDD;
QVector<MemoryRegion> regions; QVector<MemoryRegion> regions;
regions.append({0, 16, true, true, true, "Game.exe"}); regions.push_back(MemoryRegion{0, 16, true, true, true, "Game.exe"});
auto prov = std::make_shared<RegionProvider>(data, regions); auto prov = std::make_shared<RegionProvider>(data, regions);
ScanEngine engine; ScanEngine engine;
@@ -943,8 +943,8 @@ private slots:
void provider_customRegions() { void provider_customRegions() {
QVector<MemoryRegion> regs; QVector<MemoryRegion> regs;
regs.append({0x1000, 0x2000, true, true, false, "heap"}); regs.push_back(MemoryRegion{0x1000, 0x2000, true, true, false, "heap"});
regs.append({0x3000, 0x1000, true, false, true, "code"}); regs.push_back(MemoryRegion{0x3000, 0x1000, true, false, true, "code"});
RegionProvider p(QByteArray(0x4000, '\0'), regs); RegionProvider p(QByteArray(0x4000, '\0'), regs);
auto result = p.enumerateRegions(); auto result = p.enumerateRegions();
@@ -982,9 +982,9 @@ private slots:
data[36] = 0xEE; // region 2 data[36] = 0xEE; // region 2
QVector<MemoryRegion> regions; QVector<MemoryRegion> regions;
regions.append({0, 16, true, true, false, "region0"}); regions.push_back(MemoryRegion{0, 16, true, true, false, "region0"});
regions.append({16, 16, true, true, false, "region1"}); regions.push_back(MemoryRegion{16, 16, true, true, false, "region1"});
regions.append({32, 16, true, true, false, "region2"}); regions.push_back(MemoryRegion{32, 16, true, true, false, "region2"});
auto prov = std::make_shared<RegionProvider>(data, regions); auto prov = std::make_shared<RegionProvider>(data, regions);
ScanEngine engine; ScanEngine engine;
@@ -1215,7 +1215,7 @@ private slots:
data[160] = char(0xCC); data[160] = char(0xCC);
data[210] = char(0xCC); data[210] = char(0xCC);
QVector<MemoryRegion> regions; QVector<MemoryRegion> regions;
regions.append({100, 100, true, false, false, {}}); regions.push_back(MemoryRegion{100, 100, true, false, false, {}});
auto prov = std::make_shared<RegionProvider>(data, regions); auto prov = std::make_shared<RegionProvider>(data, regions);
ScanEngine engine; ScanEngine engine;
QSignalSpy finSpy(&engine, &ScanEngine::finished); QSignalSpy finSpy(&engine, &ScanEngine::finished);
@@ -1233,7 +1233,7 @@ private slots:
void scan_constrainRegions_noOverlap() { void scan_constrainRegions_noOverlap() {
QByteArray data(32, char(0xEE)); QByteArray data(32, char(0xEE));
QVector<MemoryRegion> regions; QVector<MemoryRegion> regions;
regions.append({0, 16, true, false, false, {}}); regions.push_back(MemoryRegion{0, 16, true, false, false, {}});
auto prov = std::make_shared<RegionProvider>(data, regions); auto prov = std::make_shared<RegionProvider>(data, regions);
ScanEngine engine; ScanEngine engine;
QSignalSpy finSpy(&engine, &ScanEngine::finished); QSignalSpy finSpy(&engine, &ScanEngine::finished);
@@ -1256,8 +1256,8 @@ private slots:
data[10] = char(0xDD); data[10] = char(0xDD);
data[35] = char(0xDD); data[35] = char(0xDD);
QVector<MemoryRegion> regions; QVector<MemoryRegion> regions;
regions.append({0, 16, true, true, false, {}}); regions.push_back(MemoryRegion{0, 16, true, true, false, {}});
regions.append({32, 16, true, true, false, {}}); regions.push_back(MemoryRegion{32, 16, true, true, false, {}});
auto prov = std::make_shared<RegionProvider>(data, regions); auto prov = std::make_shared<RegionProvider>(data, regions);
ScanEngine engine; ScanEngine engine;
QSignalSpy finSpy(&engine, &ScanEngine::finished); QSignalSpy finSpy(&engine, &ScanEngine::finished);
@@ -1279,7 +1279,7 @@ private slots:
data[120] = char(0xAB); data[120] = char(0xAB);
data[160] = char(0xAB); data[160] = char(0xAB);
QVector<MemoryRegion> regions; QVector<MemoryRegion> regions;
regions.append({100, 100, true, true, false, {}}); regions.push_back(MemoryRegion{100, 100, true, true, false, {}});
auto prov = std::make_shared<RegionProvider>(data, regions); auto prov = std::make_shared<RegionProvider>(data, regions);
ScanEngine engine; ScanEngine engine;
QSignalSpy finSpy(&engine, &ScanEngine::finished); QSignalSpy finSpy(&engine, &ScanEngine::finished);
@@ -1300,8 +1300,8 @@ private slots:
data[0x1500] = char(0xCC); data[0x1500] = char(0xCC);
data[0x5500] = char(0xCC); data[0x5500] = char(0xCC);
QVector<MemoryRegion> regions; QVector<MemoryRegion> regions;
regions.append({0x1000, 0x1000, true, false, true, QString("game.exe")}); regions.push_back(MemoryRegion{0x1000, 0x1000, true, false, true, QString("game.exe")});
regions.append({0x5000, 0x1000, true, true, false, {}}); regions.push_back(MemoryRegion{0x5000, 0x1000, true, true, false, {}});
auto prov = std::make_shared<RegionProvider>(data, regions); auto prov = std::make_shared<RegionProvider>(data, regions);
ScanEngine engine; ScanEngine engine;
QSignalSpy finSpy(&engine, &ScanEngine::finished); QSignalSpy finSpy(&engine, &ScanEngine::finished);
@@ -1345,8 +1345,8 @@ private slots:
data[12] = char(0xEF); data[12] = char(0xEF);
data[20] = char(0xEF); data[20] = char(0xEF);
QVector<MemoryRegion> regions; QVector<MemoryRegion> regions;
regions.append({0, 16, true, true, false, {}}); regions.push_back(MemoryRegion{0, 16, true, true, false, {}});
regions.append({16, 16, true, true, false, {}}); regions.push_back(MemoryRegion{16, 16, true, true, false, {}});
auto prov = std::make_shared<RegionProvider>(data, regions); auto prov = std::make_shared<RegionProvider>(data, regions);
ScanEngine engine; ScanEngine engine;
QSignalSpy finSpy(&engine, &ScanEngine::finished); QSignalSpy finSpy(&engine, &ScanEngine::finished);
@@ -1368,8 +1368,8 @@ private slots:
data[0x1100] = char(0xBB); data[0x1100] = char(0xBB);
data[0x2100] = char(0xBB); data[0x2100] = char(0xBB);
QVector<MemoryRegion> regions; QVector<MemoryRegion> regions;
regions.append({0x1000, 0x1000, true, false, true, {}}); regions.push_back(MemoryRegion{0x1000, 0x1000, true, false, true, {}});
regions.append({0x2000, 0x1000, true, true, false, {}}); regions.push_back(MemoryRegion{0x2000, 0x1000, true, true, false, {}});
auto prov = std::make_shared<RegionProvider>(data, regions); auto prov = std::make_shared<RegionProvider>(data, regions);
ScanEngine engine; ScanEngine engine;
QSignalSpy finSpy(&engine, &ScanEngine::finished); QSignalSpy finSpy(&engine, &ScanEngine::finished);
@@ -1394,7 +1394,7 @@ private slots:
data[15] = char(0xAA); // inside region, should be found data[15] = char(0xAA); // inside region, should be found
data[25] = char(0xAA); // outside region, should NOT be found data[25] = char(0xAA); // outside region, should NOT be found
QVector<MemoryRegion> regions; QVector<MemoryRegion> regions;
regions.append({10, 10, true, true, false, {}}); regions.push_back(MemoryRegion{10, 10, true, true, false, {}});
auto prov = std::make_shared<RegionProvider>(data, regions); auto prov = std::make_shared<RegionProvider>(data, regions);
ScanEngine engine; ScanEngine engine;
QSignalSpy finSpy(&engine, &ScanEngine::finished); QSignalSpy finSpy(&engine, &ScanEngine::finished);
@@ -1415,7 +1415,7 @@ private slots:
data[5] = char(0xBB); data[5] = char(0xBB);
data[15] = char(0xBB); data[15] = char(0xBB);
QVector<MemoryRegion> regions; QVector<MemoryRegion> regions;
regions.append({0, 32, true, true, false, {}}); regions.push_back(MemoryRegion{0, 32, true, true, false, {}});
auto prov = std::make_shared<RegionProvider>(data, regions); auto prov = std::make_shared<RegionProvider>(data, regions);
ScanEngine engine; ScanEngine engine;
QSignalSpy finSpy(&engine, &ScanEngine::finished); QSignalSpy finSpy(&engine, &ScanEngine::finished);
@@ -1506,7 +1506,7 @@ private slots:
QByteArray data(0x10000, 0); QByteArray data(0x10000, 0);
data[0x8100] = char(0xFF); data[0x8100] = char(0xFF);
QVector<MemoryRegion> regions; QVector<MemoryRegion> regions;
regions.append({0x8000, 0x1000, true, true, false, {}}); regions.push_back(MemoryRegion{0x8000, 0x1000, true, true, false, {}});
auto prov = std::make_shared<RegionProvider>(data, regions); auto prov = std::make_shared<RegionProvider>(data, regions);
ScanEngine engine; ScanEngine engine;
QSignalSpy finSpy(&engine, &ScanEngine::finished); QSignalSpy finSpy(&engine, &ScanEngine::finished);
@@ -1581,7 +1581,7 @@ private slots:
QByteArray data(64, 0); QByteArray data(64, 0);
data[20] = char(0xFE); data[20] = char(0xFE);
QVector<MemoryRegion> regions; QVector<MemoryRegion> regions;
regions.append({0, 64, true, true, false, {}}); regions.push_back(MemoryRegion{0, 64, true, true, false, {}});
auto prov = std::make_shared<RegionProvider>(data, regions); auto prov = std::make_shared<RegionProvider>(data, regions);
ScanEngine engine; ScanEngine engine;
QSignalSpy finSpy(&engine, &ScanEngine::finished); QSignalSpy finSpy(&engine, &ScanEngine::finished);
@@ -1602,7 +1602,7 @@ private slots:
QByteArray data(64, 0); QByteArray data(64, 0);
data[36] = char(0xDE); data[37] = char(0xAD); data[38] = char(0xBE); data[39] = char(0xEF); data[36] = char(0xDE); data[37] = char(0xAD); data[38] = char(0xBE); data[39] = char(0xEF);
QVector<MemoryRegion> regions; QVector<MemoryRegion> regions;
regions.append({0, 64, true, true, false, {}}); regions.push_back(MemoryRegion{0, 64, true, true, false, {}});
auto prov = std::make_shared<RegionProvider>(data, regions); auto prov = std::make_shared<RegionProvider>(data, regions);
ScanEngine engine; ScanEngine engine;
QSignalSpy finSpy(&engine, &ScanEngine::finished); QSignalSpy finSpy(&engine, &ScanEngine::finished);
@@ -1624,7 +1624,7 @@ private slots:
QByteArray data(64, 0); QByteArray data(64, 0);
data[36] = char(0xDE); data[37] = char(0xAD); data[38] = char(0xBE); data[39] = char(0xEF); data[36] = char(0xDE); data[37] = char(0xAD); data[38] = char(0xBE); data[39] = char(0xEF);
QVector<MemoryRegion> regions; QVector<MemoryRegion> regions;
regions.append({0, 64, true, true, false, {}}); regions.push_back(MemoryRegion{0, 64, true, true, false, {}});
auto prov = std::make_shared<RegionProvider>(data, regions); auto prov = std::make_shared<RegionProvider>(data, regions);
ScanEngine engine; ScanEngine engine;
QSignalSpy finSpy(&engine, &ScanEngine::finished); QSignalSpy finSpy(&engine, &ScanEngine::finished);
@@ -1643,7 +1643,7 @@ private slots:
// Region [0, 64). Constraint [30, 32). 4-byte pattern can't fit in 2 bytes. // Region [0, 64). Constraint [30, 32). 4-byte pattern can't fit in 2 bytes.
QByteArray data(64, char(0xAA)); QByteArray data(64, char(0xAA));
QVector<MemoryRegion> regions; QVector<MemoryRegion> regions;
regions.append({0, 64, true, true, false, {}}); regions.push_back(MemoryRegion{0, 64, true, true, false, {}});
auto prov = std::make_shared<RegionProvider>(data, regions); auto prov = std::make_shared<RegionProvider>(data, regions);
ScanEngine engine; ScanEngine engine;
QSignalSpy finSpy(&engine, &ScanEngine::finished); QSignalSpy finSpy(&engine, &ScanEngine::finished);
@@ -1663,7 +1663,7 @@ private slots:
QByteArray data(64, 0); QByteArray data(64, 0);
data[30] = char(0x11); data[31] = char(0x22); data[32] = char(0x33); data[33] = char(0x44); data[30] = char(0x11); data[31] = char(0x22); data[32] = char(0x33); data[33] = char(0x44);
QVector<MemoryRegion> regions; QVector<MemoryRegion> regions;
regions.append({0, 64, true, true, false, {}}); regions.push_back(MemoryRegion{0, 64, true, true, false, {}});
auto prov = std::make_shared<RegionProvider>(data, regions); auto prov = std::make_shared<RegionProvider>(data, regions);
ScanEngine engine; ScanEngine engine;
QSignalSpy finSpy(&engine, &ScanEngine::finished); QSignalSpy finSpy(&engine, &ScanEngine::finished);
@@ -1686,8 +1686,8 @@ private slots:
data[15] = char(0x77); // last byte of first region data[15] = char(0x77); // last byte of first region
data[16] = char(0x77); // first byte of second region data[16] = char(0x77); // first byte of second region
QVector<MemoryRegion> regions; QVector<MemoryRegion> regions;
regions.append({0, 16, true, true, false, {}}); regions.push_back(MemoryRegion{0, 16, true, true, false, {}});
regions.append({16, 16, true, true, false, {}}); regions.push_back(MemoryRegion{16, 16, true, true, false, {}});
auto prov = std::make_shared<RegionProvider>(data, regions); auto prov = std::make_shared<RegionProvider>(data, regions);
ScanEngine engine; ScanEngine engine;
QSignalSpy finSpy(&engine, &ScanEngine::finished); QSignalSpy finSpy(&engine, &ScanEngine::finished);
@@ -1711,7 +1711,7 @@ private slots:
QByteArray data(64, 0); QByteArray data(64, 0);
data[10] = char(0xAA); data[11] = char(0xBB); data[12] = char(0xCC); data[13] = char(0xDD); data[10] = char(0xAA); data[11] = char(0xBB); data[12] = char(0xCC); data[13] = char(0xDD);
QVector<MemoryRegion> regions; QVector<MemoryRegion> regions;
regions.append({0, 64, true, true, false, {}}); regions.push_back(MemoryRegion{0, 64, true, true, false, {}});
auto prov = std::make_shared<RegionProvider>(data, regions); auto prov = std::make_shared<RegionProvider>(data, regions);
ScanEngine engine; ScanEngine engine;
QSignalSpy finSpy(&engine, &ScanEngine::finished); QSignalSpy finSpy(&engine, &ScanEngine::finished);