liboai: Memory access violation on "A connection error occurred" exception

Describe the bug

This simple example leads to a crash with some memory access violation in xmemory.h ( I am on windows)

#include "liboai.h"

using namespace liboai;

int main() {
  OpenAI oai;
  if (oai.auth.SetKeyEnv("OPENAI_API_KEY")) {
    try {
      Response response = oai.Image->create(
        "a siamese cat!"
      );
    }
    catch (std::exception& e) {
      std::cout << e.what() << std::endl;
    }
    
    ...
  }
}

The lib crashes somewhere after

throw liboai::exception::OpenAIException(
  		"A connection error occurred",
  		liboai::exception::EType::E_CONNECTIONERROR,
  		"liboai::Response::CheckResponse()"
  	);

is called. I can’t see the exact error location on the library side in call stack, but eventually it leads to a crash in xmemory.h.

MSVS spits this:

Exception thrown at 0x00007FF8D13ECD29 in TestApp.exe: Microsoft C++ exception: liboai::exception::OpenAIException at memory location 0x00000046F09DBFC0. Exception thrown at 0x00007FF7DD1C82C5 in TestApp.exe: 0xC0000005: Access violation reading location 0xFFFFFFFFFFFFFFFF.

In my case I have no credits left in OpenAI API. Have you ever tested that case?

To Reproduce

Run the code I provided below. But maybe it is also a special case related to the fact the account has no credits left.

Code snippets

int main()
{
    OpenAI oai;
    if (oai.auth.SetKey("my key goes here"))
    {
        try {

           /* Response res = oai.Image->create(
                "A snake in the grass!",
                1,
                "256x256"
            );*/

            Response response = oai.Image->create(
                "a siamese cat!"
            );

            std::cout << response["data"][0]["url"] << std::endl;
        }
        catch (std::exception& e)
        {
            std::cout << e.what() << std::endl;
            std::quick_exit(EXIT_FAILURE);
        }
   }

    std::cout << "Hello World!\n";
    return 0;
}

OS

Windows

Library version

3.0.0

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Comments: 24 (23 by maintainers)

Most upvoted comments

Good day!

I tried running the example https://github.com/D7EAD/liboai/blob/main/documentation/chat/examples/create_chat_completion.cpp

And I also encountered this bug on my configuration: Windows 10, MSYS2, g++ compiler, linked with the currently available curl lib from MSYS2. I was building liboai from the source code, and I received “signal SIGTRAP” at the end of the

liboai::netimpl::Session::~Session() noexcept { ... }

destructor. Thanks to sasmaster, looks like the source of the error was found ^_^ I tried the code from the corresponding pull request, and it worked without any errors.

However, the main reason I am mentioning this is because I met another consequent issue, with the help of updated code:

liboai::netimpl::Session::Perform(): Timeout was reached (E_CURLERROR:0x06).

It seems that 30 seconds isn’t enough for OpenAI to respond in some cases.

To solve this issue, I increased the timeout numbers inside network.h:

Line 108: netimpl::components::Timeout{ 30000 },
Line 116: netimpl::components::Timeout{ 30000 },

After doing this, the example worked perfectly fine, and I received a result!

It appears that at this exact minute there is high demand for the OpenAI servers, so I guess, it is not usual, that 30 seconds are not enough, which maybe explains the difficulties with the initial bug reproduction. Therefore, I suggest that these numbers be increased or at least made configurable from the client code somehow =)

Good idea.

I’ll push a change to authorization.h and .cpp to allow users to dynamically set their timeout values in seconds.

All of these improvements should be released to main once this PR and its related issue are merged and closed.

Making PR + moved that header into includes. Pushed another small update.Added a check for nullptr to make sure we don’t put null url string into Response.

Nailed it. This is the code that corrupts the internal string buffer:

e[2] = curl_easy_getinfo(this->curl_, CURLINFO_EFFECTIVE_URL, &this->url_str);

Reading curl doc for this function it all makes sense. The function will fill the buffer with data. Now, you can’t do that with std::string as manipulations of its internal memory outside the container may lead to all kind of troubles. Enough that the filled data is bigger than the buffer or no null char is added by the filling logic - it all explodes. In this case the returned data overwrite the pointer and then the container is trying to dealloc memory which doesn’t belong to it.

I also reviewed your whole API and here just a couple of friendly tips: I am more orthodox in C++ dev so of course I cannot urge you to write less meta-programming,but still,I would reduce amount of modern C++ wherever possible, as it would make the code more readable and easier to maintain. Template classes with variadic arg forwarding are extremely hard to debug. If there are no endless variations for function signatures I would just implement those several overloaded methods instead. Your lib is otherwise robust but as I said, less templatization would make it easier to use and more portable. 😃

Yeah, that’s a pretty obvious culprit for an error–passing the address of a C++ type to a C API method.

If this is the cause of the crashes, I would assume an easy fix would just be passing a char* and then doing a deep copy to a string afterwards.

I’ll look into it, but feel free to make a PR if you have done so already.

Okay, I can confirm I have isolated this issue to Debug mode builds.