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 */