Speed handle object comparison by reducing NtQuerySystemInformation calls
This commit is contained in:
parent
ac238429fc
commit
28f11b7f9b
@ -50,16 +50,6 @@ static void Test_CreateProcess_STARTUPINFOEX() {
|
||||
// handles didn't revert to the original default, but were inherited.
|
||||
p.openConout(true);
|
||||
|
||||
// Verify that compareObjectHandles is working...
|
||||
{
|
||||
CHECK(!compareObjectHandles(ph1, ph2));
|
||||
auto dupTest = ph1.dup();
|
||||
CHECK(compareObjectHandles(ph1, dupTest));
|
||||
dupTest.close();
|
||||
Worker other;
|
||||
CHECK(compareObjectHandles(ph1, ph1.dup(other)));
|
||||
}
|
||||
|
||||
auto testSetupOneHandle = [&](SpawnParams sp, size_t cb, HANDLE inherit) {
|
||||
sp.sui.cb = cb;
|
||||
sp.inheritCount = 1;
|
||||
@ -159,10 +149,13 @@ static void Test_CreateProcess_STARTUPINFOEX() {
|
||||
auto ch2 = Handle::invent(ph2.value(), c);
|
||||
auto ch3 = Handle::invent(ph3.value(), c);
|
||||
auto ch4 = Handle::invent(ph4.value(), c);
|
||||
CHECK(!compareObjectHandles(ph1, ch1));
|
||||
CHECK(!compareObjectHandles(ph2, ch2));
|
||||
CHECK(!compareObjectHandles(ph3, ch3));
|
||||
CHECK(!compareObjectHandles(ph4, ch4));
|
||||
{
|
||||
ObjectSnap snap;
|
||||
CHECK(!snap.eq(ph1, ch1));
|
||||
CHECK(!snap.eq(ph2, ch2));
|
||||
CHECK(!snap.eq(ph3, ch3));
|
||||
CHECK(!snap.eq(ph4, ch4));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,9 +17,10 @@ static void Test_CreateProcess_DefaultInherit() {
|
||||
auto pipe = newPipe(p, false);
|
||||
auto wh = std::get<1>(pipe).setStdin().setStdout().setStderr();
|
||||
auto c = p.child({ false });
|
||||
CHECK(compareObjectHandles(c.getStdin(), wh));
|
||||
CHECK(compareObjectHandles(c.getStdout(), wh));
|
||||
CHECK(compareObjectHandles(c.getStderr(), wh));
|
||||
{
|
||||
ObjectSnap snap;
|
||||
CHECK(snap.eq({ c.getStdin(), c.getStdout(), c.getStderr(), wh }));
|
||||
}
|
||||
// CreateProcess makes separate handles for stdin/stdout/stderr.
|
||||
CHECK(c.getStdin().value() != c.getStdout().value());
|
||||
CHECK(c.getStdout().value() != c.getStderr().value());
|
||||
@ -27,9 +28,10 @@ static void Test_CreateProcess_DefaultInherit() {
|
||||
// Calling FreeConsole in the child does not free the duplicated
|
||||
// handles.
|
||||
c.detach();
|
||||
CHECK(compareObjectHandles(c.getStdin(), wh));
|
||||
CHECK(compareObjectHandles(c.getStdout(), wh));
|
||||
CHECK(compareObjectHandles(c.getStderr(), wh));
|
||||
{
|
||||
ObjectSnap snap;
|
||||
CHECK(snap.eq({ c.getStdin(), c.getStdout(), c.getStderr(), wh }));
|
||||
}
|
||||
}
|
||||
{
|
||||
// Bogus values are transformed into zero.
|
||||
@ -49,8 +51,9 @@ static void Test_CreateProcess_DefaultInherit() {
|
||||
auto ph = stdHandles(p);
|
||||
auto ch = stdHandles(c);
|
||||
auto check = [&]() {
|
||||
ObjectSnap snap;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
CHECK(compareObjectHandles(ph[i], ch[i]));
|
||||
CHECK(snap.eq(ph[i], ch[i]));
|
||||
CHECK_EQ(ph[i].inheritable(), ch[i].inheritable());
|
||||
}
|
||||
};
|
||||
@ -100,9 +103,9 @@ static void Test_CreateProcess_DefaultInherit() {
|
||||
} else {
|
||||
// In Win8, a console handle works like all other handles.
|
||||
CHECK_EQ(c.getStdout().firstChar(), 'B');
|
||||
CHECK(compareObjectHandles(p.getStdout(), p.getStderr()));
|
||||
CHECK(compareObjectHandles(c.getStdout(), c.getStderr()));
|
||||
CHECK(compareObjectHandles(p.getStdout(), c.getStdout()));
|
||||
ObjectSnap snap;
|
||||
CHECK(snap.eq({ p.getStdout(), p.getStderr(),
|
||||
c.getStdout(), c.getStderr() }));
|
||||
CHECK(!c.getStdout().inheritable());
|
||||
CHECK(!c.getStderr().inheritable());
|
||||
}
|
||||
|
@ -10,9 +10,10 @@ static void Test_CreateProcess_DefaultInherit_XPPipeBug() {
|
||||
CHECK((proc.getStdout().value() == nullptr) == expectBroken);
|
||||
CHECK((proc.getStderr().value() == nullptr) == expectBroken);
|
||||
if (!expectBroken) {
|
||||
CHECK(compareObjectHandles(proc.getStdin(), correct));
|
||||
CHECK(compareObjectHandles(proc.getStdout(), correct));
|
||||
CHECK(compareObjectHandles(proc.getStderr(), correct));
|
||||
ObjectSnap snap;
|
||||
CHECK(snap.eq({
|
||||
proc.getStdin(), proc.getStdout(), proc.getStderr(), correct
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,5 +1,34 @@
|
||||
#include <TestCommon.h>
|
||||
|
||||
REGISTER(Test_CompareObjectHandles, always);
|
||||
static void Test_CompareObjectHandles() {
|
||||
// Verify that compareObjectHandles and ObjectSnap are working.
|
||||
|
||||
Worker p;
|
||||
Worker other;
|
||||
auto pipe1 = newPipe(p, true);
|
||||
auto ph1 = std::get<0>(pipe1);
|
||||
auto ph2 = std::get<1>(pipe1);
|
||||
auto ph1dup = ph1.dup();
|
||||
auto ph1other = ph1.dup(other);
|
||||
|
||||
ObjectSnap snap;
|
||||
|
||||
CHECK(!compareObjectHandles(ph1, ph2));
|
||||
CHECK(compareObjectHandles(ph1, ph1dup));
|
||||
CHECK(compareObjectHandles(ph1, ph1other));
|
||||
|
||||
CHECK(!snap.eq(ph1, ph2));
|
||||
CHECK(snap.eq(ph1, ph1dup));
|
||||
CHECK(snap.eq(ph1, ph1other));
|
||||
CHECK(snap.eq({ ph1, ph1other, ph1dup }));
|
||||
|
||||
CHECK(!snap.eq({ ph2, ph1, ph1other, ph1dup }));
|
||||
CHECK(!snap.eq({ ph1, ph2, ph1other, ph1dup }));
|
||||
CHECK(!snap.eq({ ph1, ph1other, ph2, ph1dup }));
|
||||
CHECK(!snap.eq({ ph1, ph1other, ph1dup, ph2 }));
|
||||
}
|
||||
|
||||
REGISTER(Test_IntrinsicInheritFlags, always);
|
||||
static void Test_IntrinsicInheritFlags() {
|
||||
// Console handles have an inherit flag, just as kernel handles do.
|
||||
|
@ -59,40 +59,77 @@ void *ntHandlePointer(const std::vector<SYSTEM_HANDLE_ENTRY> &table,
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool hasBuiltinCompareObjectHandles() {
|
||||
static auto kernelbase = LoadLibraryW(L"KernelBase.dll");
|
||||
if (kernelbase != nullptr) {
|
||||
static auto proc = GetProcAddress(kernelbase, "CompareObjectHandles");
|
||||
if (proc != nullptr) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool compareObjectHandles(RemoteHandle h1, RemoteHandle h2) {
|
||||
static auto kernelbaseCheck = LoadLibraryW(L"KernelBase.dll");
|
||||
if (kernelbaseCheck != nullptr) {
|
||||
if (hasBuiltinCompareObjectHandles()) {
|
||||
static OsModule kernelbase(L"KernelBase.dll");
|
||||
static auto comp =
|
||||
reinterpret_cast<BOOL(WINAPI*)(HANDLE,HANDLE)>(
|
||||
kernelbase.proc("CompareObjectHandles"));
|
||||
if (comp != nullptr) {
|
||||
HANDLE h1local = nullptr;
|
||||
HANDLE h2local = nullptr;
|
||||
bool dup1 = DuplicateHandle(
|
||||
h1.worker().processHandle(),
|
||||
h1.value(),
|
||||
GetCurrentProcess(),
|
||||
&h1local,
|
||||
0, false, DUPLICATE_SAME_ACCESS);
|
||||
bool dup2 = DuplicateHandle(
|
||||
h2.worker().processHandle(),
|
||||
h2.value(),
|
||||
GetCurrentProcess(),
|
||||
&h2local,
|
||||
0, false, DUPLICATE_SAME_ACCESS);
|
||||
bool ret = dup1 && dup2 && comp(h1local, h2local);
|
||||
if (dup1) {
|
||||
CloseHandle(h1local);
|
||||
ASSERT(comp != nullptr);
|
||||
HANDLE h1local = nullptr;
|
||||
HANDLE h2local = nullptr;
|
||||
bool dup1 = DuplicateHandle(
|
||||
h1.worker().processHandle(),
|
||||
h1.value(),
|
||||
GetCurrentProcess(),
|
||||
&h1local,
|
||||
0, false, DUPLICATE_SAME_ACCESS);
|
||||
bool dup2 = DuplicateHandle(
|
||||
h2.worker().processHandle(),
|
||||
h2.value(),
|
||||
GetCurrentProcess(),
|
||||
&h2local,
|
||||
0, false, DUPLICATE_SAME_ACCESS);
|
||||
bool ret = dup1 && dup2 && comp(h1local, h2local);
|
||||
if (dup1) {
|
||||
CloseHandle(h1local);
|
||||
}
|
||||
if (dup2) {
|
||||
CloseHandle(h2local);
|
||||
}
|
||||
return ret;
|
||||
} else {
|
||||
auto table = queryNtHandles();
|
||||
return ntHandlePointer(table, h1) == ntHandlePointer(table, h2);
|
||||
}
|
||||
}
|
||||
|
||||
ObjectSnap::ObjectSnap() {
|
||||
if (!hasBuiltinCompareObjectHandles()) {
|
||||
m_table = queryNtHandles();
|
||||
}
|
||||
}
|
||||
|
||||
bool ObjectSnap::eq(std::initializer_list<RemoteHandle> handles) {
|
||||
if (handles.size() < 2) {
|
||||
return true;
|
||||
}
|
||||
if (hasBuiltinCompareObjectHandles()) {
|
||||
for (auto i = handles.begin() + 1; i < handles.end(); ++i) {
|
||||
if (!compareObjectHandles(*handles.begin(), *i)) {
|
||||
return false;
|
||||
}
|
||||
if (dup2) {
|
||||
CloseHandle(h2local);
|
||||
}
|
||||
} else {
|
||||
HANDLE first = ntHandlePointer(m_table, *handles.begin());
|
||||
for (auto i = handles.begin() + 1; i < handles.end(); ++i) {
|
||||
if (first != ntHandlePointer(m_table, *i)) {
|
||||
return false;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
auto table = queryNtHandles();
|
||||
return ntHandlePointer(table, h1) == ntHandlePointer(table, h2);
|
||||
return true;
|
||||
}
|
||||
|
||||
void registerTest(const std::string &name, bool (&cond)(), void (&func)()) {
|
||||
|
@ -50,8 +50,19 @@ void printTestName(const std::string &name);
|
||||
// NT kernel handle query
|
||||
void *ntHandlePointer(const std::vector<SYSTEM_HANDLE_ENTRY> &table,
|
||||
RemoteHandle h);
|
||||
bool hasBuiltinCompareObjectHandles();
|
||||
bool compareObjectHandles(RemoteHandle h1, RemoteHandle h2);
|
||||
|
||||
// NT kernel handle->object snapshot
|
||||
class ObjectSnap {
|
||||
public:
|
||||
ObjectSnap();
|
||||
bool eq(std::initializer_list<RemoteHandle> handles);
|
||||
bool eq(RemoteHandle h1, RemoteHandle h2) { return eq({h1, h2}); }
|
||||
private:
|
||||
std::vector<SYSTEM_HANDLE_ENTRY> m_table;
|
||||
};
|
||||
|
||||
// Misc
|
||||
std::tuple<RemoteHandle, RemoteHandle> newPipe(
|
||||
RemoteWorker &w, BOOL inheritable=FALSE);
|
||||
|
Loading…
Reference in New Issue
Block a user