01.05.2023 07:04, Tom Lane wrote:
> Alexander Lakhin <exclusion@gmail.com> writes:
>> So I'm going to start it over and find a repro that will show something
>> interesting without Valgrind (and let estimate the probability of a
>> problem in the field).
> I think a probability estimate is not all that exciting: "it's low
> but not zero" is sufficient information to act on. What I am curious
> about is how come 86dc90056's changes triggered a visible problem.
> Understanding that might give us a better feel for what is the real
> structural issue here --- which I'm worried about because I have
> little confidence that there aren't similar bugs lurking in other
> code paths.
I've found one significant difference between old and new code paths.
On 86dc90056 I see the following call chain:
ExecGetUpdateNewTuple(planSlot = epqslot_candidate, oldSlot = oldslot):
econtext->ecxt_scantuple = oldSlot;
-> internalGetUpdateNewTuple() -> ExecProject(projInfo=relinfo->ri_projectNew)
-> ExecEvalExprSwitchContext(state=projInfo->pi_state, econtext=projInfo->pi_exprContext)
-> state->evalfunc(state, econtext, isNull);
-> ExecInterpExpr():
scanslot = econtext->ecxt_scantuple;
...
EEOP_SCAN_FETCHSOME: slot_getsomeattrs(scanslot, op->d.fetch.last_var);
So someattrs loaded into oldslot, which is released after
trigtuple = ExecFetchSlotHeapTuple(oldslot, true, &should_free_trig)
But before 86dc90056 we had:
ExecFilterJunk(junkfilter=relinfo->ri_junkFilter, slot=epqslot_candidate):
-> slot_getallattrs(slot);
-> slot_getsomeattrs(slot, slot->tts_tupleDescriptor->natts);
I. e., someattrs were loaded into the epqslot_candidate slot,
which wasn't touched by ExecFetchSlotHeapTuple(oldslot,...) and
the newslot's contents survived the call.
It's not a final conclusion, but maybe it could be helpful for someone who
investigates it too.
Best regards,
Alexander