Sqlite3 и pthread, двойное освобождение или искажение (выход) - PullRequest
0 голосов
/ 28 декабря 2018

Я пытаюсь создать поток, который подключается к базе данных, получает оттуда некоторые данные и выводит их на консоль.Проблема в том, что когда этот поток завершает работу, генерируется исключение:

двойное освобождение или повреждение (выход) Прервано (ядро сброшено)

Я пытаюсьиспользовать sqlite3 и pthread, и эти двое на самом деле не друзья.

Я думаю, но я не уверен, что проблемы связаны с классом Database.

Кто-нибудь знает, что вызывает исключение?Вот мой код: ссылка

Класс базы данных:

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 голосов
/ 29 декабря 2018

Вы разыменовываете data, переданное CallBack в ((char **)data)[index], но его значение было передано из data в Select через обратный вызов sqlite3_exec.data in Select было выделено для in:

char **data = (char **)malloc(0);

Вы не можете разыменовать указатель на распределение нулевой длины.Также обратите внимание, что поведение malloc нулевого размера определяется реализацией, поэтому его следует избегать (как и malloc в C ++ в любом случае в предпочтении new).


Послеedit:

Теперь data возвращается из Select без какой-либо записи в него, но затем разыменовывается в

returnData[0]

в FunctioForThread.Это неопределенное поведение.

Более того, sizeof(argv[i - index]) не возвращает длину строки, на которую указывает argv[i - index].Он вернет размер указателя типа.Вероятно, поэтому ваши ассигнования будут слишком малы, опять же неопределенное поведение.Используйте std::strlen, чтобы получить длину строки с нулевым символом в конце.

Тогда указатель argv[i - index] также может быть NULL, чтобы указать значение NULL в возвращенной строке (см. Документацию ).sqlite3_exec).В этом случае strcpy извлечение из него также будет неопределенным поведением.

Цикл while (dataToReturn[index]) вызовет неопределенное поведение, поскольку массив для dataToReturn был выделен, но его элементы никогда не установлены.Даже если значения были заданы, обратите внимание, что условие выполняется тогда и только тогда, когда строка в стиле C dataToReturn[index] указывает на нулевую длину.Если такая строка не существует в выделенном диапазоне, снова поведение не определено.


У вас также есть утечки памяти, потому что вы никогда не free какие-либо из ваших malloc ed данных и потому что dataToReturn отбрасывается в конце каждого вызова CallBack, это не очень полезно.


Нет веских оснований для использования всех этих конструкций в стиле C.Используйте new вместо malloc, std::string и std::vector вместо char массивов, std::cout и std::cerr вместо printf и fprintf(stcerr, ..., std::thread вместо pthreads.Единственный момент, когда эти вещи необходимо учитывать, - это граница интерфейса с библиотекой C.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...