Безопасное управление ресурсами: использование InternetCloseHandle() без обработки ошибок?
При работе с системными ресурсами в операционных системах семейства Windows важно корректно их освобождать, чтобы избежать утечек ресурсов. Одно из таких действий – закрытие дескрипторов, полученных через функции Winsock или WinINet. В частности, функция InternetCloseHandle() используется для освобождения ресурсов, связанных с объектом HINTERNET.
Вопрос, поднятый в контексте, заключается в том, можно ли считать, что вызов InternetCloseHandle() не приведет к ошибке и, следовательно, можно ли упростить код, не обрабатывая возможные ошибки при закрытии дескриптора.
Пример кода с обработкой ошибок
function Request(const pConnection: HINTERNET; const localpath: string): string;
var
Buffer: packed array[1..5000] of Char;
BytesRead: Cardinal;
pRequest: HINTERNET;
Sent: boolean;
begin
Result := '';
pRequest := HTTPOpenRequest(pConnection, 'GET', pchar(localpath), nil, nil, nil, 0, 0);
if pRequest <> nil then
try
Sent := HTTPSendRequest(pRequest, nil, 0, nil, 0);
if Sent then
while InternetReadFile(pRequest, @Buffer[1], SizeOf(Buffer)-1, BytesRead) do
begin
SetLength(Buffer, BytesRead+1);
Buffer[BytesRead+1] := #0;
Result := Result + Buffer;
end;
CheckWin32Error(Sent);
finally
CheckWin32Error(InternetCloseHandle(pRequest));
end;
if not Sent then
RaiseLastOSerror; // HTTPSendRequest failed
else
CheckWin32Error(GetLastError <> 0);
end;
В этом примере используется конструкция try-finally для гарантированного освобождения ресурса, даже если в процессе работы с ним возникли исключения. Функция CheckWin32Error используется для проверки результата выполнения функций WinAPI и подъема исключения в случае ошибки.
Альтернативное мнение
Рассмотрим альтернативный подход, предложенный в контексте:
try
// Действия с объектом
finally
Win32Check(InternetCloseHandle(H));
end;
Этот подход предполагает, что InternetCloseHandle() будет вызван в блоке finally, что гарантирует его выполнение, даже если в блоке try возникнут исключения.
Подтвержденный ответ
В контексте обсуждения было предложено следующее решение:
Result := '';
pRequest := HTTPOpenRequest(pConnection, 'GET', pchar(localpath), nil, nil, nil, 0, 0);
if pRequest = nil then
RaiseLastOSerror;
try
CheckWin32Error(HTTPSendRequest(pRequest, nil, 0, nil, 0));
while InternetReadFile(pRequest, @Buffer, SizeOf(Buffer)-1, BytesRead) do
begin
SetLength(Buffer, BytesRead+1);
Buffer[BytesRead+1] := #0;
Result := Result + Buffer;
end;
if GetLastError <> 0 then
RaiseLastOSerror;
finally
CheckWin32Error(InternetCloseHandle(pRequest));
end;
Здесь используется подход, при котором ошибки каждой функции проверяются сразу после её вызова, и в случае возникновения ошибки поднимается исключение, соответствующее этому событию. Это позволяет получить сообщение об ошибке, относящееся к конкретной операции, а не к операции, произошедшей ранее.
Вывод
Использование InternetCloseHandle() без обработки ошибок может быть небезопасно, так как, хотя вероятность возникновения ошибки невелика, она все же существует. Поэтому рекомендуется использовать конструкцию try-finally для гарантированного освобождения ресурсов и проверку результатов вызовов функций WinAPI для своевременного подъема исключений в случае ошибок.
Вопрос заключается в том, можно ли пропустить обработку ошибок при использовании функции `InternetCloseHandle()` для закрытия дескрипторов в Windows и какие подходы к этому вопросу существуют в контексте обеспечения безопасности управления ресурсами.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.