Skip to content

Commit c66f84d

Browse files
authored
Resolve double free when WinHttpSendRequest fails (#1022)
* Update vcpkg. * Resolve double free when WinHttpSendRequest fails A customer reported that win WinHttpSendRequest fails, WinHTTP still delivers WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING callbacks. When _start_request_send encountered a failure, it deleted the context weak_ptr, and then the WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING also tried to delete it, resulting in double frees. This change binds the weak_ptr to the handle more directly and avoids paying attention to WinHttpSendRequest.
1 parent e6498b2 commit c66f84d

File tree

2 files changed

+41
-60
lines changed

2 files changed

+41
-60
lines changed

Release/src/http/client/http_client_winhttp.cpp

Lines changed: 40 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,8 @@ class winhttp_request_context final : public request_context
244244
bool is_externally_allocated() const { return !m_body_data.is_internally_allocated(); }
245245

246246
HINTERNET m_request_handle;
247-
std::weak_ptr<winhttp_request_context>* m_request_context;
247+
std::weak_ptr<winhttp_request_context>*
248+
m_request_handle_context; // owned by m_request_handle to be delete'd by WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING
248249

249250
bool m_proxy_authentication_tried;
250251
bool m_server_authentication_tried;
@@ -532,9 +533,7 @@ class winhttp_request_context final : public request_context
532533

533534
if (m_request_handle != nullptr)
534535
{
535-
auto tmp_handle = m_request_handle;
536-
m_request_handle = nullptr;
537-
WinHttpCloseHandle(tmp_handle);
536+
WinHttpCloseHandle(m_request_handle);
538537
}
539538
}
540539

@@ -660,7 +659,6 @@ class winhttp_request_context final : public request_context
660659
winhttp_request_context(const std::shared_ptr<_http_client_communicator>& client, const http_request& request)
661660
: request_context(client, request)
662661
, m_request_handle(nullptr)
663-
, m_request_context(nullptr)
664662
, m_bodyType(no_body)
665663
, m_startingPosition(std::char_traits<uint8_t>::eof())
666664
, m_body_data()
@@ -1004,6 +1002,8 @@ class winhttp_client final : public _http_client_communicator
10041002
http::uri_builder(m_uri).append(msg.relative_uri()).to_uri().resource().to_string();
10051003

10061004
// Open the request.
1005+
winhttp_context->m_request_handle_context = new std::weak_ptr<winhttp_request_context>(winhttp_context);
1006+
10071007
winhttp_context->m_request_handle =
10081008
WinHttpOpenRequest(m_hConnection,
10091009
msg.method().c_str(),
@@ -1015,10 +1015,24 @@ class winhttp_client final : public _http_client_communicator
10151015
if (winhttp_context->m_request_handle == nullptr)
10161016
{
10171017
auto errorCode = GetLastError();
1018+
delete winhttp_context->m_request_handle_context;
1019+
winhttp_context->m_request_handle_context = 0;
10181020
request->report_error(errorCode, build_error_msg(errorCode, "WinHttpOpenRequest"));
10191021
return;
10201022
}
10211023

1024+
if (!WinHttpSetOption(winhttp_context->m_request_handle,
1025+
WINHTTP_OPTION_CONTEXT_VALUE,
1026+
&winhttp_context->m_request_handle_context,
1027+
sizeof(void*)))
1028+
{
1029+
auto errorCode = GetLastError();
1030+
delete winhttp_context->m_request_handle_context;
1031+
winhttp_context->m_request_handle_context = 0;
1032+
request->report_error(errorCode, build_error_msg(errorCode, "WinHttpSetOption request context"));
1033+
return;
1034+
}
1035+
10221036
if (proxy_info_required)
10231037
{
10241038
auto result = WinHttpSetOption(
@@ -1194,69 +1208,36 @@ class winhttp_client final : public _http_client_communicator
11941208
private:
11951209
void _start_request_send(const std::shared_ptr<winhttp_request_context>& winhttp_context, size_t content_length)
11961210
{
1197-
// WinHttp takes a context object as a void*. We therefore heap allocate a std::weak_ptr to the request context
1198-
// which will be destroyed during the final callback.
1199-
std::unique_ptr<std::weak_ptr<winhttp_request_context>> weak_context_holder;
1200-
if (winhttp_context->m_request_context == nullptr)
1211+
DWORD totalLength;
1212+
if (winhttp_context->m_bodyType == no_body)
12011213
{
1202-
weak_context_holder = std::make_unique<std::weak_ptr<winhttp_request_context>>(winhttp_context);
1203-
winhttp_context->m_request_context = weak_context_holder.get();
1214+
totalLength = 0;
12041215
}
1205-
1206-
if (winhttp_context->m_bodyType == no_body)
1216+
else
12071217
{
1208-
if (!WinHttpSendRequest(winhttp_context->m_request_handle,
1209-
WINHTTP_NO_ADDITIONAL_HEADERS,
1210-
0,
1211-
nullptr,
1212-
0,
1213-
0,
1214-
(DWORD_PTR)winhttp_context->m_request_context))
1215-
{
1216-
if (weak_context_holder) winhttp_context->m_request_context = nullptr;
1218+
// Capture the current read position of the stream.
1219+
auto rbuf = winhttp_context->_get_readbuffer();
12171220

1218-
auto errorCode = GetLastError();
1219-
winhttp_context->report_error(errorCode, build_error_msg(errorCode, "WinHttpSendRequest"));
1220-
}
1221-
else
1222-
{
1223-
// Ownership of the weak_context_holder was accepted by the callback, so release the pointer without
1224-
// freeing.
1225-
weak_context_holder.release();
1226-
}
1221+
// Record starting position in case request is challenged for authorization
1222+
// and needs to seek back to where reading is started from.
1223+
winhttp_context->m_startingPosition = rbuf.getpos(std::ios_base::in);
12271224

1228-
return;
1225+
// If we find ourselves here, we either don't know how large the message
1226+
totalLength = winhttp_context->m_bodyType == content_length_chunked ? (DWORD)content_length
1227+
: WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH;
12291228
}
12301229

1231-
// Capture the current read position of the stream.
1232-
auto rbuf = winhttp_context->_get_readbuffer();
1233-
1234-
// Record starting position in case request is challenged for authorization
1235-
// and needs to seek back to where reading is started from.
1236-
winhttp_context->m_startingPosition = rbuf.getpos(std::ios_base::in);
1237-
1238-
// If we find ourselves here, we either don't know how large the message
1239-
// body is, or it is larger than our threshold.
1240-
if (!WinHttpSendRequest(winhttp_context->m_request_handle,
1241-
WINHTTP_NO_ADDITIONAL_HEADERS,
1242-
0,
1243-
nullptr,
1244-
0,
1245-
winhttp_context->m_bodyType == content_length_chunked
1246-
? (DWORD)content_length
1247-
: WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH,
1248-
(DWORD_PTR)winhttp_context->m_request_context))
1230+
const auto requestSuccess = WinHttpSendRequest(winhttp_context->m_request_handle,
1231+
WINHTTP_NO_ADDITIONAL_HEADERS,
1232+
0,
1233+
nullptr,
1234+
0,
1235+
totalLength,
1236+
(DWORD_PTR)winhttp_context->m_request_handle_context);
1237+
if (!requestSuccess)
12491238
{
1250-
if (weak_context_holder) winhttp_context->m_request_context = nullptr;
1251-
12521239
auto errorCode = GetLastError();
1253-
winhttp_context->report_error(errorCode, build_error_msg(errorCode, "WinHttpSendRequest chunked"));
1254-
}
1255-
else
1256-
{
1257-
// Ownership of the weak_context_holder was accepted by the callback, so release the pointer without
1258-
// freeing.
1259-
weak_context_holder.release();
1240+
winhttp_context->report_error(errorCode, build_error_msg(errorCode, "WinHttpSendRequest"));
12601241
}
12611242
}
12621243

vcpkg

Submodule vcpkg updated 331 files

0 commit comments

Comments
 (0)