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
-
(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
#include
#include
#include/* general Postgres declarations */
#include/* 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
? "%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 0x0403 in ?? ()
#2 0x081ed694 in ArrayCastAndSet (src=138452140, typlen=1027,
typbyval=, typalign=105 'i',
dest=0x8409cac "\177\177\177\177~", '\177' ...)
at arrayfuncs.c:3673
#3 0x081ed92a in CopyArrayEls (array=,
values=0x8409ba4,
nulls=0x84