首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >成功执行的查询上的mysql_stmt_free_result分段错误

成功执行的查询上的mysql_stmt_free_result分段错误
EN

Stack Overflow用户
提问于 2017-05-20 17:03:38
回答 1查看 394关注 0票数 0

我使用MySQL C与我的数据库进行通信。我目前正在迁移到使用准备好的语句。然而,mysql_stmt_free_result会导致分段错误,我不知道原因。

代码语言:javascript
复制
#define SENSOR_SQL_GET_KEY "SELECT `password` FROM `station` "  \
    "WHERE `station_id`=?;"
int32_t sensor_get_station_key(struct Sensor_Handle *handle, char *key, uint32_t size,
                               uint32_t station_id)
{
    MYSQL_BIND bind;
    uint32_t length;
    MYSQL_STMT *stmt = handle->stmt_get_key;

    memset(&bind,0,sizeof(bind));
    bind.buffer_type=MYSQL_TYPE_LONG;
    bind.buffer=&station_id;
    bind.is_unsigned = 1;

    check(mysql_stmt_bind_param(stmt, &bind)==0, "mysql_stmt_bind_param failed: %s",
          mysql_stmt_error(stmt));
    check(mysql_stmt_execute(stmt)==0, "mysql_stmt_execute failed: %s",
          mysql_stmt_error(stmt));

    memset(&bind,0,sizeof(bind));
    bind.buffer_type=MYSQL_TYPE_STRING;
    bind.buffer=key;
    bind.buffer_length=size;
    bind.length=(unsigned long*)&length;

    check(mysql_stmt_bind_result(stmt, &bind)==0, "mysql_stmt_bind_result failed");

    check(mysql_stmt_store_result(stmt)==0, "mysql_stmt_store_result failed: %s",
          mysql_stmt_error(stmt));

    check(mysql_stmt_num_rows(stmt)==1,
          "mysql_stmt_num_rows didn't return 1, for station_id %i", station_id);

    check(mysql_stmt_fetch(stmt)==0,
          "mysql_stmt_fetch_result failed: %s", mysql_stmt_error(stmt));

    mysql_stmt_free_result(stmt); //segfaults

    return length;

error:
    mysql_stmt_free_result(handle->stmt_get_key);

    return -1;
}

我已经标记了导致分段错误的行(使用gdb回溯获得)。如果我注释这一行,一切正常,key (调用函数中声明的堆栈上的一个32字节数组)被数据库中正确的32字节字符串填充。因此,查询确实成功执行。

另一方面,在下面的代码中,mysql_stmt_free_result执行时没有导致分段错误,这让我感到困惑,因为代码的结构非常相似。

代码语言:javascript
复制
#define SENSOR_SQL_CHECK_SENSOR_STATION "SELECT `station_id` FROM `sensor` " \
    "WHERE sensor_id = ?"
int32_t sensor_check_sensor_station(struct Sensor_Handle *handle, uint32_t sensor_id, uint32_t station_id)
{    
    MYSQL_BIND bind;
    uint32_t id;
    MYSQL_STMT *stmt = handle->stmt_check_sensor_station;

    memset(&bind,0,sizeof(bind));
    bind.buffer_type=MYSQL_TYPE_LONG;
    bind.buffer=&sensor_id;
    bind.is_unsigned = 1;

    check(mysql_stmt_bind_param(stmt, &bind)==0,
          "mysql_stmt_bind_param failed: %s", mysql_stmt_error(stmt));
    check(mysql_stmt_execute(stmt)==0,
          "mysql_stmt_execute failed: %s", mysql_stmt_error(stmt));

    check(mysql_stmt_store_result(stmt)==0,
          "mysql_stmt_store_result failed: %s", mysql_stmt_error(stmt));

    if(!mysql_stmt_num_rows(stmt)) //sensor_id doesn't exist
    {
        mysql_stmt_free_result(stmt);
        return 0;
    }

    memset(&bind,0,sizeof(bind));
    bind.buffer_type=MYSQL_TYPE_LONG;
    bind.buffer=&id;
    bind.is_unsigned=1;

    check(mysql_stmt_bind_result(stmt, &bind)==0, "mysql_stmt_bind_result failed");

    check(mysql_stmt_fetch(stmt)==0,
          "mysql_stmt_fetch_result failed: %s", mysql_stmt_error(stmt));    

    mysql_stmt_free_result(stmt); //no problem

    if(id == station_id)
        return 1;
    else
        return 0;

error:
    return -1;
}

我还对代码使用,它没有报告任何内存访问错误。我在实际的查询中包含了定义,这些查询用于在一个单独的函数中准备语句。

更多信息:

我把我准备好的陈述储存在

代码语言:javascript
复制
struct Sensor_Handle
{
    MYSQL *connection;

    MYSQL_STMT *stmt_get_key;
    MYSQL_STMT *stmt_check_sensor_station;
    etc.
};

我把他们都准备好了

代码语言:javascript
复制
int32_t sensor_create_statement(struct Sensor_Handle *handle, MYSQL_STMT **stmt_out, char *sql)
{
    MYSQL_STMT *stmt;

    stmt = mysql_stmt_init(handle->connection);
    check(stmt, "mysql_stmt_init failed: Out of Memory");

    check(mysql_stmt_prepare(stmt, sql, strlen(sql))==0,
          "mysql_stmt_prepare failed: %s", mysql_stmt_error(stmt));
    *stmt_out = stmt;

    return 0;

error:
    return -1;
}

int32_t sensor_statement_init(struct Sensor_Handle *handle)
{
    MYSQL_STMT *stmt;

    //sensor_get_station_key
    check(sensor_create_statement(handle, &stmt, SENSOR_SQL_GET_KEY)==0,
          "sensor_create_statement failed");
    handle->stmt_get_key = stmt;

    //sensor_check_sensor_station
    check(sensor_create_statement(handle, &stmt, SENSOR_SQL_CHECK_SENSOR_STATION)==0,
          "sensor_create_statement failed");
    handle->stmt_check_sensor_station = stmt;

    return 0;

error:
    return -1;
}

在另一个函数中调用分段错误的函数如下:

代码语言:javascript
复制
char key[AES_KEY_SIZE];

i=sensor_get_station_key(handle, key, sizeof(key), station_id);
check(i==AES_KEY_SIZE,
      "sensor_get_station_id didn't return the expected keysize. Got: %i, expected: %i",
      i, AES_KEY_SIZE);

因此,如您所见,如果我移除mysql_stmt_free_result,它甚至返回预期的键大小。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-05-20 22:08:51

代码语言:javascript
复制
uint32_t length;
...
bind.length=(unsigned long*)&length;

这是不安全的,bind.length被声明为一个无符号的长指针,但是您传递的是32位uint32_t的地址。如果是的话,一个未签名的long可能是64位,如果最终在mysql写入它时会导致堆栈损坏。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44088660

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档