Bug #70113 Memory leak in SQLPrepare with queries that use parameters
Submitted: 21 Aug 2013 21:15 Modified: 11 Sep 2013 16:06
Reporter: Denis Parnovsky Email Updates:
Status: Closed Impact on me:
None 
Category:Connector / ODBC Severity:S1 (Critical)
Version:5.2.5 OS:Windows
Assigned to: Bogdan Degtyariov CPU Architecture:Any

[21 Aug 2013 21:15] Denis Parnovsky
Description:
ODBC Connector 5.2.2 and 5.2.5 is leaking on SQLBindParamater. 
Several kilobytes per operation.
3.51.11 is not leaking with the same test program.

If the parameter value is inserted into the query text instead of Bind then the memory is stable.

Memory consumption is visible in Task Manager, the program quickly grows from 1200K to 140000k.

Looks like #31115 is back.

How to repeat:

#include <iostream>

#include <windows.h>

#include <sqltypes.h>

#include <sql.h>

#include <sqlext.h>

 

using namespace std;

 

void show_error(unsigned int handletype, const SQLHANDLE& handle){

    SQLCHAR sqlstate[1024];

    SQLCHAR message[1024];

    if(SQL_SUCCESS == SQLGetDiagRec(handletype, handle, 1, sqlstate, NULL, message, 1024, NULL))

        cout<<"Message: "<<message<<"\nSQLSTATE: "<<sqlstate<<endl;

}

 

int main(){

      SQLHANDLE sqlenvhandle;   

    SQLHANDLE sqlconnectionhandle;

    SQLHANDLE sqlstatementhandle;

    SQLRETURN retcode;

 

    if(SQL_SUCCESS!=SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &sqlenvhandle))

        goto FINISHED;

 

    if(SQL_SUCCESS!=SQLSetEnvAttr(sqlenvhandle,SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0))

        goto FINISHED;

   

    if(SQL_SUCCESS!=SQLAllocHandle(SQL_HANDLE_DBC, sqlenvhandle, &sqlconnectionhandle))

        goto FINISHED;

 

    SQLCHAR retconstring[1024];

    switch(SQLDriverConnect (sqlconnectionhandle,

                NULL,

                (SQLCHAR*)"DSN=l106;SERVER=localhost;UID=root;PWD=root;",

                SQL_NTS,

                retconstring,

                1024,

                NULL,

                SQL_DRIVER_NOPROMPT)){

        case SQL_SUCCESS_WITH_INFO:

            show_error(SQL_HANDLE_DBC, sqlconnectionhandle);

            break;

        case SQL_INVALID_HANDLE:

        case SQL_ERROR:

            show_error(SQL_HANDLE_DBC, sqlconnectionhandle);

            goto FINISHED;

        default:

            break;

    }

 

    for(int i = 0; i < 100000; i++)

    {

      if(SQL_SUCCESS!=SQLAllocHandle(SQL_HANDLE_STMT, sqlconnectionhandle, &sqlstatementhandle))

          goto FINISHED;

 

      SWORD val = 100;

      SQLINTEGER iJunk = SQL_NTS;

 

      char* query = "select exists(select NULL from acdgroup where GROUPID = ?)";

 

      if(SQL_SUCCESS!=SQLPrepare(sqlstatementhandle, (SQLCHAR*)query, strlen(query)))

          goto FINISHED;

 

        if(SQL_SUCCESS!=SQLBindParameter(sqlstatementhandle,1,SQL_PARAM_INPUT,SQL_C_SSHORT,SQL_SMALLINT,2,0,&val,sizeof(val),&iJunk))

          goto FINISHED;

 

      if(SQL_SUCCESS!=SQLExecute(sqlstatementhandle)){

          show_error(SQL_HANDLE_STMT, sqlstatementhandle);

          goto FINISHED;

      }

      else{

          short result = -1;

          while(SQLFetch(sqlstatementhandle)==SQL_SUCCESS){

              SQLGetData(sqlstatementhandle, 1, SQL_C_SHORT, &result, 0, NULL);

              cout<<result<<endl;

          }

      }

      SQLCloseCursor(sqlstatementhandle);

      SQLFreeHandle(SQL_HANDLE_STMT, sqlstatementhandle);

    }

 

FINISHED:

    show_error(SQL_HANDLE_DBC, sqlconnectionhandle);

    SQLDisconnect(sqlconnectionhandle);

    SQLFreeHandle(SQL_HANDLE_DBC, sqlconnectionhandle);

    SQLFreeHandle(SQL_HANDLE_ENV, sqlenvhandle);

   

}
[23 Aug 2013 12:58] Bogdan Degtyariov
Hi Denis,

Thank you for your interest in MySQL software and for reporting the problem in it.
A special big thanks for providing the working C++ test case, which demonstrated the memory leak as described. We really appreciate your efforts to make the verification task easier for us.

The bug is verified.
This looks like a serious high-priority issue. I will keep you informed about the bug fixing progress.
[30 Aug 2013 9:27] Bogdan Degtyariov
The actual memory leak occurs in SQLPrepare() because the result of mysql_stmt_result_metadata() is not freed.
[3 Sep 2013 8:26] Bogdan Degtyariov
Leak #2 was discovered in ssps_close() function, which did not always call free_result_bind() to free the bind result.
[4 Sep 2013 14:02] andrew turnbull
When do you expect to have a released fix for this?
[5 Sep 2013 4:56] Bogdan Degtyariov
Andrew,

Oracle company policy does not allow us to disclose the dates of software product releases before they are officially announced. Sorry if it creates inconveniences.
[5 Sep 2013 4:59] Bogdan Degtyariov
Patch

Attachment: bug70113.diff (application/octet-stream, text), 3.91 KiB.

[5 Sep 2013 5:12] andrew turnbull
When will the msi get rebuilt?
[5 Sep 2013 5:52] Denis Parnovsky
Bogdan, if I remove SQLPrepare and change SQLExecute to SQLExecDirect then the situation remains the same, memory usage grows at the rate of 300Kb per second.

Do I need to create another issue since you changed this one to be specific about SQLPrepare?
[5 Sep 2013 7:16] Bogdan Degtyariov
Andrew, as I said before - you have to wait for the official announcement of the next version.
[5 Sep 2013 7:19] Bogdan Degtyariov
Denis,

The patch addressed both memory leaks in SQLPrepare and in SQLExecDirect.
We run valgrind memory checks and no more leaks were reported.
[9 Sep 2013 5:45] andrew turnbull
If you cant tell me when the fix will be released can you tell me in what version the bug was introduced so I can roll back. This is creating chaos in a new mission critical application.
[9 Sep 2013 6:05] Bogdan Degtyariov
Andrew,

No need to rollback to the previous version to stop the memory leak.
It only happens when the Server Side Prepared Statements are used (SSPS).
SSPS are used for any query by default.

SSPS can be disabled by adding "NO_SSPS=1" to the connection string or ticking the checkbox [Details->Misc->Prepare Statements on Client] in the Data Source setup GUI.

Sorry for inconvenience caused by the bug.
[9 Sep 2013 6:09] andrew turnbull
Thanks will give it a try
[11 Sep 2013 16:06] Daniel So
The following changelog entry has been added for Connector/ODBC 5.2.6:

Memory leaks occurred in SQLPrepare() and SQLExecDirect() when SQLBindParamater was used on the SQL statements. This fix frees previous results of mysql_stmt_result_metadata() in order to prevent the memory leaks.