This tripped me up for about 2 hours this morning. If you are creating an aggregate with a dynamically allocated C object as the state type (type "internal" at the SQL level) you need to make sure that it is allocated in a context that has the same lifetime as the aggregate call, so that it will be valid across calls to the transition function. So if your state object is a StringInfo object, as mine was, instead of doing:
state = makeStringInfo();
you need to do something like:
oldcontext = MemoryContextSwitchTo(aggcontext);
state = makeStringInfo();
MemoryContextSwitchTo(oldcontext);
.
There is a good complete example of this in the source code in the file src/backend/utils/adt/varlena.c - see the functions string_agg_transfn() and makeStringAggState().
Once I got this fixed my aggregate was much happier