handles.hpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. // Copyright (c) 2019 Klemens D. Morgenstern
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  4. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. #ifndef BOOST_PROCESS_DETAIL_WINDOWS_HANDLES_HPP_
  6. #define BOOST_PROCESS_DETAIL_WINDOWS_HANDLES_HPP_
  7. #include <vector>
  8. #include <system_error>
  9. #include <boost/process/v1/detail/windows/handle_workaround.hpp>
  10. #include <boost/process/v1/detail/windows/handler.hpp>
  11. #include <boost/winapi/get_current_process_id.hpp>
  12. #include <boost/winapi/handles.hpp>
  13. #include <boost/winapi/handle_info.hpp>
  14. namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail {
  15. template<typename Executor, typename Function>
  16. void foreach_used_handle(Executor &exec, Function &&func);
  17. namespace windows {
  18. using native_handle_type = ::boost::winapi::HANDLE_ ;
  19. inline std::vector<native_handle_type> get_handles(std::error_code & ec)
  20. {
  21. auto pid = ::boost::winapi::GetCurrentProcessId();
  22. std::vector<char> buffer(2048);
  23. constexpr static auto STATUS_INFO_LENGTH_MISMATCH_ = static_cast<::boost::winapi::NTSTATUS_>(0xC0000004l);
  24. auto info_pointer = reinterpret_cast<workaround::SYSTEM_HANDLE_INFORMATION_*>(buffer.data());
  25. ::boost::winapi::NTSTATUS_ nt_status = STATUS_INFO_LENGTH_MISMATCH_;
  26. for (;
  27. nt_status == STATUS_INFO_LENGTH_MISMATCH_;
  28. nt_status = workaround::nt_system_query_information(
  29. workaround::SystemHandleInformation_,
  30. info_pointer, static_cast<::boost::winapi::ULONG_>(buffer.size()),
  31. nullptr))
  32. {
  33. buffer.resize(buffer.size() * 2);
  34. info_pointer = reinterpret_cast<workaround::SYSTEM_HANDLE_INFORMATION_*>(buffer.data());
  35. }
  36. if (nt_status < 0 || nt_status > 0x7FFFFFFF)
  37. {
  38. ec = ::boost::process::v1::detail::get_last_error();
  39. return {};
  40. }
  41. else
  42. ec.clear();
  43. std::vector<native_handle_type> res;
  44. for (auto itr = info_pointer->Handle; itr != (info_pointer->Handle + info_pointer->Count); itr++)
  45. {
  46. if (itr->OwnerPid == pid)
  47. res.push_back(reinterpret_cast<native_handle_type>(static_cast<std::uintptr_t>(itr->HandleValue)));
  48. }
  49. return res;
  50. }
  51. inline std::vector<native_handle_type> get_handles()
  52. {
  53. std::error_code ec;
  54. auto res = get_handles(ec);
  55. if (ec)
  56. boost::process::v1::detail::throw_error(ec, "NtQuerySystemInformation failed");
  57. return res;
  58. }
  59. inline bool is_stream_handle(native_handle_type handle, std::error_code & ec)
  60. {
  61. ::boost::winapi::ULONG_ actual_size;
  62. auto nt_status = workaround::nt_query_object(
  63. handle,
  64. workaround::ObjectTypeInformation,
  65. NULL,
  66. 0, &actual_size);
  67. std::vector<char> vec;
  68. vec.resize(actual_size);
  69. workaround::OBJECT_TYPE_INFORMATION_ * type_info_p = reinterpret_cast<workaround::OBJECT_TYPE_INFORMATION_*>(vec.data());
  70. nt_status = workaround::nt_query_object(
  71. handle,
  72. workaround::ObjectTypeInformation,
  73. type_info_p,
  74. actual_size, &actual_size);
  75. if (nt_status < 0 || nt_status > 0x7FFFFFFF)
  76. {
  77. ec = ::boost::process::v1::detail::get_last_error();
  78. return false;
  79. }
  80. else
  81. ec.clear();
  82. auto &nm = type_info_p->TypeName.Buffer;
  83. return type_info_p->TypeName.Length >= 5 &&
  84. nm[0] == L'F' &&
  85. nm[1] == L'i' &&
  86. nm[2] == L'l' &&
  87. nm[3] == L'e' &&
  88. nm[4] == L'\0';
  89. }
  90. inline bool is_stream_handle(native_handle_type handle)
  91. {
  92. std::error_code ec;
  93. auto res = is_stream_handle(handle, ec);
  94. if (ec)
  95. boost::process::v1::detail::throw_error(ec, "NtQueryObject failed");
  96. return res;
  97. }
  98. struct limit_handles_ : handler_base_ext
  99. {
  100. mutable std::vector<::boost::winapi::HANDLE_> handles_with_inherit_flag;
  101. template<typename Executor>
  102. void on_setup(Executor & exec) const
  103. {
  104. auto all_handles = get_handles();
  105. foreach_used_handle(exec,
  106. [&](::boost::winapi::HANDLE_ handle)
  107. {
  108. auto itr = std::find(all_handles.begin(), all_handles .end(), handle);
  109. ::boost::winapi::DWORD_ flags = 0u;
  110. if (itr != all_handles.end())
  111. *itr = ::boost::winapi::INVALID_HANDLE_VALUE_;
  112. else if ((::boost::winapi::GetHandleInformation(*itr, &flags) != 0)
  113. &&((flags & ::boost::winapi::HANDLE_FLAG_INHERIT_) == 0)) //it is NOT inherited anyhow, so ignore too
  114. *itr = ::boost::winapi::INVALID_HANDLE_VALUE_;
  115. });
  116. auto part_itr = std::partition(all_handles.begin(), all_handles.end(),
  117. [](::boost::winapi::HANDLE_ handle) {return handle != ::boost::winapi::INVALID_HANDLE_VALUE_;});
  118. all_handles.erase(part_itr, all_handles.end()); //remove invalid handles
  119. handles_with_inherit_flag = std::move(all_handles);
  120. for (auto handle : handles_with_inherit_flag)
  121. ::boost::winapi::SetHandleInformation(handle, ::boost::winapi::HANDLE_FLAG_INHERIT_, 0);
  122. }
  123. template<typename Executor>
  124. void on_error(Executor & exec, const std::error_code & ec) const
  125. {
  126. for (auto handle : handles_with_inherit_flag)
  127. ::boost::winapi::SetHandleInformation(handle, ::boost::winapi::HANDLE_FLAG_INHERIT_, ::boost::winapi::HANDLE_FLAG_INHERIT_);
  128. }
  129. template<typename Executor>
  130. void on_success(Executor & exec) const
  131. {
  132. for (auto handle : handles_with_inherit_flag)
  133. ::boost::winapi::SetHandleInformation(handle, ::boost::winapi::HANDLE_FLAG_INHERIT_, ::boost::winapi::HANDLE_FLAG_INHERIT_);
  134. }
  135. };
  136. }}}}}
  137. #endif //PROCESS_HANDLES_HPP