Sqlite3和pthread,双重释放或损坏(输出)

时间:2018-12-28 20:50:04

标签: c++ linux sqlite pthreads

我尝试创建一个连接数据库的线程,从那里获取一些数据并打印到控制台。问题在于,当该线程完成时会引发异常:

双重释放或腐败(淘汰) 已中止(核心已弃用)

我尝试使用sqlite3和pthread,但这两个并不是真正的朋友。

我认为,但是我不确定问题是否来自数据库类。

任何人都知道产生异常的原因是什么? 这是我的代码:link

数据库类:

class Database {
private:
  sqlite3 *db;
  static int CallBack(void *data, int argc, char **argv, char **azColName)
  {
    int index = 0;
    char** dataToReturn = new char*[1000];

    while (dataToReturn[index])
    {
        index++;
    }

    for (int i = index; i < argc + index; i++)
    {
        dataToReturn[i] = (char *)malloc(sizeof(char) * sizeof(argv[i - index]));
        strcpy((dataToReturn)[i], argv[i - index]);
    }

    return 0;
}

public:
  char **Select()
  {
    char *zErrMsg = 0;
    int rc;

    rc = sqlite3_open("test.db", &db);

    if (rc)
    {
        fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
        exit(1);
    }
    else
    {
        fprintf(stderr, "Opened database successfully\n");
    }
    char **data;

    int rc2 = sqlite3_exec(db, "SELECT * FROM SHARED_FILE", CallBack, data, &zErrMsg);

    if (rc2 != SQLITE_OK)
    {
        sqlite3_free(zErrMsg);
        exit(2);
    }

    sqlite3_close(db);
    return data;
}

线程功能:

static void FunctioForThread()
{
    printf("start");

    auto database = new Database();
    char** returnData = database->Select();

    printf("something from db: %s \n", returnData[0]);
    printf("stop");
}

static void *threadd(void *arg)
{
    pthread_detach(pthread_self());
    fflush(stdout);

    FunctioForThread();
}

主要功能:

int main()
{
    pthread_t thread;
    char arg[100] = "test";
    pthread_create(&thread, NULL, &threadd, arg);

    while(1);
}

1 个答案:

答案 0 :(得分:1)

您要取消引用data中传递给CallBack的{​​{1}},但其值是通过{{1}的回调从((char **)data)[index]中的data传递的}。 Select中的sqlite3_exec已分配给:

data

不允许您取消引用指向零长度分配的指针。还要注意,零尺寸Select的行为是实现定义的,因此应避免使用(就像C ++中的char **data = (char **)malloc(0); 应该优先于malloc一样)。


编辑后:

现在mallocnew返回,而从未写入,但随后在其中取消引用

data
Select

。那是不确定的。

此外,returnData[0] 不返回FunctioForThread指向的字符串的长度。它将返回指针类型的大小。因此,您的分配可能会太小,再次是未定义的行为。使用sizeof(argv[i - index])获取以零结尾的字符串的长度。

然后,指针argv[i - index]也可以是std::strlen,以指示返回行中的argv[i - index]值(请参见documentation of sqlite3_exec)。在这种情况下,NULL的行为也将是未定义的行为。

循环NULL将导致未定义的行为,因为已分配了strcpy的数组,但从未设置其元素。 即使设置了值,也请注意,并且仅当C样式字符串while (dataToReturn[index])指向长度为零时,该条件才得到满足。如果在分配的范围内不存在这样的字符串,则行为将再次不确定。


您还存在内存泄漏,因为您从未dataToReturn编辑过任何数据dataToReturn[index],并且由于free在每个CallBack调用结束时被丢弃,因此它不是很有用。 / p>


没有充分的理由使用所有这些C样式的构造。使用malloc代替dataToReturnnewmalloc代替std::string数组,使用std::vectorchar代替{{1 }}和std::cout,而不是std::cerrprintf。唯一需要考虑的事情就是C库的接口边界。