Index: doc/src/sgml/xfunc.sgml =================================================================== RCS file: /projects/cvsroot/pgsql/doc/src/sgml/xfunc.sgml,v retrieving revision 1.112 diff -c -r1.112 xfunc.sgml *** doc/src/sgml/xfunc.sgml 23 Apr 2006 03:39:52 -0000 1.112 --- doc/src/sgml/xfunc.sgml 7 May 2006 21:14:49 -0000 *************** *** 1149,1154 **** --- 1149,1161 ---- + After the module has been found, PostgreSQL looks for its magic block. + This block contains information about the environment a module was + compiled in. The server uses this to verify the module was compiled + under the same assumptions and environment as the backend. + + + The user ID the PostgreSQL server runs as must be able to traverse the path to the file you intend to load. Making the file or a higher-level directory not readable *************** *** 1953,1958 **** --- 1960,1985 ---- + To ensure your module is not loaded into an incompatible backend, it + is recommended to include a magic block. To do this you must include + the header pgmagic.h and declare the block as + follows: + + + + #include "pgmagic.h" + + PG_MODULE_MAGIC; + + + + If the module consists of multiple source files, this only needs to + be done in one of them. + + + + + Symbol names defined within object files must not conflict with each other or with symbols defined in the PostgreSQL server executable. You Index: src/backend/utils/fmgr/dfmgr.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v retrieving revision 1.82 diff -c -r1.82 dfmgr.c *** src/backend/utils/fmgr/dfmgr.c 5 Mar 2006 15:58:46 -0000 1.82 --- src/backend/utils/fmgr/dfmgr.c 7 May 2006 21:14:49 -0000 *************** *** 20,26 **** #include "dynloader.h" #include "miscadmin.h" #include "utils/dynamic_loader.h" ! /* * List of dynamically loaded files (kept in malloc'd memory). --- 20,26 ---- #include "dynloader.h" #include "miscadmin.h" #include "utils/dynamic_loader.h" ! #include "pgmagic.h" /* * List of dynamically loaded files (kept in malloc'd memory). *************** *** 60,65 **** --- 60,68 ---- static char *expand_dynamic_library_name(const char *name); static char *substitute_libpath_macro(const char *name); + /* Magic structure that module needs to match to be accepted */ + static Pg_magic_struct magic_data = PG_MODULE_MAGIC_DATA; + /* * Load the specified dynamic-link library file, and look for a function * named funcname in it. (funcname can be NULL to just load the file.) *************** *** 116,121 **** --- 119,125 ---- if (file_scanner == NULL) { + PGModuleMagicFunction magic_func; /* * File not loaded yet. */ *************** *** 146,151 **** --- 150,186 ---- fullname, load_error))); } + /* Check the magic function to determine compatability */ + magic_func = pg_dlsym( file_scanner->handle, PG_MAGIC_FUNCTION_NAME_STRING ); + if( magic_func ) + { + int i; + Pg_magic_struct *module_magic_data = magic_func(); + if( module_magic_data->len != magic_data.len ) + ereport(ERROR, + (errmsg("incompatible library \"%s\": Magic block length mismatch", + fullname))); + for( i=0; ivalues[i] != magic_data.values[i] ) + ereport(ERROR, + (errmsg("incompatible library \"%s\": Magic block mismatch at %d", + fullname, i), + errdetail("Expected %d (0x%08X), got %d (0x%08X)", + magic_data.values[i], magic_data.values[i], + module_magic_data->values[i], module_magic_data->values[i]))); + if( strcmp( module_magic_data->compiler, magic_data.compiler ) != 0 ) + ereport(ERROR, + (errmsg("incompatible library \"%s\": Compiler mismatch", + fullname), + errdetail("Expected %s, got %s", + magic_data.compiler, magic_data.compiler))); + } + else + /* Currently we do not penalize modules for not having a + magic block, it would break every external module in + existance. At some point though... */ + ereport(LOG, (errmsg("external library \"%s\" did not have magic block", fullname ))); + /* OK to link it into list */ if (file_list == NULL) file_list = file_scanner; Index: src/test/regress/regress.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/test/regress/regress.c,v retrieving revision 1.65 diff -c -r1.65 regress.c *** src/test/regress/regress.c 11 Jan 2006 20:12:43 -0000 1.65 --- src/test/regress/regress.c 7 May 2006 21:14:50 -0000 *************** *** 9,14 **** --- 9,15 ---- #include "utils/geo_decls.h" /* includes */ #include "executor/executor.h" /* For GetAttributeByName */ #include "commands/sequence.h" /* for nextval() */ + #include "pgmagic.h" #define P_MAXDIG 12 #define LDELIM '(' *************** *** 27,33 **** extern Datum int44in(PG_FUNCTION_ARGS); extern Datum int44out(PG_FUNCTION_ARGS); ! /* * Distance from a point to a path */ --- 28,34 ---- extern Datum int44in(PG_FUNCTION_ARGS); extern Datum int44out(PG_FUNCTION_ARGS); ! PG_MODULE_MAGIC; /* * Distance from a point to a path */ Index: src/include/pgmagic.h ========================================================================= *** src/include/pgmagic.h.orig Sun May 7 23:15:36 2006 --- src/include/pgmagic.h Sun May 7 22:59:57 2006 *************** *** 0 **** --- 1,113 ---- + /*------------------------------------------------------------------------- + * + * pgmagic.h + * Defines a magic block that can mark a module in a way so show that + * it is compatible with the server it is being loaded into. + * + * This file is intended to be included into modules that wish to load + * themselves into the backend. All they need to do is include this header + * into one of the source files and include the line: + * + * PG_MODULE_MAGIC; + * + * The trailing semi-colon is optional. To work with versions of PostgreSQL + * that do not support this, you may put an #ifdef/endif block around it. + * + * Originally written by Martijn van Oosterhout + * + * $PostgreSQL: $ + * + *------------------------------------------------------------------------- + */ + + #ifndef PGMAGIC_H + #define PGMAGIC_H + + #include "catalog/catversion.h" + #include "c.h" + + /* The main structure in which the magic is stored. the length field is used + * to detect major changes */ + + #define PG_MAGIC_CONSTANTS 5 + typedef struct { + int len; + int values[PG_MAGIC_CONSTANTS]; + char compiler[8]; + } Pg_magic_struct; + + /* Declare the module magic function. It needs to be a function as the dlsym + * in the backend is only guarenteed to work on functions, not data */ + + typedef Pg_magic_struct *(*PGModuleMagicFunction) (void); + + #define PG_MAGIC_FUNCTION_NAME Pg_magic_func + #define PG_MAGIC_FUNCTION_NAME_STRING "Pg_magic_func" + + #define PG_MODULE_MAGIC \ + extern DLLIMPORT Pg_magic_struct *PG_MAGIC_FUNCTION_NAME(void); \ + Pg_magic_struct * \ + PG_MAGIC_FUNCTION_NAME(void) \ + { \ + static Pg_magic_struct Pg_magic_data = PG_MODULE_MAGIC_DATA; \ + return &Pg_magic_data; \ + } + + + /* Information about system datatypes */ + #define PG_MODULE_MAGIC_CONST3 \ + (sizeof(char) << 0) + \ + (sizeof(short) << 4) + \ + (sizeof(int) << 8) + \ + (sizeof(long) << 12) + \ + (sizeof(void*) << 16) + \ + (sizeof(float) << 20) + \ + (sizeof(double) << 24) + \ + (sizeof(size_t) << 28) + + /* First set of adjustable constants */ + #ifdef HAVE_INT64_TIMESTAMP + #define PG_MODULE_MAGIC_CONST4 BLCKSZ + NAMEDATALEN + 1 + #else + #define PG_MODULE_MAGIC_CONST4 BLCKSZ + NAMEDATALEN + #endif + + /* More adjustable constants */ + #define PG_MODULE_MAGIC_CONST5 \ + (INDEX_MAX_KEYS << 0) + \ + (FUNC_MAX_ARGS << 8) + \ + (VARHDRSZ << 16) + \ + (MAXDIM << 24) + + /* The compiler used to compile. List seeded from list at: + * http://predef.sourceforge.net/precomp.html */ + #if defined(__GNUC__) + #define PG_MODULE_MAGIC_COMPILER "GNUC" + #elif defined(_MSC_VER) + #define PG_MODULE_MAGIC_COMPILER "MSC" + #elif defined(__HP_cc) + #define PG_MODULE_MAGIC_COMPILER "HPCC" + #elif defined(__ICC) + #define PG_MODULE_MAGIC_COMPILER "ICC" + #elif defined(__MINGW32__) + #define PG_MODULE_MAGIC_COMPILER "MINGW" + #elif + #define PG_MODULE_MAGIC_COMPILER "????" + #endif + + /* Finally, the actual data block */ + #define PG_MODULE_MAGIC_DATA \ + { \ + sizeof(Pg_magic_struct), \ + { \ + PG_VERSION_NUM, /* Version of postgres */ \ + CATALOG_VERSION_NO, /* Catalog version */ \ + /* Some constants users can configure */ \ + PG_MODULE_MAGIC_CONST3, \ + PG_MODULE_MAGIC_CONST4, \ + PG_MODULE_MAGIC_CONST5 \ + }, \ + PG_MODULE_MAGIC_COMPILER \ + } + + #endif /* PGMAGIC_H */