You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用C语言+SQLite3开发CGI程序遭遇EXC_BAD_ACCESS错误求助

问题描述

使用C语言结合SQLite3开发CGI可执行程序时遇到EXC_BAD_ACCESS错误,调试器停在main.c第37行的sqlite3_exec调用处,错误信息为EXC_BAD_ACCESS (code=1, address=0x2a205443454c45c4),无法在变量视图中找到该地址,使用CLion作为编辑器。

相关代码

main.c

#include <stdio.h>
#include <stdlib.h>
#include <sqlite3.h>
#include "sqlite.h"

int callback(void *, int, char **, char **);

int main() {

    printf("Content-Type: text/html\n\n");

    sqlite_container *ptr = get_sql();

    char *sql_query = "DROP TABLE IF EXISTS Cars;"
                "CREATE TABLE Cars(Id INT, Name TEXT, Price INT);"
                "INSERT INTO Cars VALUES(1, 'Audi', 52642);"
                "INSERT INTO Cars VALUES(2, 'Mercedes', 57127);"
                "INSERT INTO Cars VALUES(3, 'Skoda', 9000);"
                "INSERT INTO Cars VALUES(4, 'Volvo', 29000);"
                "INSERT INTO Cars VALUES(5, 'Bentley', 350000);"
                "INSERT INTO Cars VALUES(6, 'Citroen', 21000);"
                "INSERT INTO Cars VALUES(7, 'Hummer', 41400);"
                "INSERT INTO Cars VALUES(8, 'Volkswagen', 21600);";

    int rc = sqlite3_exec(ptr->db, sql_query, 0, 0, 0);

    if (rc != SQLITE_OK) {

        fprintf(stderr, "Failed to fetch data: %s\n", sqlite3_errmsg(ptr->db));
        sqlite3_close(ptr->db);

        return 1;
    }

    ptr = "SELECT * FROM Cars";

    rc = sqlite3_exec(ptr->db, sql_query, callback, 0, 0);

    if (rc != SQLITE_OK ) {

        fprintf(stderr, "Failed to select data\n");
        fprintf(stderr, "SQL error: %s\n", sqlite3_errmsg(ptr->db));

        sqlite3_close(ptr->db);

        return 1;
    }

    sqlite3_close(ptr->db);

    printf("%s\n", sqlite3_libversion());

    return 0;
}

int callback(void *NotUsed, int argc, char **argv,
             char **azColName) {

    NotUsed = 0;

    for (int i = 0; i < argc; i++) {

        printf("<pre>%s = %s</pre>\n", azColName[i], argv[i] ? argv[i] : "NULL");
    }

    printf("\n");

    return 0;
}

sqlite.h

#pragma once
#include <sqlite3.h>

typedef struct {
    struct sqlite3 *db;
    int status;
} sqlite_container;

sqlite_container *get_sql();

sqlite.c

#include "sqlite.h"
#include <sqlite3.h>
#include <stdio.h>
#include <stdlib.h>
#include "config.h"

sqlite_container* get_sql() {
    sqlite_container* container = malloc(sizeof(struct sqlite_container *));
    container->db = NULL;
    container->status = 0;

    int rc = sqlite3_open(DATABASEFILE, &container->db);
    container->status = rc;

    if (rc != SQLITE_OK) {
        fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(container->db));
        sqlite3_close(container->db);
    }
    return container;
}

config.h

#pragma once

#define DATABASEFILE "test.sql"

错误原因及修复方案

1. 致命指针类型错误(直接触发崩溃)

main.c中执行建表插入后,错误地将字符串字面量赋值给sqlite_container*类型的ptr指针:

ptr = "SELECT * FROM Cars";

这会让ptr指向字符串内存而非原结构体,后续ptr->db访问的是无效内存,直接导致EXC_BAD_ACCESS。

修复:
创建独立字符串变量存储查询语句,保留ptr指向原结构体:

// 替换原错误赋值代码
char *select_query = "SELECT * FROM Cars";
rc = sqlite3_exec(ptr->db, select_query, callback, 0, 0);

2. 内存分配大小错误

sqlite.c中malloc时错误使用结构体指针大小而非结构体本身大小:

sqlite_container* container = malloc(sizeof(struct sqlite_container *));

分配的内存不足以容纳sqlite_container结构体,会引发内存越界和未定义行为。

修复:
修改为分配结构体实际大小:

sqlite_container* container = malloc(sizeof(sqlite_container));

3. 数据库打开失败后的错误处理漏洞

当sqlite3_open失败时,container->db可能为NULL,此时调用sqlite3_errmsg和sqlite3_close会触发额外错误,且未释放已分配的结构体内存,造成泄漏。

修复:
调整get_sql()的错误处理逻辑:

if (rc != SQLITE_OK) {
    fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(container->db));
    if (container->db != NULL) {
        sqlite3_close(container->db);
    }
    free(container);
    return NULL;
}

同时在main.c中增加空指针检查:

sqlite_container *ptr = get_sql();
if (ptr == NULL) {
    fprintf(stderr, "Failed to initialize database connection\n");
    return 1;
}

4. 内存泄漏问题

main.c中未释放get_sql()分配的sqlite_container结构体内存。

修复:
在关闭数据库后添加释放操作:

sqlite3_close(ptr->db);
free(ptr);

修复后的main.c关键代码片段

int main() {

    printf("Content-Type: text/html\n\n");

    sqlite_container *ptr = get_sql();
    if (ptr == NULL) {
        fprintf(stderr, "Failed to initialize database connection\n");
        return 1;
    }

    char *sql_query = "DROP TABLE IF EXISTS Cars;"
                "CREATE TABLE Cars(Id INT, Name TEXT, Price INT);"
                "INSERT INTO Cars VALUES(1, 'Audi', 52642);"
                "..."; // 省略其余插入语句

    int rc = sqlite3_exec(ptr->db, sql_query, 0, 0, 0);

    if (rc != SQLITE_OK) {
        fprintf(stderr, "Failed to fetch data: %s\n", sqlite3_errmsg(ptr->db));
        sqlite3_close(ptr->db);
        free(ptr);
        return 1;
    }

    char *select_query = "SELECT * FROM Cars";
    rc = sqlite3_exec(ptr->db, select_query, callback, 0, 0);

    if (rc != SQLITE_OK ) {
        fprintf(stderr, "Failed to select data\n");
        fprintf(stderr, "SQL error: %s\n", sqlite3_errmsg(ptr->db));
        sqlite3_close(ptr->db);
        free(ptr);
        return 1;
    }

    sqlite3_close(ptr->db);
    free(ptr);

    printf("%s\n", sqlite3_libversion());

    return 0;
}

内容的提问来源于stack exchange,提问作者Hendrik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 04:34:52