diff options
Diffstat (limited to 'boost/process/detail/windows/handles.hpp')
-rw-r--r-- | boost/process/detail/windows/handles.hpp | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/boost/process/detail/windows/handles.hpp b/boost/process/detail/windows/handles.hpp new file mode 100644 index 0000000000..5ba5780e9f --- /dev/null +++ b/boost/process/detail/windows/handles.hpp @@ -0,0 +1,176 @@ +// Copyright (c) 2019 Klemens D. Morgenstern +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_PROCESS_DETAIL_WINDOWS_HANDLES_HPP_ +#define BOOST_PROCESS_DETAIL_WINDOWS_HANDLES_HPP_ + +#include <vector> +#include <system_error> +#include <boost/process/detail/windows/handle_workaround.hpp> +#include <boost/process/detail/windows/handler.hpp> +#include <boost/winapi/get_current_process_id.hpp> + +namespace boost { namespace process { namespace detail { + + +template<typename Executor, typename Function> +void foreach_used_handle(Executor &exec, Function &&func); + + +namespace windows { + + +using native_handle_type = ::boost::winapi::HANDLE_ ; + +inline std::vector<native_handle_type> get_handles(std::error_code & ec) +{ + auto pid = ::boost::winapi::GetCurrentProcessId(); + + std::vector<char> buffer(2048); + constexpr static auto STATUS_INFO_LENGTH_MISMATCH_ = static_cast<::boost::winapi::NTSTATUS_>(0xC0000004l); + auto info_pointer = reinterpret_cast<workaround::SYSTEM_HANDLE_INFORMATION_*>(buffer.data()); + + ::boost::winapi::NTSTATUS_ nt_status = STATUS_INFO_LENGTH_MISMATCH_; + + for (int cnt = 0; + nt_status == STATUS_INFO_LENGTH_MISMATCH_; + nt_status = workaround::nt_system_query_information( + workaround::SystemHandleInformation_, + info_pointer, buffer.size(), + NULL)) + { + buffer.resize(buffer.size() * 2); + info_pointer = reinterpret_cast<workaround::SYSTEM_HANDLE_INFORMATION_*>(buffer.data()); + } + + + if (nt_status < 0 || nt_status > 0x7FFFFFFF) + { + ec = ::boost::process::detail::get_last_error(); + return {}; + } + else + ec.clear(); + + std::vector<native_handle_type> res; + for (auto itr = info_pointer->Handle; itr != (info_pointer->Handle + info_pointer->Count); itr++) + { + if (itr->OwnerPid == pid) + res.push_back(reinterpret_cast<native_handle_type>(static_cast<std::uintptr_t>(itr->HandleValue))); + } + + return res; +} + +inline std::vector<native_handle_type> get_handles() +{ + std::error_code ec; + + auto res = get_handles(ec); + if (ec) + boost::process::detail::throw_error(ec, "NtQuerySystemInformation failed"); + + return res; +} + + +inline bool is_stream_handle(native_handle_type handle, std::error_code & ec) +{ + ::boost::winapi::ULONG_ actual_size; + auto nt_status = workaround::nt_query_object( + handle, + workaround::ObjectTypeInformation, + NULL, + 0, &actual_size); + + std::vector<char> vec; + vec.resize(actual_size); + + workaround::OBJECT_TYPE_INFORMATION_ * type_info_p = reinterpret_cast<workaround::OBJECT_TYPE_INFORMATION_*>(vec.data()); + nt_status = workaround::nt_query_object( + handle, + workaround::ObjectTypeInformation, + type_info_p, + actual_size, &actual_size); + + if (nt_status < 0 || nt_status > 0x7FFFFFFF) + { + ec = ::boost::process::detail::get_last_error(); + return false; + } + else + ec.clear(); + + auto &nm = type_info_p->TypeName.Buffer; + return type_info_p->TypeName.Length >= 5 && + nm[0] == L'F' && + nm[1] == L'i' && + nm[2] == L'l' && + nm[3] == L'e' && + nm[4] == L'\0'; +} + + +inline bool is_stream_handle(native_handle_type handle) +{ + std::error_code ec; + auto res = is_stream_handle(handle, ec); + if (ec) + boost::process::detail::throw_error(ec, "NtQueryObject failed"); + + return res; +} + + +struct limit_handles_ : handler_base_ext +{ + mutable std::vector<::boost::winapi::HANDLE_> handles_with_inherit_flag; + + template<typename Executor> + void on_setup(Executor & exec) const + { + auto all_handles = get_handles(); + foreach_used_handle(exec, + [&](::boost::winapi::HANDLE_ handle) + { + auto itr = std::find(all_handles.begin(), all_handles .end(), handle); + DWORD flags = 0u; + if (itr != all_handles.end()) + *itr = ::boost::winapi::INVALID_HANDLE_VALUE_; + else if ((::boost::winapi::GetHandleInformation(*itr, &flags) != 0) + &&((flags & ::boost::winapi::HANDLE_FLAG_INHERIT_) == 0)) //it is NOT inherited anyhow, so ignore too + *itr = ::boost::winapi::INVALID_HANDLE_VALUE_; + }); + + auto part_itr = std::partition(all_handles.begin(), all_handles.end(), + [](::boost::winapi::HANDLE_ handle) {return handle != ::boost::winapi::INVALID_HANDLE_VALUE_;}); + + all_handles.erase(part_itr, all_handles.end()); //remove invalid handles + handles_with_inherit_flag = std::move(all_handles); + + for (auto handle : handles_with_inherit_flag) + ::boost::winapi::SetHandleInformation(handle, ::boost::winapi::HANDLE_FLAG_INHERIT_, 0); + } + + template<typename Executor> + void on_error(Executor & exec, const std::error_code & ec) const + { + for (auto handle : handles_with_inherit_flag) + ::boost::winapi::SetHandleInformation(handle, ::boost::winapi::HANDLE_FLAG_INHERIT_, ::boost::winapi::HANDLE_FLAG_INHERIT_); + } + + template<typename Executor> + void on_sucess(Executor & exec) const + { + for (auto handle : handles_with_inherit_flag) + ::boost::winapi::SetHandleInformation(handle, ::boost::winapi::HANDLE_FLAG_INHERIT_, ::boost::winapi::HANDLE_FLAG_INHERIT_); + } + +}; + + +}}}} + +#endif //PROCESS_HANDLES_HPP |