Thread: User-defined-type in C crashing PostgreSQL server: What am I doing wrong?
User-defined-type in C crashing PostgreSQL server: What am I doing wrong?
From
"J. Greg Davidson"
Date:
Hello, My user-defined types are crashing the PostgreSQL server and I don't understand why. I've been trying to figure it out on my own for overr a week. I've cooked what I'm doing down to the essentials and I'm asking for help. Help: What am I doing wrong? * Sections of this message: ** Overview with psql session ** SQL code ** C Code ** gdb backtraces *** gdb backtrace after SELECT ARRAY[ pair_tag_id(3, 4) ]; *** gdb backtrace after SELECT x from pair_tag_id(3, 4) x; *** gdb backtrace after SELECT ROW( pair_tag_id(3, 4) ); ** Thanks for your help! ** Overview wiith psql session Tested with: PostgreSQL-8.1.4 and PostgreSQL-8.2beta3, installed from source with ./configure ... --enable-debug --enable-cassert Platform: SuSE Linux 10.0 on i686 Dell Notebook Computer I have a simple one-word datatype called a "pair", which consists of a 1-byte "tag" and a 3-byte "id". -- At first, it seems to work: pairs=# select pair_tag_id(3, 4); pair_tag_id ------------------------- <pair tag="3" id="4" /> (1 row) pairs=# select tag_pair(pair_tag_id(3, 4)); tag_pair ---------- 3 (1 row) pairs=# select id_pair(pair_tag_id(3, 4)); id_pair --------- 4 (1 row) -- But all three of these crash the server with Signal 11: SELECT ARRAY[ pair_tag_id(3, 4) ]; SELECT x from pair_tag_id(3, 4) x; SELECT ROW( pair_tag_id(3, 4) ); -- Note: Nothing special about 3 and 4, all values I've tried behave -- the same! ** SQL code -- CREATE TYPE pair; -- PostgreSQL 8.2 CREATE OR REPLACE FUNCTION pair_in(cstring) RETURNS pair AS 'pair.so' LANGUAGE 'c' STRICT; CREATE OR REPLACE FUNCTION pair_out(pair) RETURNS cstring AS 'pair.so' LANGUAGE 'c' STRICT; CREATE TYPE pair ( INTERNALLENGTH = 4, -- 32-bits INPUT = pair_in, OUTPUT = pair_out ); CREATE OR REPLACE FUNCTION tag_pair(pair) RETURNS integer AS 'pair.so' LANGUAGE 'c' STRICT; CREATE OR REPLACE FUNCTION id_pair(pair) RETURNS integer AS 'pair.so' LANGUAGE 'c' STRICT; CREATE OR REPLACE FUNCTION pair_tag_id(integer, integer) RETURNS pair AS 'pair.so' LANGUAGE 'c' STRICT; ** C Code $ cc -fpic -I/Ubuntu/usr/local/pgsql-8.1.4/include/server -Wall -c -o pair.o pair.c $ cc -shared -o pair.so pair.o $ cat pair.c #include <stdlib.h> #include <stdarg.h> #include <string.h> #include <postgres.h> /* general Postgres declarations */ #include <fmgr.h> /* for argument/result macros */ #define PAIR_TAG_WIDTH 8 #define PAIR_MAX_TAG ( (1U << PAIR_TAG_WIDTH) - 1) #define PAIR_MAX_ID ( (int) (INT_MAX >> PAIR_TAG_WIDTH) ) #define PAIR_MIN_ID ( -PAIR_MAX_ID ) typedef long pairs; // a tag plus an ID typedef unsigned tags; #define F_TAG "tag: %u " // Format string for tags typedef long ids; #define F_ID "id: %ld " // Format string for ids typedef char *StrPtr; // '\0' terminated modifiable string typedef const char *Str; // '\0' terminated constant string #ifdef PG_MODULE_MAGIC PG_MODULE_MAGIC; #endif inline pairs TagPairId (tags tag, ids id) { return (id << PAIR_TAG_WIDTH) | tag; } inline tags TagPair(pairs v) { return v & ~(~0U << PAIR_TAG_WIDTH); } inline ids IdPair(pairs v) { return v >> PAIR_TAG_WIDTH; } #define FUNCTION_DEFINE(f) \ PG_FUNCTION_INFO_V1(f); \ Datum (f)(PG_FUNCTION_ARGS) FUNCTION_DEFINE(pair_tag_id) { // (tags, ids) -> pair tags tag = PG_GETARG_INT32(0); ids id = PG_GETARG_INT32(1); PG_RETURN_INT32( TagPairId( tag, id) ); } FUNCTION_DEFINE(tag_pair) { // (pair) -> tags PG_RETURN_INT32( TagPair( PG_GETARG_INT32(0) ) ); } FUNCTION_DEFINE(id_pair) { // (pair) -> ids PG_RETURN_INT32( IdPair( PG_GETARG_INT32(0) ) ); } inline StrPtr NewStr( Str old ) { return strcpy( palloc(strlen(old)+1), old ); } StrPtr PairToXMLStr(Str message, pairs p) { tags tag = TagPair(p); ids id = IdPair(p); Str msg = message ? message : ""; Str format = message ? "<pair tag=\"%u\" id=\"%d\">%s</pair>" : "<pair tag=\"%u\" id=\"%d\" %s/>"; // I tried with both of the next two lines, just in case: same behavior // char buffer[strlen(format) + strlen(msg) + 2 * 20]; // gcc extension char * buffer = palloc(strlen(format) + strlen(msg) + 2 * 20); sprintf(buffer, format, tag, id, msg); return NewStr(buffer); } FUNCTION_DEFINE(pair_in) { // cstring -> pair PG_RETURN_INT32(0); } FUNCTION_DEFINE(pair_out) { // pair -> cstring PG_RETURN_CSTRING( PairToXMLStr( NULL, PG_GETARG_INT32(0) ) ); } ** gdb backtraces # gdb bin/postgres data/core GNU gdb 6.3 ... Core was generated by `postgres: greg pairs [local] SELECT '. Program terminated with signal 11, Segmentation fault. ... *** gdb backtrace after SELECT ARRAY[ pair_tag_id(3, 4) ]; (gdb) backtrace #0 0xb7d2a07d in memmove () from /lib/tls/libc.so.6 #1 0x00000403 in ?? () #2 0x081ed694 in ArrayCastAndSet (src=138452140, typlen=1027, typbyval=<value optimized out>, typalign=105 'i', dest=0x8409cac "\177\177\177\177~", '\177' <repeats 195 times>...) at arrayfuncs.c:3673 #3 0x081ed92a in CopyArrayEls (array=<value optimized out>, values=0x8409ba4, nulls=0x8409bb8 "", nitems=1, typlen=4, typbyval=0 '\0', typalign=105 'i', freedata=0 '\0') at arrayfuncs.c:872 #4 0x081edbde in construct_md_array (elems=0x8409ba4, nulls=0x8409bb8 "", ndims=1, dims=0xbfaaddc0, lbs=0xbfaadda8, elmtype=164377, elmlen=4, elmbyval=0 '\0', elmalign=105 'i') at arrayfuncs.c:2863 #5 0x0815ae43 in ExecEvalArray (astate=0x8407e58, econtext=0x8407dc0, isNull=0x84085cc "", isDone=0x84085e0) at execQual.c:2266 #6 0x08159b54 in ExecProject (projInfo=0x8408520, isDone=0xbfaade7c) at execQual.c:3986 #7 0x08167e83 in ExecResult (node=0x8407d34) at nodeResult.c:157 #8 0x08156673 in ExecProcNode (node=0x8407d34) at execProcnode.c:334 #9 0x08154dc0 in ExecutorRun (queryDesc=0x84077c0, direction=ForwardScanDirection, count=0) at execMain.c:1081 #10 0x081e3129 in PortalRunSelect (portal=0x83fecdc, forward=<value optimized out>, count=0, dest=0x83f299c) at pquery.c:831 #11 0x081e441a in PortalRun (portal=0x83fecdc, count=2147483647, ---Type <return> to continue, or q <return> to quit--- *** gdb backtrace after SELECT x from pair_tag_id(3, 4) x; (gdb) backtrace #0 0xb7d2a58c in memcpy () from /lib/tls/libc.so.6 #1 0x0807b58f in heap_fill_tuple (tupleDesc=0x842053c, values=0xbfaaddb8, isnull=0xbfaadb8c "", data=0x842053c "", infomask=0x8420538, bit=0x0) at heaptuple.c:180 #2 0x0807c0e6 in heap_form_tuple (tupleDescriptor=0x841aeec, values=0xbfaaddb8, isnull=0xbfaadb8c "") at heaptuple.c:745 #3 0x0815aac9 in ExecMakeTableFunctionResult (funcexpr=0x841a930, econtext=0x841a718, expectedDesc=0x841a7fc, returnDesc=0x842053c) at execQual.c:1457 #4 0x08167c0c in FunctionNext (node=0x841a68c) at nodeFunctionscan.c:69 #5 0x0815c7d8 in ExecScan (node=0x841a68c, accessMtd=0x8167bb0 <FunctionNext>) at execScan.c:68 #6 0x08167824 in ExecFunctionScan (node=0x841a68c) at nodeFunctionscan.c:110 #7 0x081566ec in ExecProcNode (node=0x841a68c) at execProcnode.c:371 #8 0x08154dc0 in ExecutorRun (queryDesc=0x8403450, direction=ForwardScanDirection, count=0) at execMain.c:1081 #9 0x081e3129 in PortalRunSelect (portal=0x83fa96c, forward=<value optimized out>, count=0, dest=0x83d96c4) at pquery.c:831 #10 0x081e441a in PortalRun (portal=0x83fa96c, count=2147483647, dest=0x83d96c4, altdest=0x83d96c4, completionTag=0xbfaae0ba "") at pquery.c:684 #11 0x081dffaa in exec_simple_query ( query_string=0x83d774c "SELECT x from pair_tag_id(3, 4) x;") ---Type <return> to continue, or q <return> to quit--- *** gdb backtrace after SELECT ROW( pair_tag_id(3, 4) ); (gdb) backtrace #0 0xb7d2a58c in memcpy () from /lib/tls/libc.so.6 #1 0x0807b58f in heap_fill_tuple (tupleDesc=0x8411d84, values=0x8411d2c, isnull=0x8411d40 "", data=0x8411d84 "", infomask=0x8411d80, bit=0x0) at heaptuple.c:180 #2 0x0807c0e6 in heap_form_tuple (tupleDescriptor=0x8403954, values=0x8411d2c, isnull=0x8411d40 "") at heaptuple.c:745 #3 0x08158a53 in ExecEvalRow (rstate=0x8403928, econtext=0x8403890, isNull=0x84041a8 "", isDone=0x84041bc) at execQual.c:2479 #4 0x08159b54 in ExecProject (projInfo=0x84040fc, isDone=0xbfaade7c) at execQual.c:3986 #5 0x08167e83 in ExecResult (node=0x8403804) at nodeResult.c:157 #6 0x08156673 in ExecProcNode (node=0x8403804) at execProcnode.c:334 #7 0x08154dc0 in ExecutorRun (queryDesc=0x8403290, direction=ForwardScanDirection, count=0) at execMain.c:1081 #8 0x081e3129 in PortalRunSelect (portal=0x840726c, forward=<value optimized out>, count=0, dest=0x8416454) at pquery.c:831 #9 0x081e441a in PortalRun (portal=0x840726c, count=2147483647, dest=0x8416454, altdest=0x8416454, completionTag=0xbfaae0ba "") at pquery.c:684 #10 0x081dffaa in exec_simple_query ( query_string=0x83d774c "SELECT ROW( pair_tag_id(3, 4) );") at postgres.c:939 #11 0x081e0f6e in PostgresMain (argc=4, argv=<value optimized out>, ---Type <return> to continue, or q <return> to quit--- ** Thanks for your help! _Greg
Re: User-defined-type in C crashing PostgreSQL server: What am I doing wrong?
From
Martijn van Oosterhout
Date:
On Sat, Nov 18, 2006 at 01:07:15PM -0800, J. Greg Davidson wrote: > Hello, > > My user-defined types are crashing the PostgreSQL server and I don't > understand why. I've been trying to figure it out on my own for overr > a week. I've cooked what I'm doing down to the essentials and I'm > asking for help. Help: What am I doing wrong? This may be a long shot but: > CREATE TYPE pair ( > INTERNALLENGTH = 4, -- 32-bits > INPUT = pair_in, > OUTPUT = pair_out > ); You're not specifying PASSEDBYVALUE, so I think postgres is assuming you're returning a *pointer* to 4 bytes, so it's dying trying to copy it. Hope this helps, -- Martijn van Oosterhout <kleptog@svana.org> http://svana.org/kleptog/ > From each according to his ability. To each according to his ability to litigate.
Attachment
Martijn was exactly right! All of the examples I'd been following were using pass-by-reference, the function call interface is oblivious and I missed this very important part of the type definition. Yea! Big thanks, _Greg n Sat, 2006-11-18 at 23:15 +0100, Martijn van Oosterhout wrote: > On Sat, Nov 18, 2006 at 01:07:15PM -0800, J. Greg Davidson wrote: > > Hello, > > > > My user-defined types are crashing the PostgreSQL server and I don't > > understand why. I've been trying to figure it out on my own for overr > > a week. I've cooked what I'm doing down to the essentials and I'm > > asking for help. Help: What am I doing wrong? > > This may be a long shot but: > > > CREATE TYPE pair ( > > INTERNALLENGTH = 4, -- 32-bits > > INPUT = pair_in, > > OUTPUT = pair_out > > ); > > You're not specifying PASSEDBYVALUE, so I think postgres is assuming > you're returning a *pointer* to 4 bytes, so it's dying trying to copy > it. > > Hope this helps,