XMLWordPrintable

    Details

    • Type: Bug
    • Status: Closed (View Workflow)
    • Priority: Major
    • Resolution: Fixed
    • Affects Version/s: 2.1
    • Fix Version/s: 2.2.0
    • Component/s: None
    • Labels:
      None
    • Environment:
      All

      Description

      When using async, there is a logic error in the connect/close processing when using async but an error occurs during connection. Sample code:

      MYSQL* pTest, *pRes;
      int nRV, nRes;

      // Create for async:
      pTest = mysql_init(nullptr);
      mysql_options(pTest, MYSQL_OPT_NONBLOCK, 0);

      // Async connect:
      nRV = mysql_real_connect_start(&pRes, pTest, "nonexist.example.com", "", "", "", 0, nullptr, 0);
      while (nRV != 0)

      { nRV = mysql_real_connect_cont(&pRes, pTest, MYSQL_WAIT_WRITE | MYSQL_WAIT_READ); };
      if (pRes == nullptr) { printf("FAIL\n"); } else { printf("SUCC\n"); };

      // Async close:
      nRV = mysql_close_start(pTest);
      while (nRV != 0) { nRV = mysql_close_cont(pTest, MYSQL_WAIT_WRITE | MYSQL_WAIT_READ); };

      This will segfault in mysql_close_start. The problem is that when real_connect fails, it deletes the options object that indicates that the client is using async. This happens on Line 1989 of libmariadb.c. This does not occur if there is a connection/network failure in any other async function. For comparison, here is modified sample code:

      MYSQL* pTest, *pRes;
      int nRV, nRes;

      // Create for async:
      pTest = mysql_init(nullptr);
      mysql_options(pTest, MYSQL_OPT_NONBLOCK, 0);

      // Async connect:
      nRV = mysql_real_connect_start(&pRes, pTest, nullptr, "", "", "", 0, nullptr, 0);
      while (nRV != 0) { nRV = mysql_real_connect_cont(&pRes, pTest, MYSQL_WAIT_WRITE | MYSQL_WAIT_READ); }

      ;
      if (pRes == nullptr)

      { printf("FAIL\n"); } else { printf("SUCC\n"); };

      // Async query:
      nRV = mysql_query_start(&nRes, pTest, "show databases");
      while (nRV != 0) { closesocket(mysql_get_socket(pTest)); nRV = mysql_query_cont(&nRes, pTest, MYSQL_WAIT_WRITE | MYSQL_WAIT_READ); };
      if (nRes == 0) { printf("SUCCn"); } else { printf("FAILn"); }

      ;

      // Async close:
      nRV = mysql_close_start(pTest);
      while (nRV != 0)

      { nRV = mysql_close_cont(pTest, MYSQL_WAIT_WRITE | MYSQL_WAIT_READ); }

      ;

      This will run successfully without any segfault, because when the mysql_query_cont() call fails, it does not delete the options object.

      There are a few possible fixes:
      1. Add note to the documentation that mysql_close_start cannot be used if an error occurs in mysql_real_connect_start/cont.
      2. Remove the call to mysql_close_options() at the bottom of the mthd_my_real_connect() function. This way, the MYSQL* object will be in the same state regardless of whether a connection error occurs in mysql_connect or mysql_query.
      3. Modify mysql_close_start() to first check if the socket is actually running. If it is not running, then it can divert to run the synchronous mysql_close() instead. This avoids the problem under all circumstances without modifying the current behavior. For this, change part of mysql_async.c from:

      int STDCALL
      mysql_close_start(MYSQL *sock)
      {
      int res;

      /* It is legitimate to have NULL sock argument, which will do nothing. */
      if (sock)

      { res= mysql_close_slow_part_start(sock); /* If we need to block, return now and do the rest in mysql_close_cont(). */ if (res) return res; }
      mysql_close(sock);
      return 0;
      }

      To:

      mysql_close_start(MYSQL *sock)
      {
      int res;

      /* It is legitimate to have NULL sock argument, which will do nothing. */
      if (sock && sock->net.vio)
      { res= mysql_close_slow_part_start(sock); /* If we need to block, return now and do the rest in mysql_close_cont(). */ if (res) return res; }

      mysql_close(sock);
      return 0;
      }

      Note the only change is the if conditional, from:
      if (sock)
      To:
      if (sock && sock->net.vio)

      An alternative that would work is:
      if (sock && sock->options.extension)

        Attachments

          Activity

            People

            Assignee:
            georg Georg Richter
            Reporter:
            A812371 Matt Fagan
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Dates

              Created:
              Updated:
              Resolved:

                Git Integration