// 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 (; nt_status == STATUS_INFO_LENGTH_MISMATCH_; nt_status = workaround::nt_system_query_information( workaround::SystemHandleInformation_, info_pointer, static_cast<::boost::winapi::ULONG_>(buffer.size()), nullptr)) { 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