• Tom Lane's avatar
    Prevent dangling-pointer access when update trigger returns old tuple. · 25b69256
    Tom Lane authored
    A before-update row trigger may choose to return the "new" or "old" tuple
    unmodified.  ExecBRUpdateTriggers failed to consider the second
    possibility, and would proceed to free the "old" tuple even if it was the
    one returned, leading to subsequent access to already-deallocated memory.
    In debug builds this reliably leads to an "invalid memory alloc request
    size" failure; in production builds it might accidentally work, but data
    corruption is also possible.
    
    This is a very old bug.  There are probably a couple of reasons it hasn't
    been noticed up to now.  It would be more usual to return NULL if one
    wanted to suppress the update action; returning "old" is significantly less
    efficient since the update will occur anyway.  Also, none of the standard
    PLs would ever cause this because they all returned freshly-manufactured
    tuples even if they were just copying "old".  But commit 4b93f579 changed
    that for plpgsql, making it possible to see the bug with a plpgsql trigger.
    Still, this is certainly legal behavior for a trigger function, so it's
    ExecBRUpdateTriggers's fault not plpgsql's.
    
    It seems worth creating a test case that exercises returning "old" directly
    with a C-language trigger; testing this through plpgsql seems unreliable
    because its behavior might change again.
    
    Report and fix by Rushabh Lathia; regression test case by me.
    Back-patch to all supported branches.
    
    Discussion: https://postgr.es/m/CAGPqQf1P4pjiNPrMof=P_16E-DFjt457j+nH2ex3=nBTew7tXw@mail.gmail.com
    25b69256
triggers.out 105 KB