Search Postgresql Archives

Recovering from an exception

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

I'm trying to recover from an exception in an fmgr hook. It seems to work relatively well most of the time, but in some cases the backend segfaults. Attached is a self-contained test case demonstrating the problem. The problem I'm hitting can be reproduced with:

create function f4() returns int as $$ select 2 $$ language sql;
create function f3() returns int as $$ declare f int; begin select f4() into f; return 1; end $$ language plpgsql;

select f3();

the backend dies at:

Program received signal SIGSEGV, Segmentation fault.
0x08406d49 in fmgr_security_definer (fcinfo=0x89b133c) at fmgr.c:975
975                     result = FunctionCallInvoke(fcinfo);

10 lines of backtrace:

#0  0x08406d49 in fmgr_security_definer (fcinfo=0x89b133c) at fmgr.c:975
#1  0x082094b5 in ExecMakeFunctionResult (fcache=0x89b1300,
    econtext=0x89b11ec, isNull=0x89b185c '\177' <repeats 200 times>...,
    isDone=0x89b1908) at execQual.c:1917
#2  0x08209e32 in ExecEvalFunc (fcache=0x89b1300, econtext=0x89b11ec,
    isNull=0x89b185c '\177' <repeats 200 times>..., isDone=0x89b1908)
    at execQual.c:2356
#3  0x0820f6d9 in ExecTargetList (targetlist=0x89b18ec, econtext=0x89b11ec,
    values=0x89b1848, isnull=0x89b185c '\177' <repeats 200 times>...,
    itemIsDone=0x89b1908, isDone=0xbffc2118) at execQual.c:5210
#4  0x0820fc03 in ExecProject (projInfo=0x89b1870, isDone=0xbffc2118)
    at execQual.c:5425
#5  0x08224972 in ExecResult (node=0x89b1160) at nodeResult.c:155
#6  0x08206337 in ExecProcNode (node=0x89b1160) at execProcnode.c:367
#7  0x082041dc in ExecutePlan (estate=0x89b10d4, planstate=0x89b1160,
    operation=CMD_SELECT, sendTuples=1 '\001', numberTuples=1,
    direction=ForwardScanDirection, dest=0x862170c) at execMain.c:1440
#8  0x08202887 in standard_ExecutorRun (queryDesc=0x89adcac,
    direction=ForwardScanDirection, count=1) at execMain.c:314
#9  0x082026fb in ExecutorRun (queryDesc=0x89adcac,
    direction=ForwardScanDirection, count=1) at execMain.c:262
#10 0x08232131 in _SPI_pquery (queryDesc=0x89adcac, fire_triggers=1 '\001',
    tcount=1) at spi.c:2110

It looks like fcinfo (amongst other things) is allocated in a child of the SPI context. My speculation is that the SPI context gets reset by AtEOSubXact_SPI(), thus resetting the memory fcinfo points to, leading to SIGSEGV.

Any thoughts on how to avoid this crash? Or generally, how to correctly clean up after an exception? The attached code tries to imitate what the PLs are doing, but it's not working. :-(


Regards,
Marko Tiikkaja
#include <stdio.h>
#include <stdarg.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>

#include "postgres.h"
#include "plpgsql.h"
#include "miscadmin.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "commands/explain.h"
#include "executor/executor.h"
#include "executor/instrument.h"
#include "executor/spi.h"
#include "nodes/params.h"
#include "parser/parser.h"
#include "parser/parse_target.h"
#include "parser/parse_node.h"
#include "utils/builtins.h"
#include "utils/guc.h"
#include "utils/memutils.h"
#include "utils/syscache.h"
#include "utils/lsyscache.h"


PG_MODULE_MAGIC;

static MemoryContext MyMemoryContext = NULL;
static needs_fmgr_hook_type prev_needs_fmgr_hook = NULL;
static fmgr_hook_type prev_fmgr_hook = NULL;

void _PG_fini(void);
void _PG_init(void);

static void
do_stuff()
{
	MemoryContext oldcxt;
	ResourceOwner oldowner = CurrentResourceOwner;


	oldcxt = MemoryContextSwitchTo(MyMemoryContext);
	BeginInternalSubTransaction(NULL);
	PG_TRY();
	{
		elog(ERROR, "BIG LETTERS");
	}
	PG_CATCH();
	{
		ErrorData *edata;

		MemoryContextSwitchTo(MyMemoryContext);
		edata = CopyErrorData();
		FlushErrorState();

		RollbackAndReleaseCurrentSubTransaction();
		MemoryContextSwitchTo(oldcxt);
		CurrentResourceOwner = oldowner;
		
		//SPI_restore_connection();

		FreeErrorData(edata);
	}
	PG_END_TRY();
}

static bool
cleanup_test_needs_fmgr_hook(Oid functionId)
{
	return true;
}

static void
cleanup_test_fmgr_hook(FmgrHookEventType event, FmgrInfo *flinfo,
						   Datum *args)
{
	if (prev_fmgr_hook)
		(*prev_fmgr_hook) (event, flinfo, args);

	switch (event)
	{
		case FHET_START:
			do_stuff();
			break;
		case FHET_ABORT:
		case FHET_END:
			break;
		default:
			elog(ERROR, "unknown FmgtHookEventType %d", event);

	}
}

void
_PG_init(void)
{
	MyMemoryContext = AllocSetContextCreate(TopTransactionContext,
											"mymemcxt",
											ALLOCSET_DEFAULT_MINSIZE,
											ALLOCSET_DEFAULT_INITSIZE,
											ALLOCSET_DEFAULT_MAXSIZE);

	prev_needs_fmgr_hook = needs_fmgr_hook;
	needs_fmgr_hook = cleanup_test_needs_fmgr_hook;
	prev_fmgr_hook = fmgr_hook;
	fmgr_hook = cleanup_test_fmgr_hook;
}

void
_PG_fini(void)
{
	needs_fmgr_hook = prev_needs_fmgr_hook;
	prev_needs_fmgr_hook = NULL;
	fmgr_hook = prev_fmgr_hook;
	prev_fmgr_hook = NULL;

	MemoryContextDelete(MyMemoryContext);
	MyMemoryContext = NULL;
}

# cleanup_test/Makefile

MODULE_big = cleanup_test

OBJS = cleanup_test.o

PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)
-- 
Sent via pgsql-general mailing list (pgsql-general@xxxxxxxxxxxxxx)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-general

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Postgresql Jobs]     [Postgresql Admin]     [Postgresql Performance]     [Linux Clusters]     [PHP Home]     [PHP on Windows]     [Kernel Newbies]     [PHP Classes]     [PHP Books]     [PHP Databases]     [Postgresql & PHP]     [Yosemite]
  Powered by Linux