Skip to content

Commit

Permalink
Add more ConsoleBench tests (microsoft#17441)
Browse files Browse the repository at this point in the history
This now covers all major Console APIs.
In the future we could add tests that cover VT sequences as well.
  • Loading branch information
lhecker authored Jun 22, 2024
1 parent 8511f3d commit bb4981c
Show file tree
Hide file tree
Showing 9 changed files with 588 additions and 152 deletions.
26 changes: 26 additions & 0 deletions src/tools/ConsoleBench/ConsoleBench.exe.manifest
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly
xmlns="urn:schemas-microsoft-com:asm.v1"
xmlns:asm3="urn:schemas-microsoft-com:asm.v3"
xmlns:cv1="urn:schemas-microsoft-com:compatibility.v1"
xmlns:ws="http://schemas.microsoft.com/SMI/2005/WindowsSettings"
xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings"
xmlns:ws3="http://schemas.microsoft.com/SMI/2019/WindowsSettings"
manifestVersion="1.0">
<asm3:application>
<windowsSettings>
<ws2:longPathAware>true</ws2:longPathAware>
<ws3:activeCodePage>UTF-8</ws3:activeCodePage>
</windowsSettings>
</asm3:application>
<cv1:compatibility>
<application>
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
</application>
</cv1:compatibility>
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*" />
</dependentAssembly>
</dependency>
</assembly>
3 changes: 3 additions & 0 deletions src/tools/ConsoleBench/ConsoleBench.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
<ClInclude Include="pch.h" />
<ClInclude Include="utils.h" />
</ItemGroup>
<ItemGroup>
<Manifest Include="ConsoleBench.exe.manifest" />
</ItemGroup>
<ItemDefinitionGroup>
<ClCompile>
<ControlFlowGuard>false</ControlFlowGuard>
Expand Down
5 changes: 5 additions & 0 deletions src/tools/ConsoleBench/ConsoleBench.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,9 @@
<Filter>Source Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Manifest Include="ConsoleBench.exe.manifest">
<Filter>Source Files</Filter>
</Manifest>
</ItemGroup>
</Project>
20 changes: 16 additions & 4 deletions src/tools/ConsoleBench/arena.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ using namespace mem;

Arena::Arena(size_t bytes)
{
m_alloc = static_cast<uint8_t*>(THROW_IF_NULL_ALLOC(VirtualAlloc(nullptr, bytes, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE)));
m_alloc = static_cast<uint8_t*>(THROW_IF_NULL_ALLOC(VirtualAlloc(nullptr, bytes, MEM_RESERVE, PAGE_READWRITE)));
}

Arena::~Arena()
Expand Down Expand Up @@ -41,8 +41,18 @@ void* Arena::_push_raw(size_t bytes, size_t alignment)
{
const auto mask = alignment - 1;
const auto pos = (m_pos + mask) & ~mask;
const auto pos_new = pos + bytes;
const auto ptr = m_alloc + pos;
m_pos = pos + bytes;

if (pos_new > m_commit)
{
// Commit in 1MB chunks and pre-commit 1MiB in advance.
const auto commit_new = (pos_new + 0x1FFFFF) & ~0xFFFFF;
THROW_IF_NULL_ALLOC(VirtualAlloc(m_alloc + m_commit, commit_new - m_commit, MEM_COMMIT, PAGE_READWRITE));
m_commit = commit_new;
}

m_pos = pos_new;
return ptr;
}

Expand Down Expand Up @@ -76,8 +86,8 @@ ScopedArena::~ScopedArena()
static [[msvc::noinline]] std::array<Arena, 2> thread_arenas_init()
{
return {
Arena{ 64 * 1024 * 1024 },
Arena{ 64 * 1024 * 1024 },
Arena{ 1024 * 1024 * 1024 },
Arena{ 1024 * 1024 * 1024 },
};
}

Expand Down Expand Up @@ -166,7 +176,9 @@ std::wstring_view mem::format(Arena& arena, const wchar_t* fmt, va_list args)
return {};
}

// Make space for a terminating \0 character.
len++;

const auto buffer = arena.push_uninitialized<wchar_t>(len);

len = _vsnwprintf(buffer, len, fmt, args);
Expand Down
31 changes: 24 additions & 7 deletions src/tools/ConsoleBench/arena.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ namespace mem
void* _push_uninitialized(size_t bytes, size_t alignment = __STDCPP_DEFAULT_NEW_ALIGNMENT__);

uint8_t* m_alloc = nullptr;
size_t m_commit = 0;
size_t m_pos = 0;
};

Expand Down Expand Up @@ -96,16 +97,32 @@ namespace mem
}

template<typename T>
std::basic_string_view<T> repeat_string(Arena& arena, std::basic_string_view<T> in, size_t count)
auto repeat(Arena& arena, const T& in, size_t count) -> decltype(auto)
{
const auto len = count * in.size();
const auto buf = arena.push_uninitialized<T>(len);

for (size_t i = 0; i < count; ++i)
if constexpr (is_std_view<T>::value)
{
mem::copy(buf + i * in.size(), in.data(), in.size());
const auto data = in.data();
const auto size = in.size();
const auto len = count * size;
const auto buf = arena.push_uninitialized<typename T::value_type>(len);

for (size_t i = 0; i < count; ++i)
{
mem::copy(buf + i * size, data, size);
}

return T{ buf, len };
}
else
{
const auto buf = arena.push_uninitialized<T>(count);

for (size_t i = 0; i < count; ++i)
{
memcpy(buf + i, &in, sizeof(T));
}

return { buf, len };
return std::span{ buf, count };
}
}
}
36 changes: 34 additions & 2 deletions src/tools/ConsoleBench/conhost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <conmsgl1.h>
#include <winternl.h>
#include <wil/win32_helpers.h>

#include "arena.h"

Expand Down Expand Up @@ -46,12 +47,27 @@ static void conhostCopyToStringBuffer(USHORT& length, auto& buffer, const wchar_

ConhostHandle spawn_conhost(mem::Arena& arena, const wchar_t* path)
{
const auto pathLen = wcslen(path);
const auto isDLL = pathLen > 4 && wcscmp(&path[pathLen - 4], L".dll") == 0;

const auto scratch = mem::get_scratch_arena(arena);
const auto server = conhostCreateHandle(nullptr, L"\\Device\\ConDrv\\Server", true, false);
auto server = conhostCreateHandle(nullptr, L"\\Device\\ConDrv\\Server", true, false);
auto reference = conhostCreateHandle(server.get(), L"\\Reference", false, true);

{
const auto cmd = format(scratch.arena, LR"("%s" --server 0x%zx)", path, server.get());
const auto selfPath = scratch.arena.push_uninitialized<wchar_t>(64 * 1024);
GetModuleFileNameW(nullptr, selfPath, 64 * 1024);

std::wstring_view cmd;

if (isDLL)
{
cmd = format(scratch.arena, LR"("%s" host %zx "%s")", selfPath, server.get(), path);
}
else
{
cmd = format(scratch.arena, LR"("%s" --server 0x%zx)", path, server.get());
}

uint8_t attrListBuffer[64];

Expand Down Expand Up @@ -154,6 +170,22 @@ ConhostHandle spawn_conhost(mem::Arena& arena, const wchar_t* path)
};
}

// A continuation of spawn_conhost().
void check_spawn_conhost_dll(int argc, const wchar_t* argv[])
{
if (argc == 4 && wcscmp(argv[1], L"host") == 0)
{
const auto serverHandle = reinterpret_cast<HANDLE>(wcstoull(argv[2], nullptr, 16));
const auto path = argv[3];

using Entrypoint = NTSTATUS(NTAPI*)(HANDLE);
const auto h = THROW_LAST_ERROR_IF_NULL(LoadLibraryExW(path, nullptr, 0));
const auto f = THROW_LAST_ERROR_IF_NULL(reinterpret_cast<Entrypoint>(GetProcAddress(h, "ConsoleCreateIoThread")));
THROW_IF_NTSTATUS_FAILED(f(serverHandle));
ExitThread(S_OK);
}
}

HANDLE get_active_connection()
{
// (Not actually) FUN FACT! The handles don't mean anything and the cake is a lie!
Expand Down
1 change: 1 addition & 0 deletions src/tools/ConsoleBench/conhost.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ struct ConhostHandle
};

ConhostHandle spawn_conhost(mem::Arena& arena, const wchar_t* path);
void check_spawn_conhost_dll(int argc, const wchar_t* argv[]);
HANDLE get_active_connection();
void set_active_connection(HANDLE connection);
Loading

0 comments on commit bb4981c

Please sign in to comment.