Sqlcipher keeps crashing if macOS > 13.0-beta.2

Description

We are now able to reproduce crashes with lib sqlcipher if macOS >= 13.0-beta.2. Here are the minimal test sample steps.

Compile Sqlchiper

git clone https://github.com/sqlcipher/sqlcipher
cd sqlcipher
mkdir out
./configure --enable-tempstore=yes CFLAGS="-DSQLITE_HAS_CODEC" LDFLAGS="-framework CoreFoundation -framework Security" --with-crypto-lib=commoncrypto --prefix=$PWD/out
make install

Reproduce Crash

// main.c

#include "sqlite3.h"
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>

void ensure_ok(sqlite3 *handle, int code)
{
    if (code == SQLITE_OK)
    {
        return;
    }
    printf("ERROR %d %s\n", code, sqlite3_errmsg(handle));
    exit(1);
}

void run(sqlite3 *handle, const char *sql, void (*callback)(sqlite3_stmt *))
{
    sqlite3_stmt *stmt = NULL;
    char *unused = NULL;
    int sql_len = strlen(sql);
    int code = sqlite3_prepare_v2(handle, sql, sql_len, &stmt, &unused);
    ensure_ok(handle, code);
    code = SQLITE_ROW;
    while (code != SQLITE_DONE)
    {
        code = sqlite3_step(stmt);
        if (code != SQLITE_ROW && code != SQLITE_DONE)
        {
            printf("ERROR %d %s\n", code, sqlite3_errmsg(handle));
            exit(1);
        }
        if (callback != NULL)
        {
            callback(stmt);
        }
    }
    code = sqlite3_finalize(stmt);
    ensure_ok(handle, code);
}

void init_db(sqlite3 *handle)
{
    run(handle, "PRAGMA key = '114514'", NULL);
    run(handle, "PRAGMA cipher_compatibility = '3'", NULL);
    run(handle, "PRAGMA busy_timeout = '5000'", NULL);
    run(handle, "PRAGMA journal_mode = 'WAL'", NULL);
}

sqlite3 *open_db()
{
    char path[256] = {0};
    pid_t pid = getpid();
    sprintf(&path, "/tmp/%d", pid);
    mkdir(&path, 0777);
    sprintf(&path, "/tmp/%d/a.db", pid);
    sqlite3 *ret = NULL;
    int code = sqlite3_open(&path, &ret);
    ensure_ok(ret, code);
    init_db(ret);
    return ret;
}

void close_db(sqlite3 *handle)
{
    int code = sqlite3_close(handle);
    ensure_ok(handle, code);
}

int positive_rand(int start, int end)
{
    unsigned int ret = (unsigned int)rand();
    return (ret % (end - start)) + start;
}

void alloc_test()
{
    int count = positive_rand(128, 1024);
    for (int i = 0; i < count; i++)
    {
        int count2 = positive_rand(512, 1024);
        int **ll = malloc(sizeof(int *) * count2);
        for (int j = 0; j < count2; j++)
        {
            int count3 = positive_rand(0, 1024);
            int *l = malloc(sizeof(int) * count3);
            memset(l, i ^ j, count3);
            ll[j] = l;
        }
        for (int j = 0; j < count2; j++)
        {
            free(ll[j]);
        }
        free(ll);
    }
}

void run_thread(void *data)
{
    alloc_test();
    sqlite3 *db = open_db();
    sqlite3_close(db);
}

int main(void)
{
    sqlite3 *db = open_db();
    run(db, "CREATE TABLE student(id INTEGER, name STRING)", NULL);
    close_db(db);
    pthread_t threads[64];
    for (int i = 0; i < 64; i++)
    {
        pthread_create(&threads[i], NULL, run_thread, NULL);
    }
    for (int i = 0; i < 64; i++)
    {
        pthread_join(threads[i], NULL);
    }
    printf("done\n");
    return 0;
}

Put the above content to main.c file, then:

clang main.c -o demo -L ./sqlcipher/out/lib/ -I ./sqlcipher/out/include/ -lsqlcipher
export MallocScribble=1 # This will make crash easier
export MallocPreScribble=1
./demo # Execute this binaray mulitple times, you will see the crash

Since we can't reproduce the same crash if macOS < 13.0-beta.2, is there any change with beta2 that related to malloc?

Looking forward to getting the official feedback.

Sqlcipher keeps crashing if macOS &gt; 13.0-beta.2
 
 
Q