aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/error/elog.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2008-10-27 19:37:42 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2008-10-27 19:37:42 +0000
commit1b0c30f68de7af7511b5a2c7297ff55c29a84db6 (patch)
tree6ec7b3b88b8d42a29fc80c80e919e7bc6310494c /src/backend/utils/error/elog.c
parentf4d4bc827ffad194733344be07bab5a8c8b34deb (diff)
downloadpostgresql-1b0c30f68de7af7511b5a2c7297ff55c29a84db6.tar.gz
postgresql-1b0c30f68de7af7511b5a2c7297ff55c29a84db6.zip
Install a more robust solution for the problem of infinite error-processing
recursion when we are unable to convert a localized error message to the client's encoding. We've been over this ground before, but as reported by Ibrar Ahmed, it still didn't work in the case of conversion failures for the conversion-failure message itself :-(. Fix by installing a "circuit breaker" that disables attempts to localize this message once we get into recursion trouble. Patch all supported branches, because it is in fact broken in all of them; though I had to add some missing translations to the older branches in order to expose the failure in the particular test case I was using.
Diffstat (limited to 'src/backend/utils/error/elog.c')
-rw-r--r--src/backend/utils/error/elog.c75
1 files changed, 55 insertions, 20 deletions
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index 42df11cc1cf..342ee0e314b 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -42,7 +42,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.167.2.6 2008/07/08 22:18:02 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.167.2.7 2008/10/27 19:37:42 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -124,6 +124,21 @@ static const char *error_severity(int elevel);
static void append_with_tabs(StringInfo buf, const char *str);
static void write_pipe_chunks(int fd, char *data, int len);
+
+/*
+ * in_error_recursion_trouble --- are we at risk of infinite error recursion?
+ *
+ * This function exists to provide common control of various fallback steps
+ * that we take if we think we are facing infinite error recursion. See the
+ * callers for details.
+ */
+bool
+in_error_recursion_trouble(void)
+{
+ /* Pull the plug if recurse more than once */
+ return (recursion_depth > 2);
+}
+
/*
* errstart --- begin an error-reporting cycle
*
@@ -259,12 +274,12 @@ errstart(int elevel, const char *filename, int lineno,
MemoryContextReset(ErrorContext);
/*
- * If we recurse more than once, the problem might be something broken
+ * Infinite error recursion might be due to something broken
* in a context traceback routine. Abandon them too. We also
* abandon attempting to print the error statement (which, if long,
* could itself be the source of the recursive failure).
*/
- if (recursion_depth > 2)
+ if (in_error_recursion_trouble())
{
error_context_stack = NULL;
debug_query_string = NULL;
@@ -593,18 +608,20 @@ errcode_for_socket_access(void)
* it's common code for errmsg(), errdetail(), etc. Must be called inside
* a routine that is declared like "const char *fmt, ..." and has an edata
* pointer set up. The message is assigned to edata->targetfield, or
- * appended to it if appendval is true.
+ * appended to it if appendval is true. The message is subject to translation
+ * if translateit is true.
*
* Note: we pstrdup the buffer rather than just transferring its storage
* to the edata field because the buffer might be considerably larger than
* really necessary.
*/
-#define EVALUATE_MESSAGE(targetfield, appendval) \
+#define EVALUATE_MESSAGE(targetfield, appendval, translateit) \
{ \
char *fmtbuf; \
StringInfoData buf; \
/* Internationalize the error format string */ \
- fmt = _(fmt); \
+ if (translateit) \
+ fmt = _(fmt); \
/* Expand %m in format string */ \
fmtbuf = expand_fmt_string(fmt, edata); \
initStringInfo(&buf); \
@@ -651,7 +668,7 @@ errmsg(const char *fmt,...)
CHECK_STACK_DEPTH();
oldcontext = MemoryContextSwitchTo(ErrorContext);
- EVALUATE_MESSAGE(message, false);
+ EVALUATE_MESSAGE(message, false, true);
MemoryContextSwitchTo(oldcontext);
recursion_depth--;
@@ -663,9 +680,12 @@ errmsg(const char *fmt,...)
* errmsg_internal --- add a primary error message text to the current error
*
* This is exactly like errmsg() except that strings passed to errmsg_internal
- * are customarily left out of the internationalization message dictionary.
- * This should be used for "can't happen" cases that are probably not worth
- * spending translation effort on.
+ * are not translated, and are customarily left out of the
+ * internationalization message dictionary. This should be used for "can't
+ * happen" cases that are probably not worth spending translation effort on.
+ * We also use this for certain cases where we *must* not try to translate
+ * the message because the translation would fail and result in infinite
+ * error recursion.
*/
int
errmsg_internal(const char *fmt,...)
@@ -677,7 +697,7 @@ errmsg_internal(const char *fmt,...)
CHECK_STACK_DEPTH();
oldcontext = MemoryContextSwitchTo(ErrorContext);
- EVALUATE_MESSAGE(message, false);
+ EVALUATE_MESSAGE(message, false, false);
MemoryContextSwitchTo(oldcontext);
recursion_depth--;
@@ -698,7 +718,7 @@ errdetail(const char *fmt,...)
CHECK_STACK_DEPTH();
oldcontext = MemoryContextSwitchTo(ErrorContext);
- EVALUATE_MESSAGE(detail, false);
+ EVALUATE_MESSAGE(detail, false, true);
MemoryContextSwitchTo(oldcontext);
recursion_depth--;
@@ -719,7 +739,7 @@ errhint(const char *fmt,...)
CHECK_STACK_DEPTH();
oldcontext = MemoryContextSwitchTo(ErrorContext);
- EVALUATE_MESSAGE(hint, false);
+ EVALUATE_MESSAGE(hint, false, true);
MemoryContextSwitchTo(oldcontext);
recursion_depth--;
@@ -744,7 +764,7 @@ errcontext(const char *fmt,...)
CHECK_STACK_DEPTH();
oldcontext = MemoryContextSwitchTo(ErrorContext);
- EVALUATE_MESSAGE(context, true);
+ EVALUATE_MESSAGE(context, true, true);
MemoryContextSwitchTo(oldcontext);
recursion_depth--;
@@ -922,12 +942,12 @@ elog_finish(int elevel, const char *fmt,...)
return; /* nothing to do */
/*
- * Format error message just like errmsg().
+ * Format error message just like errmsg_internal().
*/
recursion_depth++;
oldcontext = MemoryContextSwitchTo(ErrorContext);
- EVALUATE_MESSAGE(message, false);
+ EVALUATE_MESSAGE(message, false, false);
MemoryContextSwitchTo(oldcontext);
recursion_depth--;
@@ -1076,7 +1096,9 @@ ReThrowError(ErrorData *edata)
/*
* Wups, stack not big enough. We treat this as a PANIC condition
* because it suggests an infinite loop of errors during error
- * recovery.
+ * recovery. Note that the message is intentionally not localized,
+ * else failure to convert it to client encoding could cause further
+ * recursion.
*/
errordata_stack_depth = -1; /* make room on stack */
ereport(PANIC, (errmsg_internal("ERRORDATA_STACK_SIZE exceeded")));
@@ -2010,6 +2032,10 @@ useful_strerror(int errnum)
/*
* error_severity --- get localized string representing elevel
+ *
+ * Note: in an error recursion situation, we stop localizing the tags
+ * for ERROR and above. This is necessary because the problem might be
+ * failure to convert one of these strings to the client encoding.
*/
static const char *
error_severity(int elevel)
@@ -2039,13 +2065,22 @@ error_severity(int elevel)
prefix = _("WARNING");
break;
case ERROR:
- prefix = _("ERROR");
+ if (in_error_recursion_trouble())
+ prefix = "ERROR";
+ else
+ prefix = _("ERROR");
break;
case FATAL:
- prefix = _("FATAL");
+ if (in_error_recursion_trouble())
+ prefix = "FATAL";
+ else
+ prefix = _("FATAL");
break;
case PANIC:
- prefix = _("PANIC");
+ if (in_error_recursion_trouble())
+ prefix = "PANIC";
+ else
+ prefix = _("PANIC");
break;
default:
prefix = "???";