mysql\u stmt\u关闭时出现SEGFULT

mysql\u stmt\u关闭时出现SEGFULT,mysql,c,linux,segmentation-fault,prepared-statement,Mysql,C,Linux,Segmentation Fault,Prepared Statement,我正在尝试使用C API查询mysql 5.5。 dbutil.c包含样板代码: #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);

我正在尝试使用C API查询mysql 5.5。
dbutil.c包含样板代码:

#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);
}
以下是实际运行查询的代码:

#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;
}
语句执行并返回预期结果,但代码在命中时出错

mysql_stmt_close(&stmt);
我浏览了一下核心转储文件,发现segfault是由libc free()语句引起的,我猜想它是在libmysql.c中的free_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));
...

具体来说。Core dump表示*stmt.extension在语句关闭时出现。你知道为什么吗?

听起来代码/库正试图
释放()
一些已经释放的内存


通过谷歌搜索,我发现在调用
mysql\u stmt\u close()
之前,您应该检查一下
stmt
是否为NULL。如果
stmt
已为空,则库已将其清除,无需调用
mysql\u stmt\u close()

检查此处的out参数:

char out[200];
...
bind_string_result(&result[0], 200, (char *) &out, &isNull[1], &length);
如果看到绑定字符串结果声明:

void bind_string_result(MYSQL_BIND *result, int stringSize, char* buffer, my_bool *isNull, unsigned long *length) {
当您发送指向
char*
的指针时,函数希望接收类型为
char*
的参数,即
char**

编译器不会给您任何警告,因为您正在将参数强制转换为
char*
,但它可能会在内存中产生冲突。尝试以以下方式调用您的函数:

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

问题实际上是mysql_init(&conn)的问题。由于某些原因,conn未初始化。如果我初始化conn并将其传递给get_connection,那么一切都会按预期工作。