brucechina 发表于 2014-9-1 00:35:27

mysql c api 多结果集时,上下文分配空间,内存访问越界

最近想做一个访问mysql的c程序, 使用mysqlclient 来访问mysql。
在做单个结果集时, 没有发生问题。访问多结果集时,出现莫名其妙的崩溃。请路过的朋友帮忙分析一下。

我把代码全部贴出来吧:
#include<mysql.h>
#include<stdio.h>
#include<stdlib.h>
#include <string.h>

struct col_def{
        char* col_name;        // col_name        unalloc
        int        col_name_len;       
        int   field_type; // ??
};

struct col_def* create_col_def( ){
        struct col_def* ptr = NULL;
    ptr = (struct col_def *)malloc(sizeof(struct col_def));
    ptr->col_name = NULL;
    ptr->col_name_len = 0;
    ptr->field_type = 0;
    return ptr;
}

void destroy_col_def( struct col_def* def ){
        free( def->col_name );       
        free( def );
}


struct field_data{
        int data_len;        // data len
        char* data;                // data                unalloc
};

struct field_data* create_field_data( ){
        struct field_data* ptr = NULL;
    ptr = (struct field_data *)malloc(sizeof(struct field_data));
    ptr->data = NULL;
    ptr->data_len = 0;
    return ptr;
}

void destroy_field_data( struct field_data* data ){
        free( data->data );       
        free( data );
}


struct res_info{
        int error_code;
        int affect_rows;
        int row_num;

        int        col_num;
        struct col_def* col_defs;        // alloc
        int file_data_count;
        struct field_data* file_data; // alloc
};

struct res_info* create_res_info( ){
        struct res_info* ptr = NULL;
    ptr = (struct res_info *)malloc(sizeof(struct res_info));
    ptr->error_code = 0;
    ptr->affect_rows = 0;
    ptr->row_num = 0;
    ptr->col_num = 0;      
    ptr->file_data_count = 0;
    return ptr;
}

void destroy_res_info( struct res_info* res_info ){
        inti = 0;
        for( i = 0; i < res_info->col_num; i++ )
                destroy_col_def( res_info->col_defs );
        for( i = 0; i < res_info->file_data_count; i++ )
                destroy_field_data( res_info->file_data );
        free( res_info );
}


intres_info_total_len( struct res_info* res_info ){
        int len = 0;
        len += 4;
        len += 4;
        len += 4;

        int i = 0;
        len += 4;
        for( i = 0; i < res_info->col_num; i++ ){
                struct col_def* def = res_info->col_defs[ i ];
                len += 4; //type
                len += 4; // len
                len += def->col_name_len;        // data
        }

        len += 4;
        for( i = 0; i < res_info->file_data_count; i++ ){
                struct field_data* def = res_info->file_data[ i ];
                len += 4;                // len
                len += def->data_len;        // data
        }

        return len;
}

void debug_res_info( struct res_info* res_info ){
        printf("debug res_info........\r\n");
        printf("res_info->error_code=%d\r\n", res_info->error_code );
        printf("res_info->affect_rows=%d\r\n", res_info->affect_rows );
        printf("res_info->row_num=%d\r\n", res_info->row_num );
        printf("res_info->col_num=%d\r\n", res_info->col_num );       
        printf("res_info->file_data_count=%d\r\n", res_info->file_data_count );
       
        printf("res_info col_defs\r\n" );       
        int i = 0;
        for( i = 0; i < res_info->col_num; i++ ){
                struct col_def* def = res_info->col_defs[ i ];
                printf("             def name=%s, type=%d\r\n", def->col_name, def->field_type );       
        }
        printf("res_info file_data\r\n" );       
        for( i = 0; i < res_info->file_data_count; i++ ){
                struct field_data* def = res_info->file_data[ i ];
                printf("             data name=%s, type=%d\r\n", def->data, def->data_len );       
        }       
}

void res_info_alloc_col_def( struct res_info* res_info){
        if( res_info->col_num == 0 )
                return;
        //res_info->col_defs = (struct col_def*)malloc( sizeof(struct col_def*)*res_info->col_num);
}

void res_info_set_col_def( struct res_info* res_info, int index, struct col_def* def ){
        if( index >= res_info->col_num )
                return;
        res_info->col_defs = def;
}

void res_info_alloc_field_data( struct res_info* res_info){
        if( res_info->file_data_count == 0 )
                return;
        //res_info->file_data = (struct field_data*)malloc( sizeof(struct field_data)*res_info->file_data_count);
}

void res_info_set_field_data( struct res_info* res_info, int index, struct field_data* data ){
        if( index >= res_info->file_data_count )
                return;
        res_info->file_data = data;
}

void pack_res_info( struct res_info* res_info, char* buffer ){
        printf("pack_res_info\r\n" );
        int offset = 0;
        int test_int = 0;
        memcpy( buffer + offset, &res_info->error_code, 4);       
        memcpy( &test_int, buffer + offset, 4 );
        offset += 4;
       
        memcpy( buffer + offset, &res_info->affect_rows, 4);       
        memcpy( &test_int, buffer + offset, 4 );
        offset += 4;       
       
        memcpy( buffer + offset, &res_info->row_num, 4);       
        memcpy( &test_int, buffer + offset, 4 );
        offset += 4;
       
       
        memcpy( buffer + offset, &res_info->col_num, 4);        offset += 4;
        int i = 0;
        for( i = 0; i < res_info->col_num; i++ ){
                struct col_def* def = res_info->col_defs[ i ];
                memcpy( buffer + offset, &def->field_type, 4);        offset += 4;
                memcpy( buffer + offset, &def->col_name_len, 4);        offset += 4;
                memcpy( buffer + offset, def->col_name, def->col_name_len);       
                printf("pack_res_infodef->col_name=%s \r\n", buffer + offset );               
                offset += def->col_name_len;       
        }
       
        memcpy( buffer + offset, &res_info->file_data_count, 4);        offset += 4;
        for( i = 0; i < res_info->file_data_count; i++ ){
                struct field_data* def = res_info->file_data[ i ];
                memcpy( buffer + offset, &def->data_len, 4);        offset += 4;
                memcpy( buffer + offset, def->data, def->data_len);               
                printf("pack_res_infodef->data=%s \r\n", buffer + offset );
                offset += def->data_len;       
        }
        printf("pack_res_infowrite buff = %d \r\n", offset );
}

void debug_bytes( char* buffer, int len ){

}
struct res_info* unpack_res_info( char* buffer, int len ){
        debug_bytes( buffer, 96 );
        printf("unpack_res_info buffer=%s\r\n", buffer+28 );
        struct res_info* res_info = create_res_info( );
        int offset = 0;
        memcpy( &res_info->error_code, buffer + offset, 4 );        offset += 4;
        memcpy( &res_info->affect_rows,buffer + offset, 4 );        offset += 4;
        memcpy( &res_info->row_num, buffer + offset, 4 );        offset += 4;

        int i = 0;
        memcpy( &res_info->col_num, buffer + offset, 4 );        offset += 4;
        for( i = 0; i < res_info->col_num; i++ ){
                struct col_def* def = create_col_def( );
                memcpy( &def->field_type, buffer + offset, 4);        offset += 4;
                memcpy( &def->col_name_len, buffer + offset, 4);        offset += 4;
                def->col_name = (char*)malloc( def->col_name_len + 1 );
                memset( def->col_name, 0,def->col_name_len + 1 );
                memcpy( def->col_name, buffer + offset, def->col_name_len);        offset += def->col_name_len;       
                res_info_set_col_def( res_info, i, def );
        }
       
        //int count = 0;
        memcpy( &res_info->file_data_count, buffer + offset, 4 );        offset += 4;
        for( i = 0; i < res_info->file_data_count; i++ ){
                struct field_data* def = create_field_data( );
                memcpy( &def->data_len, buffer + offset, 4);        offset += 4;
                def->data = (char*)malloc( def->data_len + 1 );
                memset( def->data, 0,def->data_len + 1 );
                memcpy( def->data, buffer + offset, def->data_len);        offset += def->data_len;
                res_info_set_field_data( res_info, i, def);               
        }
        //res_info->file_data_count = count;
        printf("unpack_res_inforead buff = %d \r\n", offset );
        return res_info;
}


struct sql_results {
        struct res_info*         res_infos;        //
        int                        res_num;
        int                        error_flag;
};

struct sql_results* sql_results_create( ) {
        printf(" sizeof( struct sql_results )=%ld\r\n", sizeof( struct sql_results ) );
        struct sql_results* ptr = (struct sql_results*)malloc( sizeof( struct sql_results ) );
        printf(" sql_results_create 0\r\n" );
        ptr->res_num = 0;
        ptr->error_flag = 0;
        return ptr;
}

void sql_results_destroy( struct sql_results* reslut ) {
        int i = 0;
        for( i = 0; i < reslut->res_num; i++ )
                destroy_res_info( reslut->res_infos);
        free( reslut );
}


void sql_results_set_res_info( struct sql_results* results, int index, struct res_info* res_info ){
        printf(" sql_results_set_res_info index=%d\r\n", index );       
        if( index >= 10 ){
                printf(" over flow sql_resultscur maxnum=%d\r\n", 5 );
                return;               
        }
        results->res_infos[ index ] = res_info;
}

int sql_results_set_total_len( struct sql_results* results ){
        int i = 0;
        int len = 0;
        len += 4;
        len += 4;
        for( i = 0; i < results->res_num; i++ )
                len += res_info_total_len( results->res_infos[ i ]);
        return len;
}

void sql_results_set_total_debug( struct sql_results* results ){
        printf(" results->error_flag=%d\r\n", results->error_flag );       
        printf(" results->res_num=%d\r\n", results->res_num );       
        int i = 0;
        for( i = 0; i < results->res_num; i++ )
                debug_res_info( results->res_infos );
}


void pack_sql_results_set( struct sql_results* results, char* buffer ) {

        int offset = 0;
        memcpy( buffer + offset, &results->error_flag, 4);        offset += 4;
        memcpy( buffer + offset, &results->res_num, 4);       
        int num = 0;
        memcpy( &num, buffer + offset, 4 );
       
        offset += 4;

        int i = 0;

        for( i = 0; i < results->res_num; i++ ){
                struct res_info* res_info = results->res_infos[ i ];
                pack_res_info( res_info, (char*)(buffer + offset) );


                int test_int = 0;
                memcpy( &test_int, buffer + 0 + 8, 4 );
                printf(" pack_sql_results_set test_int1=%d\n", test_int );
                memcpy( &test_int, buffer + 4 + 8, 4 );
                printf(" pack_sql_results_set test_int2=%d\n", test_int );
                memcpy( &test_int, buffer + 8 + 8, 4 );
                printf(" pack_sql_results_set test_int3=%d\n", test_int );

                memcpy( &test_int, buffer + 12 + 8, 4 );
                printf(" pack_sql_results_set test_int4=%d\n", test_int );
                malloc( 20 );
                memcpy( &test_int, buffer + 16 + 8, 4 );
                printf(" pack_sql_results_set test_int5=%d\n", test_int );
                                                               
                malloc( 20 );
//                struct res_info* res_info_temp = unpack_res_info( (char*)(buffer + offset), res_info_total_len( res_info ) );
//                debug_res_info( res_info_temp );
               
                offset += res_info_total_len( res_info );




                printf(" pack_sql_results_set unpack_sql_results_set i = %d\r\n", i );
        }
}

struct sql_results* unpack_sql_results_set( char* buffer, int len ) {
        printf("begin unpack_sql_results_set\r\n" );               
        int offset = 0;
        printf(" unpack_sql_results_set0\r\n" );       

        struct sql_results* results = sql_results_create( );
        memcpy( &results->error_flag, buffer + offset, 4 );        offset += 4;
        memcpy( &results->res_num, buffer + offset, 4 );        offset += 4;
        printf(" results->error_flag=%d\r\n", results->error_flag );       
        printf(" results->res_num=%d\r\n", results->res_num );       
        int i = 0;

        for( i = 0; i < results->res_num; i++ ){
                struct res_info* res_info = unpack_res_info( buffer + offset, 0 );
                sql_results_set_res_info( results, i, res_info );
                offset += res_info_total_len( res_info );
        }

        printf(" unpack_sql_results_set5\r\n" );
        printf("end unpack_sql_results_set\r\n" );               
        return results;
}

void process_result_set( MYSQL* mysql, MYSQL_RES * res, struct res_info* res_info ){
        my_ulonglong rownum = mysql_num_rows( res );
        int fieldcount = mysql_field_count(mysql);
        unsigned long *lengths;       
        lengths = mysql_fetch_lengths(res);
        MYSQL_FIELD *field = NULL;
        MYSQL_ROW row;

        res_info->row_num = rownum;
        res_info->col_num = fieldcount;
        res_info->file_data_count = fieldcount*rownum;
                      
        int cur_field = 0;
        while((field = mysql_fetch_field(res)) &&field != NULL ) {
                struct col_def* col_def = create_col_def( );
                col_def->col_name_len   = strlen( field->name );
                col_def->col_name = malloc( sizeof( col_def->col_name_len + 1 ) );
                memset( col_def->col_name, 0, col_def->col_name_len+1);
                memcpy( col_def->col_name, field->name, col_def->col_name_len );
                //col_def->col_name = field->name;
                col_def->field_type = field->type;
                res_info_set_col_def( res_info, cur_field, col_def );
                cur_field++;
        }


        int currow = 0;
        int irow = 0;
        int icol = 0;

        int cur_field_count = 0;
        while( currow < rownum ){
                row = mysql_fetch_row(res);       
               lengths = mysql_fetch_lengths(res);

               for( icol = 0; icol < fieldcount; icol++ ){
                       int len = lengths;
                       char* data = row[ icol ];
                       printf("irow=%d icol=%d len=%d data=%s\n", currow, icol, len, data );
                       struct field_data* field_data = create_field_data( );
                       field_data->data_len = len;
                        field_data->data = malloc( sizeof( len + 1 ) );
                        memset( field_data->data, 0, len+1);
                        memcpy( field_data->data, data, len );
                       //field_data->data = data;
                        res_info_set_field_data( res_info, cur_field_count, field_data );                
                       cur_field_count++;
               }
                currow++;
        }
}

struct sql_results* exe_sql_muti( MYSQL* mysql, char* sql ) {
        struct sql_results* response_result = sql_results_create( );
        int status = 0;
        int cur_res_info_num = 0;
        status = mysql_query(mysql,sql );
        if (status){
                printf("exe_sql                     mysql_query               error ==========================\r\n");               
                response_result->error_flag = 1;
                return response_result;       
        }
       
        MYSQL_RES *result;
        /* process each statement result */
        do {

                struct res_info* res_info = create_res_info( );
                  /* did current statement return data? */
                result = mysql_store_result(mysql);
                if (result){
                        /* yes; process rows and free the result set */
                        process_result_set(mysql, result, res_info );
                        printf("record set\r\n");
                        //mysql_free_result(result);
                }
                else { /* no result set or error */
                        if (mysql_field_count(mysql) == 0){               
                                int affect_rows = (int)mysql_affected_rows(mysql);
                                res_info->affect_rows = affect_rows;
                                printf("%d rows affected\n", affect_rows );
                        }
                        else{/* some error occurred */
                                response_result->error_flag = 1;
                                printf("Could not retrieve result set\n");
                                break;
                        }
                }
                response_result->res_num = cur_res_info_num + 1;
                sql_results_set_res_info( response_result, cur_res_info_num++, res_info );

                /* more results? -1 = no, >0 = error, 0 = yes (keep looping) */
                if ((status = mysql_next_result(mysql)) > 0){
                        response_result->error_flag = 1;
                        printf("Could not execute statement\n");
                }
        } while (status == 0);
        return response_result;
}


struct sql_results* exe_sql_single( MYSQL* mysql, char* sql ) {
        struct sql_results* response_result = sql_results_create( );
        int status = 0;
        int cur_res_info_num = 0;
        status = mysql_query(mysql,sql );
        if (status){
                response_result->error_flag = 1;
                return response_result;       
        }
       
        MYSQL_RES *result;
        /* process each statement result */


        struct res_info* res_info = create_res_info( );
        /* did current statement return data? */
        result = mysql_store_result(mysql);
        if (result){
                /* yes; process rows and free the result set */
                process_result_set(mysql, result, res_info );
                printf("record set\r\n");
                mysql_free_result(result);
        }
        else { /* no result set or error */
                if (mysql_field_count(mysql) == 0){               
                        int affect_rows = (int)mysql_affected_rows(mysql);
                        res_info->affect_rows = affect_rows;
                        printf("%d rows affected\n", affect_rows );
                }
                else{/* some error occurred */
                        response_result->error_flag = 1;
                        printf("Could not retrieve result set\n");
                }
        }
        response_result->res_num = cur_res_info_num + 1;
        sql_results_set_res_info( response_result, cur_res_info_num++, res_info );

        return response_result;
}

struct res_info*exe_sql( MYSQL* mysql, char* sql ) {
        struct res_info* res_info = create_res_info( );
        int status = 0;
        int cur_res_info_num = 0;
        status = mysql_query(mysql,sql );
        if (status){
                res_info->error_code = 1;
                return res_info;       
        }
       
        MYSQL_RES *result;
        /* process each statement result */

        /* did current statement return data? */
        result = mysql_store_result(mysql);
        if (result){
                /* yes; process rows and free the result set */
                process_result_set(mysql, result, res_info );
                printf("record set\r\n");
                mysql_free_result(result);
        }
        else { /* no result set or error */
                if (mysql_field_count(mysql) == 0){               
                        int affect_rows = (int)mysql_affected_rows(mysql);
                        res_info->affect_rows = affect_rows;
                        printf("%d rows affected\n", affect_rows );
                }
                else{/* some error occurred */
                        res_info->error_code = 1;
                        printf("Could not retrieve result set\n");
                }
        }
        //response_result->res_num = cur_res_info_num + 1;
        //sql_results_set_res_info( response_result, cur_res_info_num++, res_info );

        return res_info;
}

struct res_info* exe_sql_make_buffer( MYSQL* mysql, char* sql, char* buffer ) {
        struct res_info* res_info = create_res_info( );
        int status = 0;
        int cur_res_info_num = 0;
        status = mysql_query(mysql,sql );
        if (status){
                res_info->error_code = 1;
                pack_res_info( res_info, buffer );               
                return res_info;       
        }

        MYSQL_RES *result;
        /* process each statement result */

        /* did current statement return data? */
        result = mysql_store_result(mysql);
        if (result){
                /* yes; process rows and free the result set */
                process_result_set(mysql, result, res_info );
                printf("record set\r\n");
                pack_res_info( res_info, buffer );
                mysql_free_result(result);
                return res_info;
        }
        else { /* no result set or error */
                if (mysql_field_count(mysql) == 0){               
                        int affect_rows = (int)mysql_affected_rows(mysql);
                        res_info->affect_rows = affect_rows;
                        printf("%d rows affected\n", affect_rows );
                }
                else{/* some error occurred */
                        res_info->error_code = 1;
                        printf("Could not retrieve result set\n");
                }
        }
        //response_result->res_num = cur_res_info_num + 1;
        //sql_results_set_res_info( response_result, cur_res_info_num++, res_info );
        pack_res_info( res_info, buffer );               
        return res_info;
}


void sql_results_makehead( struct sql_results* results, char* buffer ){
        int offset = 0;
        memcpy( buffer + offset, &results->error_flag, 4);        offset += 4;
        memcpy( buffer + offset, &results->res_num, 4);
}

struct sql_results* exe_sql_muti_makebuffer( MYSQL* mysql, char* sql, char* buffer ) {
        struct sql_results* response_result = sql_results_create( );
        int status = 0;
       
        int offset = 8;
        int result_num = 0;
        int cur_res_info_num = 0;
        status = mysql_query(mysql,sql );
        if (status){
                printf("exe_sql                     mysql_query               error ========================== errormsg=%s\r\n", mysql_error(mysql) );               
                response_result->error_flag = 1;
                response_result->res_num = 0;
                sql_results_makehead( response_result, buffer );
                return response_result;       
        }


       
        MYSQL_RES *result;
        /* process each statement result */
        do {

                struct res_info* res_info = create_res_info( );
                  /* did current statement return data? */
                result = mysql_store_result(mysql);
                if (result){
                        /* yes; process rows and free the result set */
                        process_result_set(mysql, result, res_info );
                        pack_res_info( res_info, buffer+offset );
                        printf("record set\r\n");
                        mysql_free_result(result);
                }
                else { /* no result set or error */
                        if (mysql_field_count(mysql) == 0){               
                                int affect_rows = (int)mysql_affected_rows(mysql);
                                res_info->affect_rows = affect_rows;
                                printf("%d rows affected\n", affect_rows );
                                pack_res_info( res_info, buffer+offset );                               
                                               
                        }
                        else{/* some error occurred */
                                response_result->error_flag = 1;
                                printf("Could not retrieve result set\n");
                                break;
                        }
                }
                response_result->res_num = cur_res_info_num + 1;
                sql_results_set_res_info( response_result, cur_res_info_num++, res_info );
                offset += res_info_total_len( res_info );
                               
                /* more results? -1 = no, >0 = error, 0 = yes (keep looping) */
                if ((status = mysql_next_result(mysql)) > 0){
                        response_result->error_flag = 1;
                        printf("Could not execute statement\n");
                }
        } while (status == 0);
       
        sql_results_makehead( response_result, buffer );
        return response_result;
}

MYSQL mysql;
MYSQL_RES *res;
MYSQL_ROW row;

void run_req( ){
        {                            
                 printf("exe_sql........\r\n");
          char* testmsg = (char*)malloc( sizeof(20000));
                //char testmsg;
                struct sql_results* results = exe_sql_muti_makebuffer( &mysql, "DROP TABLE IF EXISTS test_table;\
                                    CREATE TABLE test_table(id INT);\
                                    INSERT INTO test_table VALUES(10);\
                                    UPDATE test_table SET id=20 WHERE id=10;\
                                    SELECT * FROM test_table;\
                                    select * from Persons;",
       
                testmsg );               
                //struct sql_results* results = exe_sql( &mysql, "select * from persons;" );
                sql_results_set_total_debug( results );
                 printf("end exe_sql........\r\n");
                int total_len = sql_results_set_total_len( results );
                 printf("end exe_sql........len=%d\r\n", total_len );
                sql_results_destroy( results );               

                struct sql_results* results_ = sql_results_create( );
                 printf("begin unpack_sql_results_set........\r\n");
                struct sql_results* result_ret = unpack_sql_results_set( testmsg, total_len );

          printf("end unpack_sql_results_set........\r\n");
                sql_results_set_total_debug( result_ret );
                sql_results_destroy( result_ret );
                free( testmsg );       
          printf("end ........\r\n");
        }
}


int main()
{
        mysql_library_init(0, NULL, NULL );
   mysql_init(&mysql);
   if(!mysql_real_connect(&mysql,"127.0.0.1","root",
                     "","test",3306,NULL,CLIENT_MULTI_RESULTS|CLIENT_MULTI_STATEMENTS))
   {
                //CLIENT_MULTI_RESULTS|CLIENT_MULTI_STATEMENTS
         printf("Error connecting to database:%s\n",mysql_error(&mysql));
   }
   else
         printf("Connected........\r\n");

   char *query = "select * from Persons;";
   int t,r;

        int j = 0;
        for( j = 0; j < 30; j++ ){
          printf("run_req........                     ====================               ------------------          ************* j = %d \r\n", j );
          malloc( 1000 );
                run_req( );
        }
    return 0;

}

Segmentation fault: 11

run_req函数
          char* testmsg = (char*)malloc( sizeof(20000));改为数组形式 比如char testmsg[2000], 则不会崩溃。




请赐教

页: [1]
查看完整版本: mysql c api 多结果集时,上下文分配空间,内存访问越界