mysqlcapisplint

MySQL C API with Splint: Freeing fields and rows


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);
  }
}

Solution

  • 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.