调用用 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
中的 clean
和 install
目标。
我有一个用 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
:
#include "utils/builtins.h"
之后,该函数在我的 PostgreSQL v13 上没有崩溃,但我没有对其进行广泛的测试。
您不应覆盖 Makefile
中的 clean
和 install
目标。