调用用 C 编写的 Postgres 函数时出现分段错误,使 Postgres 服务器崩溃

Segmentation fault when calling Postgres function written in C, crashes Postgres server

我有一个用 C 代码编写的 postgresql 函数。

当我尝试 运行 时,我在我的 postgresql-9.5-main.log 文件中得到了这个:

2021-02-28 17:28:00 CST [1393-180] LOG:  server process (PID 31043) was terminated by signal 11: Segmentation fault

psql 时,这是我收到的消息:

server closed the connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.

这也会使任何其他使用 Postgres 的程序崩溃。不过,Postgres 会立即重新启动。

我也在13.1服务器上试过运行这个,也出现了同样的错误。

psql 构建函数的代码是

CREATE OR REPLACE FUNCTION
 int_to_id(BIGINT)
 RETURNS TEXT AS 'int_to_id',
 'int_to_id'
LANGUAGE 'c' 
STRICT;

现在,我已经验证代码生成了正确的 ID,但最后一步失败了。当我用常量字符串替换 result 时也是如此,例如 "HELLO"。我在想是不是我的代码有什么问题,或者还有什么错误

C代码如下:

#include "postgres.h"
#include "fmgr.h"

#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif

const char charmap[36] = {
    '0',
    '1',
    '2',
    '3',
    '4',
    '5',
    '6',
    '7',
    '8',
    '9',
    'a',
    'b',
    'c',
    'd',
    'e',
    'f',
    'g',
    'h',
    'i',
    'j',
    'k',
    'l',
    'm',
    'n',
    'o',
    'p',
    'q',
    'r',
    's',
    't',
    'u',
    'v',
    'w',
    'x',
    'y',
    'z'
};

Datum int_to_id(PG_FUNCTION_ARGS);

PG_FUNCTION_INFO_V1(int_to_id);

Datum int_to_id(PG_FUNCTION_ARGS){
    char result[11] = {' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
    int64 x =  PG_GETARG_INT64(0);
    long base_val = 1L;
    for (int i = 1; i <= 10; i++){
        
        if (x > base_val - 1L || i == 1){
           result[10 - i] = charmap[ ((int)(x / base_val)) % 36];
        } 
        base_val = base_val * 36L;
    }

    text * textval = cstring_to_text(result);
    PG_RETURN_TEXT_P(textval);
}

我的脚本生成文件:

MODULES = int_to_id

PG_CONFIG = pg_config
PGXS = $(shell $(PG_CONFIG) --pgxs)
INCLUDEDIR = $(shell $(PG_CONFIG) --includedir-server)
LIBDIR = $(shell pg_config --pkglibdir)
FCFLAGS = -fPIC
include $(PGXS)

clean: 
    rm *.o
    rm *.so

int_to_id.so: int_to_id.o
    cc  -shared -o int_to_id.so int_to_id.o

int_to_id.o: int_to_id.c
    cc ${FCFLAGS} -o int_to_id.o -c int_to_id.c $(CRFLAGS) -I $(INCLUDEDIR) 

install:
    $(shell cp int_to_id.so ${LIBDIR})

当我执行 Makefile 时,我得到:

Makefile:11: warning: overriding recipe for target 'clean'
/usr/pgsql-13/lib/pgxs/src/makefiles/pgxs.mk:342: warning: ignoring old recipe for target 'clean'
Makefile:21: warning: overriding recipe for target 'install'
/usr/pgsql-13/lib/pgxs/src/makefiles/pgxs.mk:241: warning: ignoring old recipe for target 'install'
cc -fPIC -o int_to_id.o -c int_to_id.c  -I /usr/pgsql-13/include/server 
int_to_id.c: In function ‘int_to_id’:
int_to_id.c:63:22: warning: implicit declaration of function ‘cstring_to_text’ [-Wimplicit-function-declaration]
   63 |     text * textval = cstring_to_text(result);
      |                      ^~~~~~~~~~~~~~~
int_to_id.c:63:22: warning: initialization of ‘text *’ {aka ‘struct varlena *’} from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
cc  -shared -o int_to_id.so int_to_id.o
/usr/lib64/ccache/clang -Wno-ignored-attributes -fno-strict-aliasing -fwrapv -O2  -I. -I./ -I/usr/pgsql-13/include/server -I/usr/pgsql-13/include/internal  -D_GNU_SOURCE -I/usr/include/libxml2  -I/usr/include -flto=thin -emit-llvm -c -o int_to_id.bc int_to_id.c
int_to_id.c:63:22: warning: implicit declaration of function 'cstring_to_text' is invalid in C99 [-Wimplicit-function-declaration]
    text * textval = cstring_to_text(result);
                     ^
int_to_id.c:63:12: warning: incompatible integer to pointer conversion initializing 'text *' (aka 'struct varlena *') with an expression of type 'int' [-Wint-conversion]
    text * textval = cstring_to_text(result);
           ^         ~~~~~~~~~~~~~~~~~~~~~~~
2 warnings generated.

这意味着您忘记包含定义 cstring_to_text:

的 header
#include "utils/builtins.h"

之后,该函数在我的 PostgreSQL v13 上没有崩溃,但我没有对其进行广泛的测试。

您不应覆盖 Makefile 中的 cleaninstall 目标。