/*------------------------------------------------------------------------- * * test_explain_state.c * Crash reproducer for the sizeof bug in RegisterExtensionExplainOption. * * RegisterExtensionExplainOption allocates its ExplainExtensionOptionArray * using sizeof(char *) (8 bytes) instead of sizeof(ExplainExtensionOption) * (16 bytes). The initial allocation is for 16 "slots" at 8 bytes each = * 128 bytes, but each ExplainExtensionOption is 16 bytes, so only 8 entries * actually fit. Registering a 9th option writes past the end of the * allocation, corrupting the heap. * * This module registers 10 options, which is enough to trigger the bug. */ #include "postgres.h" #include "commands/defrem.h" #include "commands/explain_state.h" #include "fmgr.h" PG_MODULE_MAGIC; static const char *const option_names[] = { "test_explain_opt0", "test_explain_opt1", "test_explain_opt2", "test_explain_opt3", "test_explain_opt4", "test_explain_opt5", "test_explain_opt6", "test_explain_opt7", "test_explain_opt8", "test_explain_opt9", }; #define NUM_OPTIONS lengthof(option_names) static void test_explain_option_handler(ExplainState *es, DefElem *opt, ParseState *pstate); void _PG_init(void) { for (int i = 0; i < NUM_OPTIONS; i++) RegisterExtensionExplainOption(option_names[i], test_explain_option_handler); } static void test_explain_option_handler(ExplainState *es, DefElem *opt, ParseState *pstate) { ereport(NOTICE, (errmsg("test_explain_state: processed option \"%s\"", opt->defname))); }