Skip to content

Dereferencing std::vector::end using boost::process::limit_handles flag on Windows #200

@Breakwell

Description

@Breakwell

I've noticed while using boost::process::limit_handles that the code seems to be attempting to dereference std::vector::end which ultimately ends up with undefined behavior. We can see here

        auto all_handles = get_handles();
        foreach_used_handle(exec,
                [&](::boost::winapi::HANDLE_ handle)
                {
                    auto itr = std::find(all_handles.begin(), all_handles .end(), handle);
                    ::boost::winapi::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);

If the iterator != all_handles.end() then it was found and set the value to ::boost::winapi::INVALID_HANDLE_VALUE_. Otherwise dereference the iterator into GetHandleInformation, however the iterator will equal all_handles.end(). It also seems that if this is the case there's no point in setting itr to ::boost::winapi::INVALID_HANDLE_VALUE_ as it already is not present in all_handles list and therefore ::boost::winapi::SetHandleInformation won't be called on it anyway. It seems the additional else if is redundant?

Ordinarily if this code is being called you would expect at least 1 handle to be present (for the pipe) in the calling process and therefore wouldn't normally run into this error but I am also seeing it's possible for get_handles() to return nothing and this then seems to cause an access violation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions