Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exception thrown in Aws::Http::CurlHttpClient::OverrideOptionsOnConnectionHandle leaves library in an invalid state #3145

Open
gmcdorman-opentext opened this issue Oct 11, 2024 · 1 comment
Assignees
Labels
feature-request A feature should be added or improved. p3 This is a minor priority issue

Comments

@gmcdorman-opentext
Copy link

gmcdorman-opentext commented Oct 11, 2024

Describe the bug

When subclassing from Aws::Http::CurlHttpClient and overriding OverrideOptionsOnConnectionHandle, if this method throws an exception:

  • The exception is propagated outside the call (so superficially it seems to work as expected)
  • The destructor of the base class hangs (acquiring a lock)

Expected Behavior

An exception, including STL exceptions, thrown from the method is handled in a way that cleans up the connection attempt appropriately

Current Behavior

  • Exception is propagated out as per standard C++ rules
  • Subsequent destruction of the instance hangs

Relevant call stack:

aws-cpp-sdk-core.dll!std::condition_variable::wait(std::unique_lock<std::mutex> & _Lck) Line 599 (c:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.35.32215\include\mutex:599)
aws-cpp-sdk-core.dll!std::condition_variable::wait<bool <lambda>(void)>(std::unique_lock<std::mutex> & _Lck, Aws::Utils::ExclusiveOwnershipResourceManager<void *>::ShutdownAndWait::__l4::bool <lambda>(void) _Pred) Line 605 (c:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.35.32215\include\mutex:605)
aws-cpp-sdk-core.dll!Aws::Utils::ExclusiveOwnershipResourceManager<void *>::ShutdownAndWait(unsigned __int64 resourceCount) Line 106 (c:\.conan\data\aws-sdk-cpp\1.11.116\CRSB\testing\source\src\aws-cpp-sdk-core\include\aws\core\utils\ResourceManager.h:106)
aws-cpp-sdk-core.dll!Aws::Http::CurlHandleContainer::~CurlHandleContainer() Line 28 (c:\.conan\data\aws-sdk-cpp\1.11.116\CRSB\testing\source\src\aws-cpp-sdk-core\source\http\curl\CurlHandleContainer.cpp:28)
aws-cpp-sdk-core.dll!Aws::Http::CurlHttpClient::~CurlHttpClient() (Unknown Source:0)
AgentCurlHttpClient_unit.exe!`AgentCurlHttpClientUnit::demo_failure::test_method'::`2'::TestCurlHttpClient::~TestCurlHttpClient() (Unknown Source:0)

Reproduction Steps

Tested on Windows; setting the native CA option is required there to get the requests to succeed.

class TestCurlHttpClient: public  Aws::Http::CurlHttpClient
{
public:
    TestCurlHttpClient(const Aws::Client::ClientConfiguration& clientConfig): CurlHttpClient(clientConfig)
    {
    }

    void OverrideOptionsOnConnectionHandle(CURL*curlhandle) const override
    {
        auto code = curl_easy_setopt(curlhandle, CURLoption::CURLOPT_SSL_OPTIONS, CURLSSLOPT_NATIVE_CA);
        if (code != CURLE_OK)
        {
            // failed to set native CA
            throw std::runtime_error("Failed to set native CA");
            return;
        }
        if (throw_exception)
        {
            throw std::exception("Demonstration");
        }
    }
    bool throw_exception{false};
};

Aws::Client::ClientConfiguration config;

const char *endpoint = "https://www.google.com";
constexpr Aws::Http::HttpMethod method = Aws::Http::HttpMethod::HTTP_GET;
auto test_class(std::make_unique<TestCurlHttpClient>(config));

auto request_zero(Aws::Http::CreateHttpRequest(Aws::String(endpoint), method, Aws::Utils::Stream::DefaultResponseStreamFactoryMethod));

Aws::Http::CurlHttpClient basic_client_zero(config);
auto response_zero = test_class->MakeRequest(request_zero);
test_class.reset();

test_class = std::make_unique<TestCurlHttpClient>(config);
test_class->throw_exception = true;

auto request_one(Aws::Http::CreateHttpRequest(Aws::String(endpoint), method, Aws::Utils::Stream::DefaultResponseStreamFactoryMethod));
std::shared_ptr<Aws::Http::HttpResponse> response_one;
try
{
    response_one = test_class->MakeRequest(request_one);
}
catch (const std::exception &e)
{
    std::cout << "Exception caught as expected" << std::endl;
}

// Hangs.
test_class.reset();

Possible Solution

try
{
     OverrideOptionsOnConnectionHandle(handle);
}
catch (....)
{
    // cleanup, including unlocking, and put in failure state
    throw;
}

Additional Information/Context

An official mechanism for OverrideOptionsOnConnectionHandle to report a failure would also help.

AWS CPP SDK version used

1.11.116

Compiler and Version used

Visual Studio 2022: Microsoft (R) C/C++ Optimizing Compiler Version 19.41.34123 for x64

Operating System and version

Windows 11

@gmcdorman-opentext gmcdorman-opentext added bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. labels Oct 11, 2024
@SergeyRyabinin
Copy link
Contributor

Hi @gmcdorman-opentext,

The SDK by default is built with exceptions disabled, therefore the SDK is unable to catch exceptions thrown by user handlers. Please note that with exceptions disabled, the compiler may also skip exception handling generation, leaving your application process in the undefined behavior state.

This is a feature request to support building with exception handling enabled in the SDK, as well as catching and handling exceptions thrown by different components, including user callbacks/handlers.

Best regards,
Sergey

@jmklix jmklix added feature-request A feature should be added or improved. p3 This is a minor priority issue and removed bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. labels Oct 30, 2024
@sbera87 sbera87 self-assigned this Oct 31, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature-request A feature should be added or improved. p3 This is a minor priority issue
Projects
None yet
Development

No branches or pull requests

4 participants