Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 01b2168

Browse files
committed
Add pgmagic header block to store compile-time constants:
It now only checks four things: Major version number (7.4 or 8.1 for example) NAMEDATALEN FUNC_MAX_ARGS INDEX_MAX_KEYS The three constants were chosen because: 1. We document them in the config page in the docs 2. We mark them as changable in pg_config_manual.h 3. Changing any of these will break some of the more popular modules: FUNC_MAX_ARGS changes fmgr interface, every module uses this NAMEDATALEN changes syscache interface, every PL as well as tsearch uses this INDEX_MAX_KEYS breaks tsearch and anything using GiST. Martijn van Oosterhout
1 parent 87bd07d commit 01b2168

File tree

4 files changed

+149
-5
lines changed

4 files changed

+149
-5
lines changed

doc/src/sgml/xfunc.sgml

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/xfunc.sgml,v 1.112 2006/04/23 03:39:52 momjian Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/xfunc.sgml,v 1.113 2006/05/30 14:09:32 momjian Exp $ -->
22

33
<sect1 id="xfunc">
44
<title>User-Defined Functions</title>
@@ -1148,6 +1148,13 @@ CREATE FUNCTION square_root(double precision) RETURNS double precision
11481148
that fails as well, the load will fail.
11491149
</para>
11501150

1151+
<para>
1152+
After the module has been found, PostgreSQL looks for its magic block.
1153+
This block contains information about the environment a module was
1154+
compiled in. The server uses this to verify the module was compiled
1155+
under the same assumptions and environment as the backend.
1156+
</para>
1157+
11511158
<para>
11521159
The user ID the <productname>PostgreSQL</productname> server runs
11531160
as must be able to traverse the path to the file you intend to
@@ -1951,6 +1958,26 @@ concat_text(PG_FUNCTION_ARGS)
19511958
</para>
19521959
</listitem>
19531960

1961+
<listitem>
1962+
<para>
1963+
To ensure your module is not loaded into an incompatible backend, it
1964+
is recommended to include a magic block. To do this you must include
1965+
the header <filename>pgmagic.h</filename> and declare the block as
1966+
follows:
1967+
</para>
1968+
1969+
<programlisting>
1970+
#include "pgmagic.h"
1971+
1972+
PG_MODULE_MAGIC;
1973+
</programlisting>
1974+
1975+
<para>
1976+
If the module consists of multiple source files, this only needs to
1977+
be done in one of them.
1978+
</para>
1979+
</listitem>
1980+
19541981
<listitem>
19551982
<para>
19561983
Symbol names defined within object files must not conflict

src/backend/utils/fmgr/dfmgr.c

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.82 2006/03/05 15:58:46 momjian Exp $
11+
* $PostgreSQL: pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.83 2006/05/30 14:09:32 momjian Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -20,7 +20,7 @@
2020
#include "dynloader.h"
2121
#include "miscadmin.h"
2222
#include "utils/dynamic_loader.h"
23-
23+
#include "pgmagic.h"
2424

2525
/*
2626
* List of dynamically loaded files (kept in malloc'd memory).
@@ -60,6 +60,9 @@ static char *find_in_dynamic_libpath(const char *basename);
6060
static char *expand_dynamic_library_name(const char *name);
6161
static char *substitute_libpath_macro(const char *name);
6262

63+
/* Magic structure that module needs to match to be accepted */
64+
static Pg_magic_struct magic_data = PG_MODULE_MAGIC_DATA;
65+
6366
/*
6467
* Load the specified dynamic-link library file, and look for a function
6568
* named funcname in it. (funcname can be NULL to just load the file.)
@@ -116,6 +119,7 @@ load_external_function(char *filename, char *funcname,
116119

117120
if (file_scanner == NULL)
118121
{
122+
PGModuleMagicFunction magic_func;
119123
/*
120124
* File not loaded yet.
121125
*/
@@ -146,6 +150,45 @@ load_external_function(char *filename, char *funcname,
146150
fullname, load_error)));
147151
}
148152

153+
/* Check the magic function to determine compatability */
154+
magic_func = pg_dlsym( file_scanner->handle, PG_MAGIC_FUNCTION_NAME_STRING );
155+
if( magic_func )
156+
{
157+
Pg_magic_struct *module_magic_data = magic_func();
158+
if( module_magic_data->len != magic_data.len ||
159+
memcmp( module_magic_data, &magic_data, magic_data.len ) != 0 )
160+
{
161+
pg_dlclose( file_scanner->handle );
162+
163+
if( module_magic_data->len != magic_data.len )
164+
ereport(ERROR,
165+
(errmsg("incompatible library \"%s\": Magic block length mismatch",
166+
fullname)));
167+
if( module_magic_data->version != magic_data.version )
168+
ereport(ERROR,
169+
(errmsg("incompatible library \"%s\": Version mismatch",
170+
fullname),
171+
errdetail("Expected %d.%d, got %d.%d",
172+
magic_data.version/100, magic_data.version % 100,
173+
module_magic_data->version/100, module_magic_data->version % 100)));
174+
175+
if( module_magic_data->magic != magic_data.magic )
176+
ereport(ERROR,
177+
(errmsg("incompatible library \"%s\": Magic constant mismatch",
178+
fullname),
179+
errdetail("Expected 0x%08X, got 0x%08X",
180+
magic_data.magic, magic_data.magic)));
181+
/* Should never get here */
182+
ereport(ERROR,(errmsg("incompatible library \"%s\": Reason unknown",
183+
fullname)));
184+
}
185+
}
186+
else
187+
/* Currently we do not penalize modules for not having a
188+
magic block, it would break every external module in
189+
existance. At some point though... */
190+
ereport(LOG, (errmsg("external library \"%s\" did not have magic block", fullname )));
191+
149192
/* OK to link it into list */
150193
if (file_list == NULL)
151194
file_list = file_scanner;

src/include/pgmagic.h

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*-------------------------------------------------------------------------
2+
*
3+
* pgmagic.h
4+
* Defines a magic block that can mark a module in a way so show that
5+
* it is compatible with the server it is being loaded into.
6+
*
7+
* This file is intended to be included into modules that wish to load
8+
* themselves into the backend. All they need to do is include this header
9+
* into one of the source files and include the line:
10+
*
11+
* PG_MODULE_MAGIC;
12+
*
13+
* The trailing semi-colon is optional. To work with versions of PostgreSQL
14+
* that do not support this, you may put an #ifdef/endif block around it.
15+
*
16+
* Note, there is space available, particularly in the bitfield part. If it
17+
* turns out that a change has happened within a major release that would
18+
* require all modules to be recompiled, just setting one unused bit there
19+
* will do the trick.
20+
*
21+
* Originally written by Martijn van Oosterhout <kleptog@svana.org>
22+
*
23+
* $PostgreSQL: pgsql/src/include/pgmagic.h,v 1.1 2006/05/30 14:09:32 momjian Exp $
24+
*
25+
*-------------------------------------------------------------------------
26+
*/
27+
28+
#ifndef PGMAGIC_H
29+
#define PGMAGIC_H
30+
31+
#include "c.h"
32+
33+
/* The main structure in which the magic is stored. the length field is used
34+
* to detect major changes */
35+
36+
typedef struct {
37+
int len;
38+
int version;
39+
int magic;
40+
} Pg_magic_struct;
41+
42+
/* Declare the module magic function. It needs to be a function as the dlsym
43+
* in the backend is only guarenteed to work on functions, not data */
44+
45+
typedef Pg_magic_struct *(*PGModuleMagicFunction) (void);
46+
47+
#define PG_MAGIC_FUNCTION_NAME Pg_magic_func
48+
#define PG_MAGIC_FUNCTION_NAME_STRING "Pg_magic_func"
49+
50+
#define PG_MODULE_MAGIC \
51+
extern DLLIMPORT Pg_magic_struct *PG_MAGIC_FUNCTION_NAME(void); \
52+
Pg_magic_struct * \
53+
PG_MAGIC_FUNCTION_NAME(void) \
54+
{ \
55+
static Pg_magic_struct Pg_magic_data = PG_MODULE_MAGIC_DATA; \
56+
return &Pg_magic_data; \
57+
}
58+
59+
/* Common user adjustable constants */
60+
#define PG_MODULE_MAGIC_CONST \
61+
((INDEX_MAX_KEYS << 0) + \
62+
(FUNC_MAX_ARGS << 8) + \
63+
(NAMEDATALEN << 16))
64+
65+
/* Finally, the actual data block */
66+
#define PG_MODULE_MAGIC_DATA \
67+
{ \
68+
sizeof(Pg_magic_struct), \
69+
PG_VERSION_NUM / 100, /* Major version of postgres */ \
70+
PG_MODULE_MAGIC_CONST, /* Constants users can configure */ \
71+
}
72+
73+
#endif /* PGMAGIC_H */

src/test/regress/regress.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* $PostgreSQL: pgsql/src/test/regress/regress.c,v 1.65 2006/01/11 20:12:43 tgl Exp $
2+
* $PostgreSQL: pgsql/src/test/regress/regress.c,v 1.66 2006/05/30 14:09:32 momjian Exp $
33
*/
44

55
#include "postgres.h"
@@ -9,6 +9,7 @@
99
#include "utils/geo_decls.h" /* includes <math.h> */
1010
#include "executor/executor.h" /* For GetAttributeByName */
1111
#include "commands/sequence.h" /* for nextval() */
12+
#include "pgmagic.h"
1213

1314
#define P_MAXDIG 12
1415
#define LDELIM '('
@@ -27,7 +28,7 @@ extern int oldstyle_length(int n, text *t);
2728
extern Datum int44in(PG_FUNCTION_ARGS);
2829
extern Datum int44out(PG_FUNCTION_ARGS);
2930

30-
31+
PG_MODULE_MAGIC;
3132
/*
3233
* Distance from a point to a path
3334
*/

0 commit comments

Comments
 (0)