2012-09-30 4 views
3

C API를 사용하여 mysql 5.5를 쿼리하려고한다. 이Segfault mysql_stmt_close

을 칠 때

#include "../include/dbutil.h" 

int main() { 
    MYSQL conn = get_connection("localhost", "user", "pass", "test"); 
    MYSQL_STMT stmt = prepare_stmt(&conn, "SELECT hostname from hosts where id = ?"); 
    MYSQL_BIND param[1], result[1]; 

    memset(param, 0, sizeof(param)); 
    memset(result, 0, sizeof(result)); 

    int in = 1; 
    unsigned long length = 200; 
    my_bool isNull[2]; 
    isNull[0] = 0; 

    char out[200]; 
    bind_param(&param[0], MYSQL_TYPE_LONG, (char *) &in, &isNull[0], (unsigned long *)0); 
    bind_string_result(&result[0], 200, (char *) &out, &isNull[1], &length); 

    mysql_stmt_bind_param(&stmt, param); 
    mysql_stmt_execute(&stmt); 
    mysql_stmt_bind_result(&stmt, result); 
    mysql_stmt_store_result(&stmt); 
    mysql_stmt_fetch(&stmt); 

    printf("Restult %s\n", out); 

    mysql_stmt_close(&stmt); 
    mysql_close(&conn); 

    return 0; 
} 

문이 실행하고 예상 된 결과를 반환하지만 코드 세그먼테이션 폴트 (segfault) : 여기

#include "../include/dbutil.h" 
#include "../include/logging.h" 
#include "../include/common.h" 

MYSQL get_connection(char *host, char *user, char *passwd, char *db) { 
    MYSQL conn; 
    mysql_init(&conn); 
    if (!mysql_real_connect(&conn, host, user, passwd, db, 0, NULL, 0)) { 
     log_to_console("Cannot connect to MySQL server: %s", mysql_error(&conn)); 
     exit(1); 
    } 
    return conn; 
} 

MYSQL_STMT prepare_stmt(MYSQL *conn, char *sql) { 
    MYSQL_STMT *stmtP = mysql_stmt_init(conn); 
    if (!stmtP) { 
     log_to_console("Cannot create statement, out of memory."); 
     exit(1); 
    } 

    MYSQL_STMT stmt = *stmtP; 

    if (mysql_stmt_prepare(&stmt, sql, strlen(sql))) { 
     log_to_console("Preparing statement failed: %s", mysql_error(conn)); 
     exit(1); 
    } 

    return stmt; 
} 

void bind_param(MYSQL_BIND *param, enum enum_field_types fieldType, char* buffer, my_bool *isNull, unsigned long *length) { 
    param->buffer_type = fieldType; 
    param->buffer = buffer; 
    param->is_null = isNull; 
    param->length = length; 
} 

void bind_string_param(MYSQL_BIND *param, int stringSize, char* buffer, my_bool *isNull, unsigned long *length) { 
    bind_param(param, MYSQL_TYPE_STRING, buffer, isNull, length); 
    param->buffer_length = stringSize; 
} 

void bind_result(MYSQL_BIND *result, enum enum_field_types fieldType, char* buffer, my_bool *isNull, unsigned long *length) { 
    bind_param(result, fieldType, buffer, isNull, length); 
} 

void bind_string_result(MYSQL_BIND *result, int stringSize, char* buffer, my_bool *isNull, unsigned long *length) { 
    bind_string_param(result, stringSize, buffer, isNull, length); 
} 

실제로 쿼리를 실행하는 코드입니다 :
dbutil.c은 상용구 코드가 포함되어 있습니다
mysql_stmt_close(&stmt); 

코어 덤프 주위를 뚫고 segfault가 libc free() 문에 의해 발생한다는 것을 발견했습니다.이 문은 f libmysql.c의 ree_root()를

my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt) 
{ 
    MYSQL *mysql= stmt->mysql; 
    int rc= 0; 
    DBUG_ENTER("mysql_stmt_close"); 

    free_root(&stmt->result.alloc, MYF(0)); 
    free_root(&stmt->mem_root, MYF(0)); 
    free_root(&stmt->extension->fields_mem_root, MYF(0)); 
... 

으로 지정하십시오. 코어 덤프는 * stmt.extension이 명령문 닫기가 발생한다고 말합니다. 왜 그런 아이디어가 있니?

답변

1

코드/라이브러리가 이미 릴리스 된 일부 메모리 인 free()을 시도하는 것 같습니다.

Google 검색 후 this link.mysql_stmt_close()을 호출하기 전에 stmt이 NULL이 아닌지 확인해야하는 것으로 보입니다. stmt이 이미 NULL이면 라이브러리가 이미 정리 했으므로 mysql_stmt_close()을 호출 할 필요가 없습니다. 여기 out 매개 변수에

1

확인 :

char out[200]; 
... 
bind_string_result(&result[0], 200, (char *) &out, &isNull[1], &length); 

당신은 당신의 bind_string_result 선언을 참조하는 경우 :

당신이 포인터를 전송하는 동안 기능 유형 char *의 매개 변수를받을 것으로 예상된다
void bind_string_result(MYSQL_BIND *result, int stringSize, char* buffer, my_bool *isNull, unsigned long *length) { 

a char * 즉, a char **

컴파일러는 사용자에게 경고하지 않습니다. 매개 변수를 char *으로 캐스팅했으나 메모리에 충돌이 발생할 수 있습니다. 함수 호출은 다음과 같습니다 :

bind_string_result(&result[0], 200, out, &isNull[1], &length); 
+0

실제로 문제는 mysql_init (& conn)입니다. 어떤 이유로 conn이 초기화되지 않습니다. conn을 초기화하고 get_connection에 전달하면 모든 것이 예상대로 작동합니다. – cbaby