[Date Prev][Date Next] [Chronological] [Thread] [Top]

Re: (ITS#7775) LMDB terminates Postfix daemon process without logfile record

wietse@porcupine.org writes:
> Below is my "least painful" patch for both parties. What do you think?

That's roughly what I wrote was thinking, yes.

We haven't heard if it will go in at all, though:-) If this ITS
is a reaction to ITS#7774, then the motivation is not catching
an lmdb bug, but letting the user band-aid a user error.  Still
makes sense to me, lmdb lets the user screw up in many ways.


Why drop the info parameter?  If you don't need it after all,
that's fine.  But then it won't be coming back later.  It
doesn't fit in the varargs, they're reserved for the message.

I ended up declaring a type for it in ldmb.h, to make future
expansion a bit friendlier:
  /** Dummy definition for future extension of #mdb_assert_cb(). */
  typedef struct MDB_assertion MDB_assertion;

I dislike when a feature makes me #include <stdarg.h>, so I'd
not make one myself.  I'd build the message in a buffer.  Also
the code needs fleshing out a bit: Obey NDEBUG, and omit all
this if something already #defined assert.  See below.

Finally, __func__ needs a wrapper.  It can go in a renamed
"compat" section:

--- a/libraries/liblmdb/mdb.c
+++ b/libraries/liblmdb/mdb.c
@@ -151,3 +150,3 @@
-/** @defgroup compat	Windows Compatibility Macros
+/** @defgroup compat	Compatibility Macros
  *	A bunch of macros to minimize the amount of platform-specific ifdefs
@@ -158,2 +157,13 @@
+	/** Wrapper around __func__, which is a C99 feature */
+#if __STDC_VERSION__ >= 199901L
+# define mdb_func_	__func__
+#elif __GNUC__ >= 2 || _MSC_VER >= 1300
+# define mdb_func_	__FUNCTION__
+/* If a debug message says <mdb_unknown>(), update the #if statements above */
+# define mdb_func_	"<mdb_unknown>"
 #ifdef _WIN32
@@ -329,3 +339,3 @@ static txnid_t mdb_debug_start;
 # define DPRINTF0(fmt, ...) \
-	fprintf(stderr, "%s:%d " fmt "\n", __func__, __LINE__, __VA_ARGS__)
+	fprintf(stderr, "%s:%d " fmt "\n", mdb_func_, __LINE__, __VA_ARGS__)

Google found more compiler #ifdefs, but I'm not sure which of
these are still relevant as non-C99 compilers.  Could add them
later at need:
__func__: (defined(__SUNPRO_C) && defined(__C99FEATURES__))
__FUNC__:  __BORLANDC__ >= 0x550
__FUNCTION__: __MWERKS__ >= 0x3000 || defined(__ghs__) || __DMC__ >= 0x810 || __IBMCPP__ >= 500

And the assert() itself:

/** assert(3) replacement.
 *	Omitted in programs that #include mdb.c and already define assert().
#ifndef assert
# ifdef NDEBUG
#  define assert(expr) ((void) 0)
# else
#  define assert(expr) ((expr) ? (void)0 : \
		mdb_assert_fail(#expr, mdb_func_, __FILE__, __LINE__))
static void
mdb_assert_fail(const char *expr, const char *func, const char *file, int line)
	char buf[400];
	sprintf(buf, "%.100s:%d: Assertion '%.200s' failed in %.40s()",
		file, line, expr, func);
	if (mdb_assert_cb)
		mdb_assert_cb(buf, NULL);
	fprintf(stderr, "%s\n", buf);
# endif /* NDEBUG */
#endif /* assert */