@@ -87,7 +87,7 @@ err_gettext(const char *str)
87
87
/* This extension allows gcc to check the format string for consistency with
88
88
the supplied arguments. */
89
89
__attribute__((format_arg (1 )));
90
- static void set_errdata_field (char * * ptr , const char * str );
90
+ static void set_errdata_field (MemoryContextData * cxt , char * * ptr , const char * str );
91
91
92
92
/* Global variables */
93
93
ErrorContextCallback * error_context_stack = NULL ;
@@ -373,6 +373,11 @@ errstart(int elevel, const char *filename, int lineno,
373
373
/* errno is saved here so that error parameter eval can't change it */
374
374
edata -> saved_errno = errno ;
375
375
376
+ /*
377
+ * Any allocations for this error state level should go into ErrorContext
378
+ */
379
+ edata -> assoc_context = ErrorContext ;
380
+
376
381
recursion_depth -- ;
377
382
return true;
378
383
}
@@ -786,7 +791,7 @@ errmsg(const char *fmt,...)
786
791
787
792
recursion_depth ++ ;
788
793
CHECK_STACK_DEPTH ();
789
- oldcontext = MemoryContextSwitchTo (ErrorContext );
794
+ oldcontext = MemoryContextSwitchTo (edata -> assoc_context );
790
795
791
796
EVALUATE_MESSAGE (edata -> domain , message , false, true);
792
797
@@ -815,7 +820,7 @@ errmsg_internal(const char *fmt,...)
815
820
816
821
recursion_depth ++ ;
817
822
CHECK_STACK_DEPTH ();
818
- oldcontext = MemoryContextSwitchTo (ErrorContext );
823
+ oldcontext = MemoryContextSwitchTo (edata -> assoc_context );
819
824
820
825
EVALUATE_MESSAGE (edata -> domain , message , false, false);
821
826
@@ -838,7 +843,7 @@ errmsg_plural(const char *fmt_singular, const char *fmt_plural,
838
843
839
844
recursion_depth ++ ;
840
845
CHECK_STACK_DEPTH ();
841
- oldcontext = MemoryContextSwitchTo (ErrorContext );
846
+ oldcontext = MemoryContextSwitchTo (edata -> assoc_context );
842
847
843
848
EVALUATE_MESSAGE_PLURAL (edata -> domain , message , false);
844
849
@@ -859,7 +864,7 @@ errdetail(const char *fmt,...)
859
864
860
865
recursion_depth ++ ;
861
866
CHECK_STACK_DEPTH ();
862
- oldcontext = MemoryContextSwitchTo (ErrorContext );
867
+ oldcontext = MemoryContextSwitchTo (edata -> assoc_context );
863
868
864
869
EVALUATE_MESSAGE (edata -> domain , detail , false, true);
865
870
@@ -886,7 +891,7 @@ errdetail_internal(const char *fmt,...)
886
891
887
892
recursion_depth ++ ;
888
893
CHECK_STACK_DEPTH ();
889
- oldcontext = MemoryContextSwitchTo (ErrorContext );
894
+ oldcontext = MemoryContextSwitchTo (edata -> assoc_context );
890
895
891
896
EVALUATE_MESSAGE (edata -> domain , detail , false, false);
892
897
@@ -907,7 +912,7 @@ errdetail_log(const char *fmt,...)
907
912
908
913
recursion_depth ++ ;
909
914
CHECK_STACK_DEPTH ();
910
- oldcontext = MemoryContextSwitchTo (ErrorContext );
915
+ oldcontext = MemoryContextSwitchTo (edata -> assoc_context );
911
916
912
917
EVALUATE_MESSAGE (edata -> domain , detail_log , false, true);
913
918
@@ -930,7 +935,7 @@ errdetail_plural(const char *fmt_singular, const char *fmt_plural,
930
935
931
936
recursion_depth ++ ;
932
937
CHECK_STACK_DEPTH ();
933
- oldcontext = MemoryContextSwitchTo (ErrorContext );
938
+ oldcontext = MemoryContextSwitchTo (edata -> assoc_context );
934
939
935
940
EVALUATE_MESSAGE_PLURAL (edata -> domain , detail , false);
936
941
@@ -951,7 +956,7 @@ errhint(const char *fmt,...)
951
956
952
957
recursion_depth ++ ;
953
958
CHECK_STACK_DEPTH ();
954
- oldcontext = MemoryContextSwitchTo (ErrorContext );
959
+ oldcontext = MemoryContextSwitchTo (edata -> assoc_context );
955
960
956
961
EVALUATE_MESSAGE (edata -> domain , hint , false, true);
957
962
@@ -976,7 +981,7 @@ errcontext_msg(const char *fmt,...)
976
981
977
982
recursion_depth ++ ;
978
983
CHECK_STACK_DEPTH ();
979
- oldcontext = MemoryContextSwitchTo (ErrorContext );
984
+ oldcontext = MemoryContextSwitchTo (edata -> assoc_context );
980
985
981
986
EVALUATE_MESSAGE (edata -> context_domain , context , true, true);
982
987
@@ -1102,7 +1107,7 @@ internalerrquery(const char *query)
1102
1107
}
1103
1108
1104
1109
if (query )
1105
- edata -> internalquery = MemoryContextStrdup (ErrorContext , query );
1110
+ edata -> internalquery = MemoryContextStrdup (edata -> assoc_context , query );
1106
1111
1107
1112
return 0 ; /* return value does not matter */
1108
1113
}
@@ -1128,19 +1133,19 @@ err_generic_string(int field, const char *str)
1128
1133
switch (field )
1129
1134
{
1130
1135
case PG_DIAG_SCHEMA_NAME :
1131
- set_errdata_field (& edata -> schema_name , str );
1136
+ set_errdata_field (edata -> assoc_context , & edata -> schema_name , str );
1132
1137
break ;
1133
1138
case PG_DIAG_TABLE_NAME :
1134
- set_errdata_field (& edata -> table_name , str );
1139
+ set_errdata_field (edata -> assoc_context , & edata -> table_name , str );
1135
1140
break ;
1136
1141
case PG_DIAG_COLUMN_NAME :
1137
- set_errdata_field (& edata -> column_name , str );
1142
+ set_errdata_field (edata -> assoc_context , & edata -> column_name , str );
1138
1143
break ;
1139
1144
case PG_DIAG_DATATYPE_NAME :
1140
- set_errdata_field (& edata -> datatype_name , str );
1145
+ set_errdata_field (edata -> assoc_context , & edata -> datatype_name , str );
1141
1146
break ;
1142
1147
case PG_DIAG_CONSTRAINT_NAME :
1143
- set_errdata_field (& edata -> constraint_name , str );
1148
+ set_errdata_field (edata -> assoc_context , & edata -> constraint_name , str );
1144
1149
break ;
1145
1150
default :
1146
1151
elog (ERROR , "unsupported ErrorData field id: %d" , field );
@@ -1154,10 +1159,10 @@ err_generic_string(int field, const char *str)
1154
1159
* set_errdata_field --- set an ErrorData string field
1155
1160
*/
1156
1161
static void
1157
- set_errdata_field (char * * ptr , const char * str )
1162
+ set_errdata_field (MemoryContextData * cxt , char * * ptr , const char * str )
1158
1163
{
1159
1164
Assert (* ptr == NULL );
1160
- * ptr = MemoryContextStrdup (ErrorContext , str );
1165
+ * ptr = MemoryContextStrdup (cxt , str );
1161
1166
}
1162
1167
1163
1168
/*
@@ -1257,6 +1262,9 @@ elog_start(const char *filename, int lineno, const char *funcname)
1257
1262
edata -> funcname = funcname ;
1258
1263
/* errno is saved now so that error parameter eval can't change it */
1259
1264
edata -> saved_errno = errno ;
1265
+
1266
+ /* Use ErrorContext for any allocations done at this level. */
1267
+ edata -> assoc_context = ErrorContext ;
1260
1268
}
1261
1269
1262
1270
/*
@@ -1282,7 +1290,7 @@ elog_finish(int elevel, const char *fmt,...)
1282
1290
* Format error message just like errmsg_internal().
1283
1291
*/
1284
1292
recursion_depth ++ ;
1285
- oldcontext = MemoryContextSwitchTo (ErrorContext );
1293
+ oldcontext = MemoryContextSwitchTo (edata -> assoc_context );
1286
1294
1287
1295
EVALUATE_MESSAGE (edata -> domain , message , false, false);
1288
1296
@@ -1366,7 +1374,7 @@ EmitErrorReport(void)
1366
1374
1367
1375
recursion_depth ++ ;
1368
1376
CHECK_STACK_DEPTH ();
1369
- oldcontext = MemoryContextSwitchTo (ErrorContext );
1377
+ oldcontext = MemoryContextSwitchTo (edata -> assoc_context );
1370
1378
1371
1379
/*
1372
1380
* Call hook before sending message to log. The hook function is allowed
@@ -1446,6 +1454,9 @@ CopyErrorData(void)
1446
1454
if (newedata -> internalquery )
1447
1455
newedata -> internalquery = pstrdup (newedata -> internalquery );
1448
1456
1457
+ /* Use the calling context for string allocation */
1458
+ newedata -> assoc_context = CurrentMemoryContext ;
1459
+
1449
1460
return newedata ;
1450
1461
}
1451
1462
@@ -1563,6 +1574,9 @@ ReThrowError(ErrorData *edata)
1563
1574
if (newedata -> internalquery )
1564
1575
newedata -> internalquery = pstrdup (newedata -> internalquery );
1565
1576
1577
+ /* Reset the assoc_context to be ErrorContext */
1578
+ newedata -> assoc_context = ErrorContext ;
1579
+
1566
1580
recursion_depth -- ;
1567
1581
PG_RE_THROW ();
1568
1582
}
@@ -1630,12 +1644,8 @@ pg_re_throw(void)
1630
1644
* GetErrorContextStack - Return the context stack, for display/diags
1631
1645
*
1632
1646
* Returns a pstrdup'd string in the caller's context which includes the PG
1633
- * call stack. It is the caller's responsibility to ensure this string is
1634
- * pfree'd (or its context cleaned up) when done.
1635
- *
1636
- * Note that this function may *not* be called from any existing error case
1637
- * and is not for error-reporting (use ereport() and friends instead, which
1638
- * will also produce a stack trace).
1647
+ * error call stack. It is the caller's responsibility to ensure this string
1648
+ * is pfree'd (or its context cleaned up) when done.
1639
1649
*
1640
1650
* This information is collected by traversing the error contexts and calling
1641
1651
* each context's callback function, each of which is expected to call
@@ -1644,78 +1654,64 @@ pg_re_throw(void)
1644
1654
char *
1645
1655
GetErrorContextStack (void )
1646
1656
{
1647
- char * result = NULL ;
1648
1657
ErrorData * edata ;
1649
1658
ErrorContextCallback * econtext ;
1650
- MemoryContext oldcontext = CurrentMemoryContext ;
1651
-
1652
- /* this function should not be called from an exception handler */
1653
- Assert (recursion_depth == 0 );
1654
1659
1655
1660
/*
1656
- * This function should never be called from an exception handler and
1657
- * therefore will only ever be the top item on the errordata stack
1658
- * (which is set up so that the calls to the callback functions are
1659
- * able to use it).
1660
- *
1661
- * Better safe than sorry, so double-check that we are not being called
1662
- * from an exception handler.
1661
+ * Okay, crank up a stack entry to store the info in.
1663
1662
*/
1664
- if (errordata_stack_depth != -1 )
1663
+ recursion_depth ++ ;
1664
+
1665
+ if (++ errordata_stack_depth >= ERRORDATA_STACK_SIZE )
1665
1666
{
1667
+ /*
1668
+ * Wups, stack not big enough. We treat this as a PANIC condition
1669
+ * because it suggests an infinite loop of errors during error
1670
+ * recovery.
1671
+ */
1666
1672
errordata_stack_depth = -1 ; /* make room on stack */
1667
- ereport (PANIC ,
1668
- (errmsg_internal ("GetErrorContextStack called from exception handler" )));
1673
+ ereport (PANIC , (errmsg_internal ("ERRORDATA_STACK_SIZE exceeded" )));
1669
1674
}
1670
1675
1671
1676
/*
1672
- * Initialize data for the top, and only at this point, error frame as the
1673
- * callback functions we're about to call will turn around and call
1674
- * errcontext(), which expects to find a valid errordata stack.
1677
+ * Things look good so far, so initialize our error frame
1675
1678
*/
1676
- errordata_stack_depth = 0 ;
1677
1679
edata = & errordata [errordata_stack_depth ];
1678
1680
MemSet (edata , 0 , sizeof (ErrorData ));
1679
1681
1680
1682
/*
1681
- * Use ErrorContext as a short lived context for calling the callbacks;
1682
- * the callbacks will use it through errcontext() even if we don't call
1683
- * them with it, so we have to clean it up below either way.
1683
+ * Set up assoc_context to be the caller's context, so any allocations
1684
+ * done (which will include edata->context) will use their context.
1684
1685
*/
1685
- MemoryContextSwitchTo ( ErrorContext ) ;
1686
+ edata -> assoc_context = CurrentMemoryContext ;
1686
1687
1687
1688
/*
1688
1689
* Call any context callback functions to collect the context information
1689
1690
* into edata->context.
1690
1691
*
1691
1692
* Errors occurring in callback functions should go through the regular
1692
- * error handling code which should handle any recursive errors and must
1693
- * never call back to us .
1693
+ * error handling code which should handle any recursive errors, though
1694
+ * we double-check above, just in case .
1694
1695
*/
1695
1696
for (econtext = error_context_stack ;
1696
1697
econtext != NULL ;
1697
1698
econtext = econtext -> previous )
1698
1699
(* econtext -> callback ) (econtext -> arg );
1699
1700
1700
- MemoryContextSwitchTo (oldcontext );
1701
-
1702
1701
/*
1703
- * Copy out the string into the caller's context, so we can free our
1704
- * error context and reset the error stack. Caller is expected to
1705
- * pfree() the result or throw away the context.
1702
+ * Clean ourselves off the stack, any allocations done should have been
1703
+ * using edata->assoc_context, which we set up earlier to be the caller's
1704
+ * context, so we're free to just remove our entry off the stack and
1705
+ * decrement recursion depth and exit.
1706
1706
*/
1707
- if ( edata -> context )
1708
- result = pstrdup ( edata -> context ) ;
1707
+ errordata_stack_depth -- ;
1708
+ recursion_depth -- ;
1709
1709
1710
1710
/*
1711
- * Reset error stack- note that we should be the only item on the error
1712
- * stack at this point and therefore it's safe to clean up the whole stack.
1713
- * This function is not intended nor able to be called from exception
1714
- * handlers.
1711
+ * Return a pointer to the string the caller asked for, which should have
1712
+ * been allocated in their context.
1715
1713
*/
1716
- FlushErrorState ();
1717
-
1718
- return result ;
1714
+ return edata -> context ;
1719
1715
}
1720
1716
1721
1717
0 commit comments