Sunday, August 31, 2008

[HACKERS] [PATCH] In case module has wrong magic, report exact problem

*** a/src/backend/utils/fmgr/dfmgr.c
--- b/src/backend/utils/fmgr/dfmgr.c
***************
*** 19,28 ****
--- 19,29 ----
#ifndef WIN32_ONLY_COMPILER
#include "dynloader.h"
#else
#include "port/dynloader/win32.h"
#endif
+ #include "lib/stringinfo.h"
#include "miscadmin.h"
#include "utils/dynamic_loader.h"
#include "utils/hsearch.h"


*************** PGFunction
*** 163,172 ****
--- 164,213 ----
lookup_external_function(void *filehandle, char *funcname)
{
return (PGFunction) pg_dlsym(filehandle, funcname);
}

+ /*
+ * Detailed error report when module incompatibility is detected.
+ */
+
+ #define MAGIC_FIELD_TEST(field) do { \
+ if (srv->field != mod->field) { \
+ if (det->len) \
+ appendStringInfo(det, ", "); \
+ appendStringInfo(det, "%s: %d != %d", #field, mod->field, srv->field); \
+ } \
+ } while (0)
+
+ static void
+ module_incompat_error(const Pg_magic_struct *mod, const Pg_magic_struct *srv, const char *libname)
+ {
+ StringInfo det;
+
+ if (mod->version != srv->version)
+ ereport(ERROR,
+ (errmsg("incompatible library \"%s\": version mismatch",
+ libname),
+ errdetail("Server is version %d.%d, library is version %d.%d.",
+ srv->version / 100,
+ srv->version % 100,
+ mod->version / 100,
+ mod->version % 100)));
+
+ det = makeStringInfo();
+
+ MAGIC_FIELD_TEST(funcmaxargs);
+ MAGIC_FIELD_TEST(indexmaxkeys);
+ MAGIC_FIELD_TEST(namedatalen);
+ MAGIC_FIELD_TEST(float4byval);
+ MAGIC_FIELD_TEST(float8byval);
+
+ ereport(ERROR,
+ (errmsg("incompatible library \"%s\": magic block mismatch: %s",
+ libname, det->data)));
+ }
+ #undef MAGIC_FIELD_TEST

/*
* Load the specified dynamic-link library file, unless it already is
* loaded. Return the pg_dl* handle for the file.
*
*************** internal_load_library(const char *libnam
*** 255,281 ****

/* try to unlink library */
pg_dlclose(file_scanner->handle);
free((char *) file_scanner);

! /*
! * Report suitable error. It's probably not worth writing a
! * separate error message for each field; only the most common
! * case of wrong major version gets its own message.
! */
! if (module_magic_data.version != magic_data.version)
! ereport(ERROR,
! (errmsg("incompatible library \"%s\": version mismatch",
! libname),
! errdetail("Server is version %d.%d, library is version %d.%d.",
! magic_data.version / 100,
! magic_data.version % 100,
! module_magic_data.version / 100,
! module_magic_data.version % 100)));
! ereport(ERROR,
! (errmsg("incompatible library \"%s\": magic block mismatch",
! libname)));
}
}
else
{
/* try to unlink library */
--- 296,306 ----

/* try to unlink library */
pg_dlclose(file_scanner->handle);
free((char *) file_scanner);

! module_incompat_error(&module_magic_data, &magic_data, libname);
}
}
else
{
/* try to unlink library */
In case module and server magic blocks do not match
report exact parameters that differ.

It is quite cumbersome problem to track down unless
user already knows the cause.

As we want to encourage module use, such situations
can happen more often.

No comments: