2017-03-16 17 views
0

Cプログラム内でlibpq db engineを使用してpostgresql dbでデータを取得する際に問題が発生しました。私はデータを格納した後、私は自分の端末を使ってその整合性を確認することができますので、DBに残っていますが、私はそれにアクセスしようとするとsegv(ヌルref/ptrのため)を取得します。以下は、使用される関連ルーチン/関数です。テーブルの作成CプログラムでPostgreSQLからデータを取得する

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; 
} 

認証(私がnull参照のいくつかのタイプを取得する場所です)

/* 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; 
} 

そして、私はそれはいくつかの入力検証が必要であることを知って、それは上の横にありますリスト:)

EDIT:

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);は、null ptrを返します。なぜなら、私は同じ前に同じ引数を指定して同じ関数を呼び出して動作させるからです。

+0

セグメント化エラーが発生した場所を正確に知るには、gdbでコードを実行してください(そして-gを付けてコンパイルしてください)。 'valgrind'も大いに役立ちます。 –

+0

'strcat(query、statement); strcat(query、user); strcat(query、 "\ 0"); 'しないでください。代わりに、あなたの引用問題を解決する準備されたクエリを使用してください。 – wildplasser

+0

素晴らしいアイデア@wildplasser私もそれを実装しますが、null ref(上記のgdbデバッグ出力に表示されているように)がなぜ発生しているのかはまだ分かりません。dbの行にデータがあり、クエリとcmdの行から受け取るが、私はそれを取得するためにしようとすると、それはnull ptrを返します –

答えて

0

元の質問に答えるには、クエリの構文が正しくないことを尋ねました。クエリで要求された(1)値を返すため、0,0でPQgetvalueを実行しました。私はもともと考えていた)。この問題を抱えている他の人のために、完全に実装されています。ハッピーハッキング:

int authenticateUser(const char *user, const char *pass) { 
    const char *statement = "SELECT password FROM Users WHERE username='"; 
    size_t query_size = strlen(statement) + strlen(user) + 3; 
    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); 
     return -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"); 
     return failInt(conn, res); 
    } 

    char *pass_check = PQgetvalue(res, 0, 0); 
    if (strcmp(pass, pass_check) == 0) { 
     return success(conn, res); 
    } 

    PQclear(res); 
    PQfinish(conn); 
    return -1; 
} 
関連する問題