【发布时间】:2017-08-07 22:46:36
【问题描述】:
在我的 C 程序中使用 libpq db 引擎在 postgresql db 中检索数据时遇到问题。存储数据后,我可以使用终端验证其完整性,因此它会保留在数据库中,但是当我尝试访问它时,我得到一个 segv(由于 null ref / ptr)。以下是使用的相关例程/函数。
创建表:
int createTable() {
const char *conninfo = "user=tmp password=pass dbname=testdb hostaddr=127.0.0.1 port=5432 sslmode=require";
PGconn *conn = PQconnectdb(conninfo); /* connect to db */
PGresult *res;
FILE data;
int nFields;
int i, j;
// Make a connection to the database
conn = PQconnectdb(conninfo);
/* Check to see that the backend connection was successfully made */
if (PQstatus(conn) != CONNECTION_OK) {
fprintf(stderr, "Connection to database failed: %s", PQerrorMessage(conn));
PQfinish(conn);
return -1;
}
printDBInfo(conn); // DEBUG
/* drop table if exists */
res = PQexec(conn, "DROP TABLE IF EXISTS Users");
if (PQresultStatus(res) != PGRES_COMMAND_OK) {
failInt(conn, res);
}
PQclear(res);
/* create table */
res = PQexec(conn, "CREATE TABLE Users(username VARCHAR(20) PRIMARY KEY," \
"password VARCHAR(45))");
if (PQresultStatus(res) != PGRES_COMMAND_OK) {
failInt(conn, res);
}
PQclear(res);
/* add some users */
res = PQexec(conn, "INSERT INTO Users (username,password) VALUES ('foo','bar')");
if (PQresultStatus(res) != PGRES_COMMAND_OK) {
fprintf(stderr, "INSERT failed: %s", PQerrorMessage(conn));
failInt(conn, res);
}
PQclear(res);
res = PQexec(conn, "INSERT INTO Users (username,password) VALUES ('foofoo','extrabar')");
if (PQresultStatus(res) != PGRES_COMMAND_OK) {
fprintf(stderr, "INSERT failed: %s", PQerrorMessage(conn));
failInt(conn, res);
}
PQclear(res);
res = PQexec(conn, "INSERT INTO Users (username,password) VALUES ('TheFooestF00','H1gh3stBar')");
if (PQresultStatus(res) != PGRES_COMMAND_OK) {
fprintf(stderr, "INSERT failed: %s", PQerrorMessage(conn));
failInt(conn, res);
}
PQclear(res);
// res = PQexec(conn, "COMMIT");
// if (PQresultStatus(res) != PGRES_COMMAND_OK) {
// printf("COMMIT command failed\n");
// failInt(res, conn);
// }
// PQclear(res);
PQfinish(conn); /* close the connection */
return 0;
}
身份验证(这是我得到某种类型的空引用的地方)
/* TODO: whitelisting / parsing / verifying user and pass */
int authenticateUser(const char *user, const char *pass) {
const char *statement = "SELECT user FROM Users WHERE user=";
size_t query_size = strlen(statement) + strlen(user) + 1;
char *query = malloc(query_size);
memset(query, '\0', query_size);
PGconn *conn = PQconnectdb("user=tmp password=pass dbname=testdb hostaddr=127.0.0.1 port=5432 sslmode=require");
if (PQstatus(conn) == CONNECTION_BAD) {
fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(conn));
PQfinish(conn);
exit(1);
}
strcat(query, statement);
strcat(query, user);
strcat(query, "\0");
printf("query: %s\n",query);
PGresult *res = PQexec(conn, query);
printf("num of tuples: %i\n", PQntuples(res));
printf("num of columns: %i\n", PQnfields(res));
// PQprintTuples(res, STDOUT_FILENO, )
if (PQresultStatus(res) != PGRES_TUPLES_OK) {
printf("No data retrieved\n");
failInt(conn, res);
}
const char *pass_check = PQgetvalue(res, 0, 1);
if (strcmp(user, pass_check) == 0) {
success(conn, res);
}
PQclear(res);
PQfinish(conn);
return -1;
}
而且我知道它需要一些输入验证,这是列表中的下一个 :)
编辑:
GDB 输出
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff787c9de in ?? () from /lib/x86_64-linux-gnu/libc.so.6
(gdb) backtrace
#0 0x00007ffff787c9de in ?? () from /lib/x86_64-linux-gnu/libc.so.6
#1 0x0000000000402520 in authenticateUser (user=0x402b05 "foo", pass=0x402b1d "bar") at /pwdmanlib/src/db/database.h:272
#2 0x000000000040266b in main () at /pwdmanlib/src/test/db_test.c:51
(gdb) frame 1
#1 0x0000000000402520 in authenticateUser (user=0x402b05 "foo", pass=0x402b1d "bar") at /pwdmanlib/src/db/database.h:272
272 if (strcmp(user, pass_check) == 0) {
(gdb) next
Cannot find bounds of current function
这一行:const char *pass_check = PQgetvalue(res, 0, 1); 返回一个空 ptr,我不知道为什么,因为在此之前我用相同的 args 调用了相同的函数并且它可以工作。
【问题讨论】:
-
请在
gdb中运行您的代码以准确了解分段错误发生的位置(并使用-g 编译它)。valgrind也有很大帮助。 -
strcat(query, statement); strcat(query, user); strcat(query, "\0");请不要这样做。相反,请使用准备好的查询,这也将解决您的引用问题。 -
好主意@wildplasser 我也会实现它,但我仍然不确定为什么会出现空引用(如上面的 gdb 调试输出所示)。我知道其中有数据db 中的行,我可以从 cmd 行查询和接收,但是当我尝试通过 c 函数获取它时,它返回 null ptr
标签: c database postgresql null data-retrieval