swoole / ext-postgresql

🐘 Coroutine-based client for PostgreSQL
64 stars 21 forks source link

[master] Random segmentation fault while fetching results #35

Closed codercms closed 3 years ago

codercms commented 3 years ago

The problem happens with master branch. I have wrote a simple code to demonstrate the problem.

function getRandomData(): Generator
{
    for ($i = 0; $i < 10000; $i++) {
        yield [
            md5((string)random_int(100000, 900000)),
            md5((string)random_int(100000, 900000))
        ];
    }
}

function seedDataSwoole(\Swoole\Coroutine\PostgreSQL $connection): void
{
    $connection->query("DROP TABLE IF EXISTS test");
    $connection->query("CREATE TABLE test (domain VARCHAR(63), tld VARCHAR(63), PRIMARY KEY (domain, tld))");

    $connection->prepare("insert", "INSERT INTO test VALUES (\$1, \$2)");

    foreach (getRandomData() as $row) {
        $connection->execute("insert", $row);
    }

    $connection->query("DEALLOCATE insert");
}

Swoole\Coroutine\run(function () {
    $connection = new \Swoole\Coroutine\PostgreSQL();
    $connection->connect("host=127.0.0.1 port=5434 user='makise' password='el-psy-congroo' dbname='makise'");

// uncomment this only for the first run
//    seedDataSwoole($connection);

    $start = microtime(true);

    for ($i = 0; $i < 100; $i++) {
        $result = $connection->query('SELECT * FROM test');

        while ($row = $connection->fetchAssoc($result)) {
        }
    }

    $end = microtime(true);

    $total = $end - $start;

    printf("Execution time for Swoole client: %f secs\n", $total);
    printf("Peak memory usage for Swoole client: %.2f kb\n", memory_get_peak_usage() / 1024);
});

Segmentation fault occurs really random. And it happens only when calling single row fetch functions. When I call fetchAll - segmentation fault doesn't happens.

php benchmark/select-swoole-raw.php
Execution time for Swoole client: 0.416035 secs
Peak memory usage for Swoole client: 2079.92 kb

php benchmark/select-swoole-raw.php
Execution time for Swoole client: 0.423457 secs
Peak memory usage for Swoole client: 2079.92 kb

php benchmark/select-swoole-raw.php
Segmentation fault

php benchmark/select-swoole-raw.php
Execution time for Swoole client: 0.405166 secs
Peak memory usage for Swoole client: 2079.92 kb

php benchmark/select-swoole-raw.php
Execution time for Swoole client: 0.419964 secs
Peak memory usage for Swoole client: 2079.92 kb

php benchmark/select-swoole-raw.php
Segmentation fault

php benchmark/select-swoole-raw.php
Segmentation fault

php benchmark/select-swoole-raw.php
Segmentation fault

php benchmark/select-swoole-raw.php
Execution time for Swoole client: 0.438378 secs
Peak memory usage for Swoole client: 2079.92 kb

Here is what does strace say:

....
poll([{fd=4, events=POLLIN|POLLERR}], 1, -1) = 1 ([{fd=4, revents=POLLIN}])
recvfrom(4, "\27\3\3 \21", 5, 0, NULL, NULL) = 5
recvfrom(4, "\t\217\211jhHM4\360s\232\316\377\3366\353\276\222\373\216Q.\265c\341eQe(Rd\255"..., 8209, 0, NULL, NULL) = 8209
poll([{fd=4, events=POLLIN|POLLERR}], 1, -1) = 1 ([{fd=4, revents=POLLIN}])
recvfrom(4, "\27\3\3 \21", 5, 0, NULL, NULL) = 5
recvfrom(4, "[\262\7Y\312\370;\225\256\0J\354\222Y\247qD\"`Z\261H\352\304X\353~\210\242q\30`"..., 8209, 0, NULL, NULL) = 8209
poll([{fd=4, events=POLLIN|POLLERR}], 1, -1) = 1 ([{fd=4, revents=POLLIN}])
recvfrom(4, "\27\3\3 \21", 5, 0, NULL, NULL) = 5
recvfrom(4, "\244T9B\321\36L\231\363\304\265w\5\355\214\206\16\365\277\274p^\223W\227\345\367\2565\316\355W"..., 8209, 0, NULL, NULL) = 8209
poll([{fd=4, events=POLLIN|POLLERR}], 1, -1) = 1 ([{fd=4, revents=POLLIN}])
recvfrom(4, "\27\3\3 \21", 5, 0, NULL, NULL) = 5
recvfrom(4, "\206L\365\345\362\25D\320\301/\247\35\244\255\317[\343Y\300\210\255hul\37\30\350\337\360\210\304&"..., 8209, 0, NULL, NULL) = 8209
poll([{fd=4, events=POLLIN|POLLERR}], 1, -1) = 1 ([{fd=4, revents=POLLIN}])
recvfrom(4, "\27\3\3 \21", 5, 0, NULL, NULL) = 5
recvfrom(4, "7\306+u\345\1\233\261\367\342]\0\262\261e\10\374P5\260\273\0\337\312\2'\vuy\n\204`"..., 8209, 0, NULL, NULL) = 8209
poll([{fd=4, events=POLLIN|POLLERR}], 1, -1) = 1 ([{fd=4, revents=POLLIN}])
recvfrom(4, "\27\3\3\16O", 5, 0, NULL, NULL) = 5
recvfrom(4, "\330\335\17$R\323\252\334\322\315\n\272\377$\273\16\2534U\277\276Zd:\303\363\326\376*yB\322"..., 3663, 0, NULL, NULL) = 3663
epoll_ctl(3, EPOLL_CTL_DEL, 4, NULL)    = 0
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x55c00a9207c8} ---
+++ killed by SIGSEGV +++

Here is what does gdb say:

gdb --args php benchmark/select-swoole-raw.php

(gdb) run
Starting program: /usr/bin/php benchmark/select-swoole-raw.php
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff2db5339 in PQgetisnull () from /lib/x86_64-linux-gnu/libpq.so.5

@matyhtf can you help with debug?

codercms commented 3 years ago

And also when segfault doesn't happens with fetchAssoc method it always returns false.

codercms commented 3 years ago

@matyhtf Finally I found the cause of Segmentation fault. It was a simple typo in the code of php_pgsql_fetch_hash function.

Could you review my PR when you have free time - https://github.com/swoole/ext-postgresql/pull/36/files ?