使用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
相关产品推荐
相关产品推荐

