I'm trying to use Splint with MySQL C API and have run in to some additional problems relating to freeing memory. In all the examples I can find about using the C API, the only freeing function that is called is mysql_free_result
, but rows and fields are never freed:
while ((row = mysql_fetch_row(result)))
{
for(int i = 0; i < num_fields; i++)
{
if (i == 0)
{
while(field = mysql_fetch_field(result))
{
// Bla
}
}
}
}
mysql_free_result(result);
mysql_close(con);
Splint will of course throw an error saying that row and field are memory leaks. Are they? How to resolve this? Should I manually free the row and field structs?
Edit: OK, since mysql_fetch_row
returns null when there is no more rows, I assume it also frees all memory from former row each loop. But how the hell would I tell Splint this?
EDit 2: Here's the implementation for mysql_fetch_row
(version 5.5). No memory is allocated, the function just point you to the next row. So what's needed is a Splint annotation for the function that tells Splint no memory is allocated, but shared.
MYSQL_ROW STDCALL
mysql_fetch_row(MYSQL_RES *res)
{
DBUG_ENTER("mysql_fetch_row");
if (!res->data)
{ /* Unbufferred fetch */
if (!res->eof)
{
MYSQL *mysql= res->handle;
if (mysql->status != MYSQL_STATUS_USE_RESULT)
{
set_mysql_error(mysql,
res->unbuffered_fetch_cancelled ?
CR_FETCH_CANCELED : CR_COMMANDS_OUT_OF_SYNC,
unknown_sqlstate);
}
else if (!(read_one_row(mysql, res->field_count, res->row, res->lengths)))
{
res->row_count++;
DBUG_RETURN(res->current_row=res->row);
}
DBUG_PRINT("info",("end of data"));
res->eof=1;
mysql->status=MYSQL_STATUS_READY;
/*
Reset only if owner points to us: there is a chance that somebody
started new query after mysql_stmt_close():
*/
if (mysql->unbuffered_fetch_owner == &res->unbuffered_fetch_cancelled)
mysql->unbuffered_fetch_owner= 0;
/* Don't clear handle in mysql_free_result */
res->handle=0;
}
DBUG_RETURN((MYSQL_ROW) NULL);
}
{
MYSQL_ROW tmp;
if (!res->data_cursor)
{
DBUG_PRINT("info",("end of data"));
DBUG_RETURN(res->current_row=(MYSQL_ROW) NULL);
}
tmp = res->data_cursor->data;
res->data_cursor = res->data_cursor->next;
DBUG_RETURN(res->current_row=tmp);
}
}
The correct annotation for sharing read-only storage is /*@observer@*/
. For sharing writeable storage, /*@exposed@*/
could be used.
/*@observer@*/ MYSQL_ROW STDCALL mysql_fetch_row(MYSQL_RES *result);
More in the Splint manual.