From 8004b04e8e66807b8b22044c7dc3aeffebae2896 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 3 May 2022 15:46:45 -0700 Subject: [PATCH 1/5] GH 2697 squashed --- CMakeLists.txt | 19 +- azure-devops/create-prdiff.ps1 | 6 +- azure-pipelines.yml | 39 +- tests/utils/stl/util.py | 2 - tools/CMakeLists.txt | 10 - tools/format/CMakeLists.txt | 6 +- tools/inc/stljobs.h | 632 --------------------------------- tools/jobify/CMakeLists.txt | 4 - tools/jobify/jobify.cpp | 68 ---- tools/validate/CMakeLists.txt | 22 +- 10 files changed, 59 insertions(+), 749 deletions(-) delete mode 100644 tools/inc/stljobs.h delete mode 100644 tools/jobify/CMakeLists.txt delete mode 100644 tools/jobify/jobify.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index bf83f51ae6b..ef897480b06 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,19 @@ cmake_minimum_required(VERSION 3.22) set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) project(msvc_standard_libraries LANGUAGES CXX) +# add the tools subdirectory _before_ we change all the flags +add_subdirectory(tools EXCLUDE_FROM_ALL) +# these allow the targets to show up in the top-level +# (as opposed to under the tools subdirectory) +if(TARGET run-format) + add_custom_target(format) + add_dependencies(format run-format) +endif() +if(TARGET run-validate) + add_custom_target(validate) + add_dependencies(validate run-validate) +endif() + option(BUILD_TESTING "Enable testing" ON) set(VCLIBS_SUFFIX "_oss" CACHE STRING "suffix for built DLL names to avoid conflicts with distributed DLLs") @@ -86,9 +99,3 @@ if(BUILD_TESTING) enable_testing() add_subdirectory(tests) endif() - -add_subdirectory(tools/format EXCLUDE_FROM_ALL) -if(TARGET clang-format-all) - add_custom_target(format) - add_dependencies(format clang-format-all) -endif() diff --git a/azure-devops/create-prdiff.ps1 b/azure-devops/create-prdiff.ps1 index 4d2c004fa6d..d1d33dd5eff 100644 --- a/azure-devops/create-prdiff.ps1 +++ b/azure-devops/create-prdiff.ps1 @@ -3,10 +3,14 @@ [CmdletBinding(PositionalBinding = $False)] Param( - [Parameter(Mandatory = $True)] + [Parameter()] [String]$DiffFile ) +if ([string]::IsNullOrEmpty($DiffFile)) { + $DiffFile = [System.IO.Path]::GetTempFileName() +} + Start-Process -FilePath 'git' -ArgumentList 'diff' ` -NoNewWindow -Wait ` -RedirectStandardOutput $DiffFile diff --git a/azure-pipelines.yml b/azure-pipelines.yml index d7c30ec76f6..01cf59992f8 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -14,11 +14,8 @@ stages: displayName: 'Code Format' jobs: - job: Code_Format_Validation - timeoutInMinutes: 90 + timeoutInMinutes: 20 displayName: 'Validation' - variables: - - name: DiffFile - value: '$(Build.ArtifactStagingDirectory)/format.diff' steps: - script: | if exist "$(tmpDir)" ( @@ -32,30 +29,40 @@ stages: - script: | call "%ProgramFiles%\Microsoft Visual Studio\2022\Preview\Common7\Tools\VsDevCmd.bat" ^ -host_arch=amd64 -arch=amd64 -no_logo - cmake -G Ninja -S $(Build.SourcesDirectory)/tools/format -B $(tmpDir)/format-build - cmake --build $(tmpDir)/format-build - displayName: 'clang-format' + cmake -G Ninja -S $(Build.SourcesDirectory)/tools -B $(tmpDir)/format-validate-build + if %errorlevel% equ 0 cmake --build $(tmpDir)/format-validate-build + if %errorlevel% equ 0 ( + echo ##vso[task.setvariable variable=succeededInBuildingTools]true + ) else ( + echo ##vso[task.setvariable variable=succeededInBuildingTools]false + echo ##vso[task.logissue type=error]Failed to build the tools subproject + ) + displayName: 'Build format and validation' timeoutInMinutes: 5 - condition: succeededOrFailed() env: { TMP: $(tmpDir), TEMP: $(tmpDir) } - script: | call "%ProgramFiles%\Microsoft Visual Studio\2022\Preview\Common7\Tools\VsDevCmd.bat" ^ - -host_arch=amd64 -arch=amd64 -no_logo - cmake -G Ninja -DCMAKE_CXX_COMPILER=cl -DCMAKE_BUILD_TYPE=Release ^ - -S $(Build.SourcesDirectory)/tools/validate -B $(tmpDir)/validate-build - cmake --build $(tmpDir)/validate-build - "$(tmpDir)\validate-build\validate.exe" - displayName: 'Validate Files' + -host_arch=amd64 -arch=amd64 -no_logo + cmake --build $(tmpDir)/format-validate-build --target run-format + displayName: 'clang-format Files' timeoutInMinutes: 5 - condition: succeededOrFailed() + condition: eq(variables.succeededInBuildingTools, 'true') + env: { TMP: $(tmpDir), TEMP: $(tmpDir) } + - script: | + call "%ProgramFiles%\Microsoft Visual Studio\2022\Preview\Common7\Tools\VsDevCmd.bat" ^ + -host_arch=amd64 -arch=amd64 -no_logo + cmake --build $(tmpDir)/format-validate-build --target run-validate + displayName: 'Validate Files' + timeoutInMinutes: 2 + condition: eq(variables.succeededInBuildingTools, 'true') env: { TMP: $(tmpDir), TEMP: $(tmpDir) } - task: Powershell@2 displayName: 'Create Diff' inputs: filePath: azure-devops/create-prdiff.ps1 - arguments: '-DiffFile $(DiffFile)' pwsh: false condition: succeededOrFailed() + env: { TMP: $(tmpDir), TEMP: $(tmpDir) } - stage: Build_And_Test_x64 dependsOn: Code_Format diff --git a/tests/utils/stl/util.py b/tests/utils/stl/util.py index e1b3b07760e..c025f4b0ab4 100644 --- a/tests/utils/stl/util.py +++ b/tests/utils/stl/util.py @@ -153,8 +153,6 @@ def killProcessAndChildren(pid): running children (recursively). It is currently implemented using the psutil module which provides a simple platform neutral implementation. - - TRANSITION: Jobify this """ if platform.system() == 'AIX': subprocess.call('kill -kill $(ps -o pid= -L{})'.format(pid), diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 5d4089779e6..c7a63ec7f93 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -4,15 +4,5 @@ cmake_minimum_required(VERSION 3.22) project(msvc_standard_libraries_tools LANGUAGES CXX) -set(CMAKE_CXX_STANDARD 20) -set(CMAKE_CXX_STANDARD_REQUIRED True) -set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") - -add_compile_definitions(NOMINMAX UNICODE _UNICODE) -add_compile_options(/W4 /WX $<$>:/Zi> /permissive-) - -include_directories(inc) - add_subdirectory(format) -add_subdirectory(jobify) add_subdirectory(validate) diff --git a/tools/format/CMakeLists.txt b/tools/format/CMakeLists.txt index 70d35bbd25d..d1af0734451 100644 --- a/tools/format/CMakeLists.txt +++ b/tools/format/CMakeLists.txt @@ -50,7 +50,7 @@ if(CLANG_FORMAT) message("${message_level}" "Could not find any files to clang-format!") endif() - add_custom_target(clang-format-all ALL) + add_custom_target(run-format) foreach(file IN LISTS clang_format_files) cmake_path(RELATIVE_PATH file BASE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/../.." @@ -60,9 +60,9 @@ if(CLANG_FORMAT) set(target_name "clang-format.${relative-file}") add_custom_target("${target_name}" COMMAND "${CLANG_FORMAT}" -style=file -i "${file}" - WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" + WORKING_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/../.." ) - add_dependencies(clang-format-all "${target_name}") + add_dependencies(run-format "${target_name}") endforeach() else() if(did_search) diff --git a/tools/inc/stljobs.h b/tools/inc/stljobs.h deleted file mode 100644 index 9167cc60860..00000000000 --- a/tools/inc/stljobs.h +++ /dev/null @@ -1,632 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -struct api_exception : std::exception { - const char* api; - unsigned long lastError; - - explicit api_exception(const char* const api_, const unsigned long lastError_) noexcept - : api(api_), lastError(lastError_) {} - - [[noreturn]] void give_up() const { - fflush(stdout); - fprintf(stderr, "The API \"%s\" failed unexpectedly; last error 0x%08lX\n", api, lastError); - abort(); - } - - [[nodiscard]] const char* what() const noexcept override { - return "win32 exception"; - } -}; - -[[noreturn]] inline void api_failure(const char* const api, const unsigned long lastError = GetLastError()) { - throw api_exception{api, lastError}; -} - -void close_handle(const HANDLE toClose) noexcept { - if (!CloseHandle(toClose)) { - assert(false); - } -} - -struct invalid_handle_value_policy { - static constexpr HANDLE Empty = INVALID_HANDLE_VALUE; -}; - -struct null_handle_policy { - static constexpr HANDLE Empty{}; -}; - -template -class handle { -public: - handle() = default; - - explicit handle(const HANDLE hInitial) noexcept : impl(hInitial) {} - - handle(handle&& other) noexcept : impl(std::exchange(other.impl, EmptyPolicy::Empty)) {} - - handle& operator=(handle&& other) noexcept { - handle moved = std::move(other); - swap(moved, *this); - return *this; - } - - ~handle() noexcept { - if (impl != EmptyPolicy::Empty) { - close_handle(impl); - } - } - - friend void swap(handle& lhs, handle& rhs) noexcept { - using std::swap; - swap(lhs.impl, rhs.impl); - } - - void close() noexcept { - if (impl != EmptyPolicy::Empty) { - close_handle(impl); - impl = EmptyPolicy::Empty; - } - } - - [[nodiscard]] explicit operator bool() const noexcept { - return impl != EmptyPolicy::Empty; - } - - [[nodiscard]] HANDLE get() const noexcept { - return impl; - } - - void attach(const HANDLE newHandle) & noexcept { - handle captured{newHandle}; - swap(captured, *this); - } - - [[nodiscard]] HANDLE detach() noexcept { - return std::exchange(impl, EmptyPolicy::Empty); - } - -private: - HANDLE impl{EmptyPolicy::Empty}; -}; - -inline handle create_file(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, - LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, - HANDLE hTemplateFile) { - handle result{CreateFileW(lpFileName, dwDesiredAccess, dwShareMode, - lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile)}; - if (!result) { - api_failure("CreateFileW"); - } - - return result; -} - -inline handle create_event( - LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCWSTR lpName) { - handle result{CreateEventW(lpEventAttributes, bManualReset, bInitialState, lpName)}; - if (!result) { - api_failure("CreateEventW"); - } - - return result; -} - -inline handle create_named_pipe(LPCWSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, - DWORD nMaxInstances, DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut, - LPSECURITY_ATTRIBUTES lpSecurityAttributes) { - handle result{CreateNamedPipeW(lpName, dwOpenMode, dwPipeMode, nMaxInstances, - nOutBufferSize, nInBufferSize, nDefaultTimeOut, lpSecurityAttributes)}; - if (!result) { - api_failure("CreateNamedPipeW"); - } - - return result; -} - - -const auto is_exactly_space = [](const wchar_t c) { return c == L' '; }; - -[[nodiscard]] inline handle create_job_that_will_be_killed_when_closed() { - handle hJob{CreateJobObjectW(nullptr, nullptr)}; - if (!hJob) { - api_failure("CreateJobObjectW"); - } - - JOBOBJECT_EXTENDED_LIMIT_INFORMATION limits{}; - limits.BasicLimitInformation.LimitFlags = - JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION; - if (!SetInformationJobObject(hJob.get(), JobObjectExtendedLimitInformation, &limits, sizeof(limits))) { - api_failure("SetInformationJobObject"); - } - - return hJob; -} - -inline void put_self_in_job() { - auto hJob = create_job_that_will_be_killed_when_closed(); - - // Put ourselves in that job - if (!AssignProcessToJobObject(hJob.get(), GetCurrentProcess())) { - api_failure("AssignProcessToJobObject"); - } - - // Purposely leak hJob to avoid terminating ourselves - (void) hJob.detach(); -} - -class no_input_pipe { -public: - no_input_pipe() { - SECURITY_ATTRIBUTES inheritSa; - inheritSa.nLength = sizeof(inheritSa); - inheritSa.lpSecurityDescriptor = nullptr; - inheritSa.bInheritHandle = TRUE; - HANDLE read; - HANDLE write; - if (!CreatePipe(&read, &write, &inheritSa, 0)) { - api_failure("CreatePipe"); - } - - devNull.attach(write); - close_handle(read); - } - - no_input_pipe(const no_input_pipe&) = delete; - no_input_pipe& operator=(const no_input_pipe&) = delete; - - [[nodiscard]] HANDLE get() const noexcept { - return devNull.get(); - } - - [[nodiscard]] static const no_input_pipe& instance() { - static no_input_pipe instance_; - return instance_; - } - -private: - handle devNull; -}; - -class tp_io { -public: - tp_io() = default; - - explicit tp_io(handle&& fileHandle_, const PTP_WIN32_IO_CALLBACK callback, - void* const pv, const PTP_CALLBACK_ENVIRON pcbe = nullptr) - : io(CreateThreadpoolIo(fileHandle_.get(), callback, pv, pcbe)) { - if (!io) { - api_failure("CreateThreadpoolIo"); - } - - fileHandle = std::move(fileHandle_); - } - - tp_io(tp_io&& other) noexcept : fileHandle(std::move(other.fileHandle)), io(std::exchange(other.io, nullptr)) {} - - ~tp_io() { - if (io != nullptr) { - close(); - } - } - - friend void swap(tp_io& lhs, tp_io& rhs) noexcept { - using std::swap; - swap(lhs.fileHandle, rhs.fileHandle); - swap(lhs.io, rhs.io); - } - - tp_io& operator=(tp_io&& other) noexcept { - tp_io moved{std::move(other)}; - swap(moved, *this); - return *this; - } - - [[nodiscard]] HANDLE get_file() const noexcept { - return fileHandle.get(); - } - - void start_threadpool_io() noexcept { - StartThreadpoolIo(io); - } - - void cancel_threadpool_io() noexcept { - CancelThreadpoolIo(io); - } - - [[nodiscard]] explicit operator bool() const noexcept { - return io != nullptr; - } - - handle close() noexcept { - assert(io != nullptr); - WaitForThreadpoolIoCallbacks(io, TRUE); - CloseThreadpoolIo(io); - io = nullptr; - return std::move(fileHandle); - } - - void wait(const bool cancelPending) noexcept { - WaitForThreadpoolIoCallbacks(io, cancelPending); - } - -private: - handle fileHandle{}; - PTP_IO io{}; -}; - -struct output_collecting_pipe { - static constexpr unsigned long kernelBufferSize = 4096; - static constexpr unsigned long bufferSize = 4096; - - output_collecting_pipe() { - // generate a random name for the pipe (we must use a named pipe because anonymous pipes from CreatePipe can't - // be used in asynchronous mode) - std::random_device rd; - constexpr size_t pipeNameBufferCount = 15 + 8 * 8 + 1; - // 123456789012345 - wchar_t pipeNameBuffer[pipeNameBufferCount] = LR"(\\.\pipe\Local\)"; - wchar_t* pipeNameCursor = pipeNameBuffer + 15; - for (int values = 0; values < 8; ++values) { - unsigned int randomValue = rd(); - for (int hexits = 0; hexits < 8; ++hexits) { - *pipeNameCursor++ = L"0123456789ABCDEF"[randomValue & 0xFu]; - randomValue >>= 4; - } - } - - *pipeNameCursor = L'\0'; - - auto readHandle = create_named_pipe(pipeNameBuffer, - PIPE_ACCESS_INBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED, - PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS, 1, 0, kernelBufferSize, 0, - nullptr); - - if (!SetFileCompletionNotificationModes( - readHandle.get(), FILE_SKIP_COMPLETION_PORT_ON_SUCCESS | FILE_SKIP_SET_EVENT_ON_HANDLE)) { - api_failure("SetFileCompletionNotificationModes"); - } - - SECURITY_ATTRIBUTES inheritSa; - inheritSa.nLength = sizeof(inheritSa); - inheritSa.lpSecurityDescriptor = nullptr; - inheritSa.bInheritHandle = TRUE; - writeHandle = create_file(pipeNameBuffer, GENERIC_WRITE | FILE_READ_ATTRIBUTES, 0, &inheritSa, OPEN_EXISTING, - FILE_FLAG_OVERLAPPED, HANDLE{}); - - readEvent = create_event(nullptr, TRUE, FALSE, nullptr); - overlapped.hEvent = readEvent.get(); - - readIo = tp_io{std::move(readHandle), callback, this, nullptr}; - - start(); - } - - ~output_collecting_pipe() noexcept { - if (readIo) { - if (running.exchange(false)) { // prevent callback() from calling read_some() - if (!CancelIoEx(readIo.get_file(), &overlapped)) { - api_failure("CancelIoEx"); // slams into noexcept - } - } - - readIo.close(); - } - } - - output_collecting_pipe(const output_collecting_pipe&) = delete; - output_collecting_pipe& operator=(const output_collecting_pipe&) = delete; - - void start() { - [[maybe_unused]] const bool oldRunning = running.exchange(true); - assert(!oldRunning); - read_some(); - } - - void stop() { - if (running.exchange(false)) { - if (!CancelIoEx(readIo.get_file(), &overlapped)) { - api_failure("CancelIoEx"); - } - - readIo.wait(false); - } - } - - [[nodiscard]] std::string extract_and_reset() { - stop(); - auto first = targetBuffer.data(); - auto last = first + validTill; - first = std::find_if_not(first, last, is_exactly_space); - last = std::find_if_not(std::reverse_iterator(last), std::reverse_iterator(first), is_exactly_space).base(); - std::string result(first, static_cast(last - first)); - validTill = 0; - start(); - return result; - } - - [[nodiscard]] HANDLE get_write_pipe() noexcept { - return writeHandle.get(); - } - -private: - static void __stdcall callback(PTP_CALLBACK_INSTANCE, void* const thisRaw, void*, const ULONG ioResult, - const ULONG_PTR bytes, PTP_IO) noexcept { - switch (ioResult) { - case ERROR_SUCCESS: - case ERROR_OPERATION_ABORTED: - break; - default: - api_failure("StartThreadpoolIo + ReadFile callback", ioResult); // slams into noexcept - break; - } - - const auto this_ = static_cast(thisRaw); - this_->validTill += bytes; - if (this_->running.load()) { - this_->read_some(); - } - } - - void ensure_target_buffer_space() { - if (bufferSize <= targetBuffer.size() - validTill) { - // already has enough space - return; - } - - targetBuffer.resize(validTill + bufferSize); - targetBuffer.resize(std::min(static_cast(ULONG_MAX), targetBuffer.capacity())); - } - - void read_some() { - assert(running.load()); - DWORD bytesRead = 0; - readIo.start_threadpool_io(); - for (;;) { - ensure_target_buffer_space(); - if (!ReadFile(readIo.get_file(), targetBuffer.data() + validTill, - static_cast(targetBuffer.size() - validTill), &bytesRead, &overlapped)) { - break; - } - - validTill += bytesRead; - } - - const auto lastError = GetLastError(); - if (lastError == ERROR_IO_PENDING) { - return; - } - - readIo.cancel_threadpool_io(); - api_failure("ReadFile", lastError); - } - - std::atomic running{}; - std::string targetBuffer; // if running, owned by a threadpool thread, otherwise owned by the calling thread - size_t validTill{}; - handle writeHandle; - handle readEvent; - tp_io readIo; - OVERLAPPED overlapped{}; -}; - -struct execution_result { - unsigned long exitCode; - std::string output; -}; - -class environment_block { -public: - environment_block() { - default_block defaultBlock; - auto blockEnd = static_cast(defaultBlock.blockRaw); - for (;;) { - const auto thisLen = wcslen(blockEnd); - blockEnd += thisLen; - ++blockEnd; - - if (thisLen == 0) { - break; - } - } - - block.assign(static_cast(defaultBlock.blockRaw), blockEnd); - } - - [[nodiscard]] void* get() noexcept { - return block.data(); - } - - void append_environment(const std::wstring_view key, const std::wstring_view value) { - block.reserve(block.size() + key.size() + value.size() + 2); - block.append(key); - block.push_back('='); - block.append(value); - block.push_back('\0'); - } - -private: - struct default_block { - void* blockRaw; - default_block() { - if (!CreateEnvironmentBlock(&blockRaw, HANDLE{}, FALSE)) { - api_failure("CreateEnvironmentBlock"); - } - } - - ~default_block() noexcept { - if (!DestroyEnvironmentBlock(blockRaw)) { - api_failure("DestroyEnvironmentBlock"); // slams into noexcept - } - } - - default_block(const default_block&) = delete; - default_block& operator=(const default_block&) = delete; - }; - - std::wstring block; -}; - -struct create_process_result { - handle hProcess; - handle hThread; - unsigned long dwProcessId; - unsigned long dwThreadId; -}; - -inline create_process_result create_process(LPCWSTR lpApplicationName, LPWSTR lpCommandLine, - LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, - DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo) { - PROCESS_INFORMATION procInfo; - if (!CreateProcessW(lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, - dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, &procInfo)) { - api_failure("CreateProcessW"); - } - - return {handle{procInfo.hProcess}, handle{procInfo.hThread}, - procInfo.dwProcessId, procInfo.dwThreadId}; -} - -class thread_proc_attribute_list { -public: - thread_proc_attribute_list() = default; - thread_proc_attribute_list(thread_proc_attribute_list&&) = default; - thread_proc_attribute_list& operator=(thread_proc_attribute_list&&) = default; - - explicit thread_proc_attribute_list(const unsigned long attributeCount) { - SIZE_T size; - if (InitializeProcThreadAttributeList(nullptr, attributeCount, 0, &size)) { - fputs("First call to InitializeProcThreadAttributeList should not succeed.", stderr); - abort(); - } - - const auto lastError = GetLastError(); - if (lastError != ERROR_INSUFFICIENT_BUFFER) { - api_failure("InitializeProcThreadAttributeList", lastError); - } - - buffer = std::make_unique(size); - if (!InitializeProcThreadAttributeList( - reinterpret_cast(buffer.get()), attributeCount, 0, &size)) { - api_failure("InitializeProcThreadAttributeList"); - } - } - - ~thread_proc_attribute_list() { - DeleteProcThreadAttributeList(reinterpret_cast(buffer.get())); - } - - void update_attribute(DWORD_PTR Attribute, PVOID lpValue, SIZE_T cbSize) { - if (!UpdateProcThreadAttribute(reinterpret_cast(buffer.get()), 0, Attribute, - lpValue, cbSize, nullptr, nullptr)) { - api_failure("UpdateProcThreadAttribute"); - } - } - - [[nodiscard]] LPPROC_THREAD_ATTRIBUTE_LIST get() const noexcept { - return reinterpret_cast(buffer.get()); - } - -private: - std::unique_ptr buffer; -}; - -struct subprocess_executive { - subprocess_executive() = default; - explicit subprocess_executive(const environment_block& environment_) : environment(environment_) {} - explicit subprocess_executive(environment_block&& environment_) : environment(std::move(environment_)) {} - - [[nodiscard]] HANDLE get_wait_handle() const noexcept { - return runningProcess.get(); - } - - void begin_execution(const wchar_t* const applicationName, wchar_t* const commandLine, - const unsigned long creationFlags = 0, const wchar_t* const currentDirectory = nullptr) { - thread_proc_attribute_list procAttributeList{2}; - - // only inherit these pipe handles, not other handles that might be concurrently in use in this program - HANDLE inheritTheseHandles[] = {no_input_pipe::instance().get(), output.get_write_pipe()}; - procAttributeList.update_attribute( - PROC_THREAD_ATTRIBUTE_HANDLE_LIST, &inheritTheseHandles, sizeof(inheritTheseHandles)); - - // turn on all reasonable corruption detecting mitigations - unsigned long long mitigations = PROCESS_CREATION_MITIGATION_POLICY_DEP_ENABLE - | PROCESS_CREATION_MITIGATION_POLICY_SEHOP_ENABLE - | PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON_REQ_RELOCS - | PROCESS_CREATION_MITIGATION_POLICY_HEAP_TERMINATE_ALWAYS_ON - | PROCESS_CREATION_MITIGATION_POLICY_BOTTOM_UP_ASLR_ALWAYS_ON - | PROCESS_CREATION_MITIGATION_POLICY_HIGH_ENTROPY_ASLR_ALWAYS_ON - | PROCESS_CREATION_MITIGATION_POLICY_STRICT_HANDLE_CHECKS_ALWAYS_ON - | PROCESS_CREATION_MITIGATION_POLICY_WIN32K_SYSTEM_CALL_DISABLE_ALWAYS_ON - | PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE_ALWAYS_ON - | PROCESS_CREATION_MITIGATION_POLICY_CONTROL_FLOW_GUARD_ALWAYS_ON - | PROCESS_CREATION_MITIGATION_POLICY_PROHIBIT_DYNAMIC_CODE_ALWAYS_ON - | PROCESS_CREATION_MITIGATION_POLICY_FONT_DISABLE_ALWAYS_ON - | PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_REMOTE_ALWAYS_ON - | PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_LOW_LABEL_ALWAYS_ON; - procAttributeList.update_attribute(PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, &mitigations, sizeof(mitigations)); - - STARTUPINFOEXW startupInfo{}; - startupInfo.StartupInfo.cb = sizeof(startupInfo); - startupInfo.StartupInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; - startupInfo.StartupInfo.hStdInput = inheritTheseHandles[0]; - startupInfo.StartupInfo.hStdOutput = inheritTheseHandles[1]; - startupInfo.StartupInfo.hStdError = inheritTheseHandles[1]; - startupInfo.StartupInfo.wShowWindow = SW_HIDE; - startupInfo.lpAttributeList = procAttributeList.get(); - - runningJob = create_job_that_will_be_killed_when_closed(); - - auto procInfo = create_process(applicationName, commandLine, nullptr, nullptr, TRUE, - creationFlags | CREATE_UNICODE_ENVIRONMENT | CREATE_SUSPENDED, environment.get(), currentDirectory, - &startupInfo.StartupInfo); - - runningProcess = std::move(procInfo.hProcess); - if (!AssignProcessToJobObject(runningJob.get(), runningProcess.get())) { - api_failure("AssignProcessToJobObject"); - } - - if (ResumeThread(procInfo.hThread.get()) == static_cast(-1)) { - api_failure("ResumeThread"); - } - } - - execution_result complete() { - DWORD exitCode; - if (!GetExitCodeProcess(runningProcess.get(), &exitCode)) { - api_failure("GetExitCodeProcess"); - } - - runningProcess.close(); - runningJob.close(); - - return {exitCode, output.extract_and_reset()}; - } - -private: - output_collecting_pipe output; - environment_block environment; - handle runningProcess; - handle runningJob; -}; diff --git a/tools/jobify/CMakeLists.txt b/tools/jobify/CMakeLists.txt deleted file mode 100644 index fcd69f7264f..00000000000 --- a/tools/jobify/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -add_executable(jobify jobify.cpp ../inc/stljobs.h) diff --git a/tools/jobify/jobify.cpp b/tools/jobify/jobify.cpp deleted file mode 100644 index 150cea6ede5..00000000000 --- a/tools/jobify/jobify.cpp +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#include "stljobs.h" -#include -#include -#include - -#include - -// Gets the command line with the path to jobify.exe removed from the beginning. -[[nodiscard]] wchar_t* get_subcommand() { - auto first = GetCommandLineW(); - const auto last = first + wcslen(first); - first = std::find_if_not(first, last, is_exactly_space); // skip leading whitespace - if (first != last) { - if (*first == '"') { - // assumes no escaped quotes in path - ++first; - first = std::find(first, last, L'"'); - if (first != last) { - ++first; - } - } else { - first = std::find_if(first, last, is_exactly_space); - } - - first = std::find_if_not(first, last, is_exactly_space); - } - - return first; -} - -int main() { - try { - const auto subcommand = get_subcommand(); - if (*subcommand) { - put_self_in_job(); - printf("[jobify] Executing: %ls\n", subcommand); - fflush(stdout); - - STARTUPINFOW si{}; - si.cb = sizeof(si); - auto processInfo = create_process( - nullptr, subcommand, nullptr, nullptr, TRUE, INHERIT_PARENT_AFFINITY, nullptr, nullptr, &si); - - processInfo.hThread.close(); - if (WaitForSingleObject(processInfo.hProcess.get(), INFINITE) != WAIT_OBJECT_0) { - api_failure("WaitForSingleObject"); - } - - unsigned long exitCode; - if (!GetExitCodeProcess(processInfo.hProcess.get(), &exitCode)) { - api_failure("GetExitCodeProcess"); - } - - printf("[jobify] Command exited with 0x%lX\n", exitCode); - - return static_cast(exitCode); - } - - puts("[jobify] Usage: jobify.exe subcommand"); - puts("[jobify] No command supplied, terminating."); - return 1; - } catch (api_exception& api) { - api.give_up(); - } -} diff --git a/tools/validate/CMakeLists.txt b/tools/validate/CMakeLists.txt index 81909e1f394..7d1f8021deb 100644 --- a/tools/validate/CMakeLists.txt +++ b/tools/validate/CMakeLists.txt @@ -4,12 +4,20 @@ cmake_minimum_required(VERSION 3.22) project(msvc_standard_libraries_validate LANGUAGES CXX) -set(CMAKE_CXX_STANDARD 20) -set(CMAKE_CXX_STANDARD_REQUIRED True) -set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") - -add_compile_definitions(NOMINMAX UNICODE _UNICODE) +add_executable(validate-binary validate.cpp) # we use SAL annotations, so pass /analyze -add_compile_options(/W4 /WX $<$>:/Zi> /permissive- /analyze) +target_compile_options(validate-binary PRIVATE /W4 /WX $<$>:/Zi> /permissive- /analyze /EHsc) +set_target_properties(validate-binary + PROPERTIES + # use -std:c++20 -permissive- + CXX_STANDARD 20 + CXX_EXTENSIONS OFF + CXX_STANDARD_REQUIRED ON + # statically link the standard library + MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>" +) -add_executable(validate validate.cpp) +add_custom_target(run-validate + COMMAND validate-binary + WORKING_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/../.." +) From 376824a1357e1e0a5d07f7bf85018b759634bfe7 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 3 May 2022 15:57:10 -0700 Subject: [PATCH 2/5] Damage clang-format. --- stl/inc/vector | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/vector b/stl/inc/vector index 29e592a755a..e7d7f413e34 100644 --- a/stl/inc/vector +++ b/stl/inc/vector @@ -31,8 +31,8 @@ public: using iterator_category = random_access_iterator_tag; using value_type = typename _Myvec::value_type; using difference_type = typename _Myvec::difference_type; - using pointer = typename _Myvec::const_pointer; - using reference = const value_type&; + using pointer = typename _Myvec::const_pointer; + using reference = const value_type&; using _Tptr = typename _Myvec::pointer; From 8f007e0495d1585938bc8a974ce35c7164d6c82b Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 3 May 2022 15:57:51 -0700 Subject: [PATCH 3/5] Damage validate. --- stl/inc/bitset | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/bitset b/stl/inc/bitset index ad507f5b72d..2c85958ff3e 100644 --- a/stl/inc/bitset +++ b/stl/inc/bitset @@ -21,7 +21,7 @@ _STL_DISABLE_CLANG_WARNINGS _STD_BEGIN template -class bitset { // store fixed-length sequence of Boolean elements +class bitset { // 😸 store fixed-length sequence of Boolean elements public: #pragma warning(push) #pragma warning(disable : 4296) // expression is always true (/Wall) From 7a181acbf966835599b7b3b2a0a06a69ea844da8 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 3 May 2022 16:10:25 -0700 Subject: [PATCH 4/5] Simplify tools/validate/CMakeLists.txt. --- tools/validate/CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/validate/CMakeLists.txt b/tools/validate/CMakeLists.txt index 7d1f8021deb..f18374bc8d4 100644 --- a/tools/validate/CMakeLists.txt +++ b/tools/validate/CMakeLists.txt @@ -6,10 +6,9 @@ project(msvc_standard_libraries_validate LANGUAGES CXX) add_executable(validate-binary validate.cpp) # we use SAL annotations, so pass /analyze -target_compile_options(validate-binary PRIVATE /W4 /WX $<$>:/Zi> /permissive- /analyze /EHsc) +target_compile_options(validate-binary PRIVATE /W4 /WX /analyze) set_target_properties(validate-binary PROPERTIES - # use -std:c++20 -permissive- CXX_STANDARD 20 CXX_EXTENSIONS OFF CXX_STANDARD_REQUIRED ON From 79c768661c0630d1df033583840eeb7df77ae7e5 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 3 May 2022 16:23:43 -0700 Subject: [PATCH 5/5] Simplify azure-pipelines.yml. --- azure-pipelines.yml | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 01cf59992f8..bf05dbc3493 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -30,13 +30,7 @@ stages: call "%ProgramFiles%\Microsoft Visual Studio\2022\Preview\Common7\Tools\VsDevCmd.bat" ^ -host_arch=amd64 -arch=amd64 -no_logo cmake -G Ninja -S $(Build.SourcesDirectory)/tools -B $(tmpDir)/format-validate-build - if %errorlevel% equ 0 cmake --build $(tmpDir)/format-validate-build - if %errorlevel% equ 0 ( - echo ##vso[task.setvariable variable=succeededInBuildingTools]true - ) else ( - echo ##vso[task.setvariable variable=succeededInBuildingTools]false - echo ##vso[task.logissue type=error]Failed to build the tools subproject - ) + cmake --build $(tmpDir)/format-validate-build displayName: 'Build format and validation' timeoutInMinutes: 5 env: { TMP: $(tmpDir), TEMP: $(tmpDir) } @@ -46,7 +40,6 @@ stages: cmake --build $(tmpDir)/format-validate-build --target run-format displayName: 'clang-format Files' timeoutInMinutes: 5 - condition: eq(variables.succeededInBuildingTools, 'true') env: { TMP: $(tmpDir), TEMP: $(tmpDir) } - script: | call "%ProgramFiles%\Microsoft Visual Studio\2022\Preview\Common7\Tools\VsDevCmd.bat" ^ @@ -54,7 +47,6 @@ stages: cmake --build $(tmpDir)/format-validate-build --target run-validate displayName: 'Validate Files' timeoutInMinutes: 2 - condition: eq(variables.succeededInBuildingTools, 'true') env: { TMP: $(tmpDir), TEMP: $(tmpDir) } - task: Powershell@2 displayName: 'Create Diff'