ibarwick / libfq

A wrapper library for Firebird's C API, loosely based on PostgreSQL's libpq.
https://libfq.sql-info.de/
8 stars 2 forks source link

Segmentation fault #6

Closed mkgrgis closed 1 year ago

mkgrgis commented 1 year ago

The last fbsql + libfq with (gdb) run, around of https://github.com/ibarwick/libfq/blob/ff56b4d898d654cca5cab97a89ea2804ecd435ec/src/libfq.c#L2564

Starting program: /usr/bin/fbsql -d /tmp/test.fdb -u SYSDBA -p masterkey
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
fbsql 0.2.0
[New Thread 0x7ffff70bb700 (LWP 11195)]
[Thread 0x7ffff70bb700 (LWP 11195) exited]
[New Thread 0x7ffff68ba700 (LWP 11196)]
[New Thread 0x7ffff2cda700 (LWP 11197)]
[New Thread 0x7ffff24d9700 (LWP 11198)]

Thread 1 "fbsql" received signal SIGSEGV, Segmentation fault.
0x00007ffff7fa3b33 in FQgetisnull (res=res@entry=0x555555f0a790, 
    row_number=row_number@entry=0, column_number=column_number@entry=0)
    at src/libfq.c:2564
2564        if (res->tuples[row_number]->values[column_number]->has_null == true)
ibarwick commented 1 year ago

Hmm, can't reproduce this, though I see what might be happening.

mkgrgis commented 1 year ago

Maybe some initial query inside fbsql, if only /usr/bin/fbsql -d /tmp/test.fdb there is no error, just message need -u username and exit 01. Firebird_fdw isn't affected.

ibarwick commented 1 year ago

Which Firebird version?

How did you create /tmp/test.fdb?

Does the segfault occur if you execute /usr/bin/fbsql -d /tmp/test.fdb -u SYSDBA -p masterkey normally, i.e not with gdb?

Can you get a backtrace?

Does the segfault occur with a different Firebird database (i.e. not /tmp/test.fdb)?

Can you reproduce this in another environment?

The two queries which are executed at startup are:

SELECT CAST(rdb$get_context('SYSTEM', 'ENGINE_VERSION') AS VARCHAR(10)) FROM rdb$database

and

    SELECT TRIM(rdb$character_set_name) AS client_encoding,
           mon$character_set_id AS client_encoding_id
      FROM mon$attachments
INNER JOIN rdb$character_sets
        ON mon$character_set_id = rdb$character_set_id
     WHERE mon$remote_pid = %i

(where %i is the PID of the current process).

Best I can tell is there is some situation where the query appears successful but the result tuples array doesn't get populated, it would be useful to be able to reproduce what is happening.

mkgrgis commented 1 year ago

Which Firebird version?

3.0.7

How did you create /tmp/test.fdb?

isql-fb simple CREATE DATABASE, unfortunately there is no exact script with parameters.

For a new test there is segfault with this empty databases:

CREATE DATABASE '/tmp/Test0.fdb' USER 'SYSDBA' PASSWORD 'masterkey' DEFAULT CHARACTER SET NONE;
CREATE DATABASE '/tmp/Test1.fdb' USER 'SYSDBA' PASSWORD 'masterkey' DEFAULT CHARACTER SET UTF8;

Does the segfault occur if you execute /usr/bin/fbsql -d /tmp/test.fdb -u SYSDBA -p masterkey normally, i.e not with gdb?

Yes. At first I noticed the segmentation fault without gdb.

Can you get a backtrace?

Unfortunately, I do not really understand the format you need. Here are only nesting of functions with very abstract call parameters.

(gdb) backtrace
#0  0x00007ffff7fa3b33 in FQgetisnull (res=res@entry=0x555555f0a7a0, 
    row_number=row_number@entry=0, column_number=column_number@entry=0)
    at src/libfq.c:2564
#1  0x00007ffff7fa63ec in _FQinitClientEncoding (
    conn=conn@entry=0x555555ef7450) at src/libfq.c:656
#2  0x00007ffff7fa6718 in FQconnectdbParams (
    keywords=keywords@entry=0x7fffffffdf00, values=values@entry=0x7fffffffdf30)
    at src/libfq.c:315
#3  0x000055555555791c in main (argc=7, argv=0x7fffffffe078) at main.c:103

Does the segfault occur with a different Firebird database (i.e. not /tmp/test.fdb)?

Yes, see previous script for a new empty databases.

Can you reproduce this in another environment?

Yes, segmentation fault is reproducible for different machines and distributives with and without gdb but with the same combination of the newest libfq + fbsql source code (directly from git, not releases).

SELECT CAST(rdb$get_context('SYSTEM', 'ENGINE_VERSION') AS VARCHAR(10)) FROM rdb$database

Executable, 3.0.7 as result.

    SELECT TRIM(rdb$character_set_name) AS client_encoding,
           mon$character_set_id AS client_encoding_id
      FROM mon$attachments
INNER JOIN rdb$character_sets
        ON mon$character_set_id = rdb$character_set_id
     WHERE mon$remote_pid = %i

Executable without WHERE mon$remote_pid = %i, no NULLs.

Best I can tell is there is some situation where the query appears successful but the result tuples array doesn't get populated, it would be useful to be able to reproduce what is happening.

Yes, I think it can be problem with %i and then

query appears successful but the result tuples array doesn't get populated

The data is visible without WHERE mon$remote_pid = %i, 2656 is /usr/lib/postgresql/13/bin/postgres, firebird_fwd. Other processes don't have a record with not NULL MON$REMOTE_PID.

TRIM MON$CHARACTER_SET_ID MON$REMOTE_PID
NONE 0
NONE 0
UTF8 4 2656
UTF8 4
UTF8 4
UTF8 4
ibarwick commented 1 year ago

Thanks for the details, that enabled me to reproduce the issue.

Basically two things happening: 1) the query checking for client encoding assumed the client PID will always be present in MON$ATTACHMENTS, but that's not the case if the client is connecting "directly" to the database file, so no rows were returned 2) there was no check for the situation where no rows were returned, and FQgetisnull() was missing a check for out-of-bounds access, hence the segfault.

It turns out it's possible to use CURRENT_CONNECTION to query the client's MON$ATTACHMENTS entry, which should work in all cases, so query updated to use that. Also robustified various functions in case the client provides invalid row/column numbers for the query result.

mkgrgis commented 1 year ago

Thanks, @ibarwick, fixed without fbsql recompilation. Works fine! I'll continue to debug https://github.com/ibarwick/fbsql/issues/1.