Thread

Commits

  1. Suppress unused-variable warning.

  2. Make more use of castNode()

  3. Add castNode(type, ptr) for safe casting between NodeTag based types.

  4. Use the new castNode() macro in a number of places.

  1. safer node casting

    Peter Eisentraut <peter.eisentraut@2ndquadrant.com> — 2016-12-31T17:08:22Z

    There is a common coding pattern that goes like this:
    
        RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
        Assert(IsA(rinfo, RestrictInfo));
    
    (Arguably, the Assert should come before the cast, but I guess it's done
    this way out of convenience.)
    
    (Not to mention the other common coding pattern of just doing the cast
    and hoping for the best.)
    
    I propose a macro castNode() that combines the assertion and the cast,
    so this would become
    
        RestrictInfo *rinfo = castNode(RestrictInfo, lfirst(lc));
    
    This is inspired by the dynamic_cast operator in C++, but follows the
    syntax of the well-known makeNode() macro.
    
    Besides saving a bunch of code and making things safer, the function
    syntax also makes some code easier to read by saving levels of
    parentheses, for example:
    
    -           Assert(IsA(sstate->testexpr, BoolExprState));
    -           oplist = ((BoolExprState *) sstate->testexpr)->args;
    +           oplist = castNode(BoolExprState, sstate->testexpr)->args;
    
    Attached is a patch that shows how this would work.  There is a lot more
    that can be done, but I just stopped after a while for now.
    
    -- 
    Peter Eisentraut              http://www.2ndQuadrant.com/
    PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
    
  2. Re: safer node casting

    Tom Lane <tgl@sss.pgh.pa.us> — 2016-12-31T18:00:40Z

    Peter Eisentraut <peter.eisentraut@2ndquadrant.com> writes:
    > I propose a macro castNode() that combines the assertion and the cast,
    > so this would become
    >     RestrictInfo *rinfo = castNode(RestrictInfo, lfirst(lc));
    
    Seems like an OK idea, but I'm concerned by the implied multiple
    evaluations, particularly if you're going to apply this to function
    results --- as the above example does.  I think you need to go the
    extra mile to make it single-evaluation.  See newNode() for ideas.
    
    Just to bikeshed a bit ... would "castNode" be a better name?
    Seems like a closer analogy to makeNode(), for instance.
    
    			regards, tom lane
    
    
    
  3. Re: safer node casting

    Tom Lane <tgl@sss.pgh.pa.us> — 2016-12-31T18:38:55Z

    I wrote:
    > Just to bikeshed a bit ... would "castNode" be a better name?
    
    Um ... -ENOCAFFEINE.  Never mind that bit.
    
    			regards, tom lane
    
    
    
  4. Re: safer node casting

    Ashutosh Bapat <ashutosh.bapat@enterprisedb.com> — 2017-01-02T04:32:25Z

    On Sat, Dec 31, 2016 at 11:30 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
    > Peter Eisentraut <peter.eisentraut@2ndquadrant.com> writes:
    >> I propose a macro castNode() that combines the assertion and the cast,
    >> so this would become
    >>     RestrictInfo *rinfo = castNode(RestrictInfo, lfirst(lc));
    >
    
    +1. That would be wonderful.
    
    > Seems like an OK idea, but I'm concerned by the implied multiple
    > evaluations, particularly if you're going to apply this to function
    > results --- as the above example does.  I think you need to go the
    > extra mile to make it single-evaluation.  See newNode() for ideas.
    >
    
    +1.
    
    In case the Assert fails, the debugger would halt at castNode macro
    and a first time reader would be puzzled to see no assert there.
    Obviously looking at the #define should clarify the confusion. But I
    don't see how that can be avoided. I was thinking of using a function
    castNodeFunc(), but it can't accomodate Assert with _type_. Will
    calling this function as checkAndCastNode() help?
    
    -- 
    Best Wishes,
    Ashutosh Bapat
    EnterpriseDB Corporation
    The Postgres Database Company
    
    
    
  5. Re: safer node casting

    Andres Freund <andres@anarazel.de> — 2017-01-02T08:40:23Z

    Hi,
    
    
    On 2016-12-31 12:08:22 -0500, Peter Eisentraut wrote:
    > There is a common coding pattern that goes like this:
    > 
    >     RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
    >     Assert(IsA(rinfo, RestrictInfo));
    
    
    > I propose a macro castNode() that combines the assertion and the cast,
    > so this would become
    > 
    >     RestrictInfo *rinfo = castNode(RestrictInfo, lfirst(lc));
    
    I'm quite a bit in favor of something like this, having proposed it
    before ;)
    
    > +#define castNode(_type_,nodeptr)	(AssertMacro(!nodeptr || IsA(nodeptr,_type_)), (_type_ *)(nodeptr))
    
    ISTM that we need to do the core part of this in an inline function, to
    avoid multiple evaluation hazards - which seem quite likely to occur
    here - it's pretty common to cast the result of a function after all.
    
    Something like
    
    static inline Node*
    castNodeImpl(void *c, enum NodeTag t)
    {
        Assert(c == NULL || IsA(c, t));
        return c;
    }
    
    #define castNode(_type_, nodeptr) ((_type_ *) castNodeImpl(nodeptr, _type_))
    
    should work without too much trouble afaics?
    
    Greetings,
    
    Andres Freund
    
    
    
  6. Re: safer node casting

    Ashutosh Bapat <ashutosh.bapat@enterprisedb.com> — 2017-01-03T05:30:47Z

    On Mon, Jan 2, 2017 at 2:10 PM, Andres Freund <andres@anarazel.de> wrote:
    > Hi,
    >
    >
    > On 2016-12-31 12:08:22 -0500, Peter Eisentraut wrote:
    >> There is a common coding pattern that goes like this:
    >>
    >>     RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
    >>     Assert(IsA(rinfo, RestrictInfo));
    >
    >
    >> I propose a macro castNode() that combines the assertion and the cast,
    >> so this would become
    >>
    >>     RestrictInfo *rinfo = castNode(RestrictInfo, lfirst(lc));
    >
    > I'm quite a bit in favor of something like this, having proposed it
    > before ;)
    >
    >> +#define castNode(_type_,nodeptr)     (AssertMacro(!nodeptr || IsA(nodeptr,_type_)), (_type_ *)(nodeptr))
    >
    > ISTM that we need to do the core part of this in an inline function, to
    > avoid multiple evaluation hazards - which seem quite likely to occur
    > here - it's pretty common to cast the result of a function after all.
    >
    > Something like
    >
    > static inline Node*
    > castNodeImpl(void *c, enum NodeTag t)
    > {
    >     Assert(c == NULL || IsA(c, t));
    >     return c;
    > }
    >
    > #define castNode(_type_, nodeptr) ((_type_ *) castNodeImpl(nodeptr, _type_))
    >
    > should work without too much trouble afaics?
    >
    I tried this quickly as per attached patch. It gave a compiler error
    createplan.c: In function ‘castNodeImpl’:
    createplan.c:340:2: error: ‘T_t’ undeclared (first use in this function)
    createplan.c:340:2: note: each undeclared identifier is reported only
    once for each function it appears in
    createplan.c: In function ‘create_plan_recurse’:
    createplan.c:445:13: error: expected expression before ‘AggPath’
    
    Is the attached patch as per your suggestion?
    
    -- 
    Best Wishes,
    Ashutosh Bapat
    EnterpriseDB Corporation
    The Postgres Database Company
    
  7. Re: safer node casting

    Andres Freund <andres@anarazel.de> — 2017-01-04T08:10:44Z

    Hi,
    
    On 2017-01-03 11:00:47 +0530, Ashutosh Bapat wrote:
    > On Mon, Jan 2, 2017 at 2:10 PM, Andres Freund <andres@anarazel.de> wrote:
    > > Hi,
    > >
    > >
    > > On 2016-12-31 12:08:22 -0500, Peter Eisentraut wrote:
    > >> There is a common coding pattern that goes like this:
    > >>
    > >>     RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
    > >>     Assert(IsA(rinfo, RestrictInfo));
    > >
    > >
    > >> I propose a macro castNode() that combines the assertion and the cast,
    > >> so this would become
    > >>
    > >>     RestrictInfo *rinfo = castNode(RestrictInfo, lfirst(lc));
    > >
    > > I'm quite a bit in favor of something like this, having proposed it
    > > before ;)
    > >
    > >> +#define castNode(_type_,nodeptr)     (AssertMacro(!nodeptr || IsA(nodeptr,_type_)), (_type_ *)(nodeptr))
    > >
    > > ISTM that we need to do the core part of this in an inline function, to
    > > avoid multiple evaluation hazards - which seem quite likely to occur
    > > here - it's pretty common to cast the result of a function after all.
    > >
    > > Something like
    > >
    > > static inline Node*
    > > castNodeImpl(void *c, enum NodeTag t)
    > > {
    > >     Assert(c == NULL || IsA(c, t));
    > >     return c;
    > > }
    > >
    > > #define castNode(_type_, nodeptr) ((_type_ *) castNodeImpl(nodeptr, _type_))
    > >
    > > should work without too much trouble afaics?
    > >
    > I tried this quickly as per attached patch. It gave a compiler error
    > createplan.c: In function ‘castNodeImpl’:
    > createplan.c:340:2: error: ‘T_t’ undeclared (first use in this function)
    > createplan.c:340:2: note: each undeclared identifier is reported only
    > once for each function it appears in
    > createplan.c: In function ‘create_plan_recurse’:
    > createplan.c:445:13: error: expected expression before ‘AggPath’
    
    Well, I wrote that just to outline my suggestion, not as a patch ;).
    It's just that we have to replace IsA() with nodeTag(nodeptr) == t
    (because IsA does string concat magic).
    
    Greetings,
    
    Andres Freund
    
    
    
  8. Re: safer node casting

    Andres Freund <andres@anarazel.de> — 2017-01-26T00:16:34Z

    Hi Peter,
    
    
    On 2016-12-31 12:08:22 -0500, Peter Eisentraut wrote:
    >     RestrictInfo *rinfo = castNode(RestrictInfo, lfirst(lc));
    
    Are you planning to add this / update this patch? Because I really would
    have liked this a number of times already...  I can update it according
    to my suggestions (to avoid multiple eval scenarios) if helpful
    
    Greetings,
    
    Andres Freund
    
    
    
  9. Re: safer node casting

    Tom Lane <tgl@sss.pgh.pa.us> — 2017-01-26T00:21:40Z

    Andres Freund <andres@anarazel.de> writes:
    > On 2016-12-31 12:08:22 -0500, Peter Eisentraut wrote:
    >> RestrictInfo *rinfo = castNode(RestrictInfo, lfirst(lc));
    
    > Are you planning to add this / update this patch? Because I really would
    > have liked this a number of times already...  I can update it according
    > to my suggestions (to avoid multiple eval scenarios) if helpful
    
    Yeah, I'd like that in sooner rather than later, too.  But we do need
    it to be foolproof - no multiple evals.  The first draft had
    inadequate-parenthesization hazards, too.
    
    			regards, tom lane
    
    
    
  10. Re: safer node casting

    Andres Freund <andres@anarazel.de> — 2017-01-26T21:15:41Z

    On 2017-01-25 19:21:40 -0500, Tom Lane wrote:
    > Andres Freund <andres@anarazel.de> writes:
    > > On 2016-12-31 12:08:22 -0500, Peter Eisentraut wrote:
    > >> RestrictInfo *rinfo = castNode(RestrictInfo, lfirst(lc));
    >
    > > Are you planning to add this / update this patch? Because I really would
    > > have liked this a number of times already...  I can update it according
    > > to my suggestions (to avoid multiple eval scenarios) if helpful
    >
    > Yeah, I'd like that in sooner rather than later, too.  But we do need
    > it to be foolproof - no multiple evals.  The first draft had
    > inadequate-parenthesization hazards,
    
    How about something like the attached? The first patch just contains
    castNode(), the second one a rebased version of Peter's changes (with
    some long lines broken up).
    
    Andres
    
  11. Re: safer node casting

    Tom Lane <tgl@sss.pgh.pa.us> — 2017-01-26T21:55:33Z

    Andres Freund <andres@anarazel.de> writes:
    > How about something like the attached? The first patch just contains
    > castNode(), the second one a rebased version of Peter's changes (with
    > some long lines broken up).
    
    Looks generally good.  A couple quibbles from a quick read-through:
    
    * All but the first change in ProcessCopyOptions seem rather pointless:
    
     			else if (defel->arg && IsA(defel->arg, List))
    -				cstate->force_quote = (List *) defel->arg;
    +				cstate->force_quote = castNode(List, defel->arg);
    
    In these places, castNode() isn't checking anything the if-condition
    didn't.  Maybe it's good style anyway, but I'm not really convinced.
    
    * In ExecInitAgg:
    
     			aggnode = list_nth(node->chain, phase - 1);
    -			sortnode = (Sort *) aggnode->plan.lefttree;
    -			Assert(IsA(sortnode, Sort));
    +			sortnode = castNode(Sort, aggnode->plan.lefttree);
    
    it seems like the assignment to aggnode ought to have a castNode on it too
    (the fact that it lacks any cast now is sloppy and not per project style,
    IMO).
    
    There were a bunch of places in ab1f0c822 where I wished I had this,
    but I can go back and back-fill that later; doesn't need to be in the
    first commit.
    
    BTW, maybe it's just the first flush of enthusiasm, but I can see us
    using this so much that the lack of it in back branches will become
    a serious PITA for back-patching.  So I'm strongly tempted to propose
    that your 0001 should be back-patched.  However, before 9.6 we didn't
    have the compiler requirement that "static inline" in headers must be
    handled sanely.  Maybe a useful compromise would be to put 0001 in 9.6,
    and before that just add
    
    #define castNode(_type_,nodeptr)  ((_type_ *)(nodeptr))
    
    which would allow the notation to be used safely, albeit without
    any assertion backup.  Alternatively, we could enable the assertion
    code only for gcc, which would probably be plenty good enough for
    finding bugs in stable branches.
    
    			regards, tom lane
    
    
    
  12. Re: safer node casting

    Andres Freund <andres@anarazel.de> — 2017-01-26T22:24:46Z

    On 2017-01-26 16:55:33 -0500, Tom Lane wrote:
    > Andres Freund <andres@anarazel.de> writes:
    > > How about something like the attached? The first patch just contains
    > > castNode(), the second one a rebased version of Peter's changes (with
    > > some long lines broken up).
    > 
    > Looks generally good.  A couple quibbles from a quick read-through:
    > 
    > * All but the first change in ProcessCopyOptions seem rather pointless:
    > 
    >  			else if (defel->arg && IsA(defel->arg, List))
    > -				cstate->force_quote = (List *) defel->arg;
    > +				cstate->force_quote = castNode(List, defel->arg);
    > 
    > In these places, castNode() isn't checking anything the if-condition
    > didn't.  Maybe it's good style anyway, but I'm not really convinced.
    
    Agreed that it's not not necessary - I didn't add this one (or any
    castNode actually). But I don't think it matters much.
    
    
    > * In ExecInitAgg:
    > 
    >  			aggnode = list_nth(node->chain, phase - 1);
    > -			sortnode = (Sort *) aggnode->plan.lefttree;
    > -			Assert(IsA(sortnode, Sort));
    > +			sortnode = castNode(Sort, aggnode->plan.lefttree);
    > 
    > it seems like the assignment to aggnode ought to have a castNode on it
    > too
    
    Yea, looks good.
    
    
    > (the fact that it lacks any cast now is sloppy and not per project style,
    > IMO).
    
    There's a lot of these missing :(.  This is one of these things that'd
    be a lot easier to enforce if we'd be able to compile in a c++
    compatible mode (-Wc++-compat), because there void * to X * casts
    have to be done explicitly.
    
    
    > BTW, maybe it's just the first flush of enthusiasm, but I can see us
    > using this so much that the lack of it in back branches will become
    > a serious PITA for back-patching.
    
    Might, yea.
    
    
    > So I'm strongly tempted to propose
    > that your 0001 should be back-patched.  However, before 9.6 we didn't
    > have the compiler requirement that "static inline" in headers must be
    > handled sanely.  Maybe a useful compromise would be to put 0001 in 9.6,
    > and before that just add
    > 
    > #define castNode(_type_,nodeptr)  ((_type_ *)(nodeptr))
    > 
    > which would allow the notation to be used safely, albeit without
    > any assertion backup.  Alternatively, we could enable the assertion
    > code only for gcc, which would probably be plenty good enough for
    > finding bugs in stable branches.
    
    #if defined(USE_ASSERT_CHECKING) && defined(PG_USE_INLINE)
    is probably a better gatekeeper in the back-branches, than gcc? Then we
    can just remove the defined(PG_USE_INLINE) and it's associated comment
    in >= 9.6.
    
    Regards,
    
    Andres
    
    
    
  13. Re: safer node casting

    Tom Lane <tgl@sss.pgh.pa.us> — 2017-01-26T22:27:45Z

    Andres Freund <andres@anarazel.de> writes:
    > #if defined(USE_ASSERT_CHECKING) && defined(PG_USE_INLINE)
    > is probably a better gatekeeper in the back-branches, than gcc?
    
    Ah, yeah, that would work --- I'd already swapped out that business ;-)
    
    			regards, tom lane
    
    
    
  14. Re: safer node casting

    Andres Freund <andres@anarazel.de> — 2017-01-27T01:01:22Z

    On 2017-01-26 17:27:45 -0500, Tom Lane wrote:
    > Andres Freund <andres@anarazel.de> writes:
    > > #if defined(USE_ASSERT_CHECKING) && defined(PG_USE_INLINE)
    > > is probably a better gatekeeper in the back-branches, than gcc?
    > 
    > Ah, yeah, that would work --- I'd already swapped out that business ;-)
    
    Done that way.
    
    - Andres
    
    
    
  15. Re: safer node casting

    Andres Freund <andres@anarazel.de> — 2017-01-27T01:03:56Z

    Hi,
    
    On 2016-12-31 12:08:22 -0500, Peter Eisentraut wrote:
    > This is inspired by the dynamic_cast operator in C++, but follows the
    > syntax of the well-known makeNode() macro.
    
    The analogy to dynamic_cast goes only so far, because we don't actually
    support inheritance.  I.e. in c++ we could successfully cast SeqScanState to a
    PlanState, ScanState and SeqScanState - but with our model only
    SeqScanState can be checked.
    
    Greetings,
    
    Andres
    
    
    
  16. Re: safer node casting

    Tom Lane <tgl@sss.pgh.pa.us> — 2017-01-27T01:29:06Z

    Andres Freund <andres@anarazel.de> writes:
    > On 2016-12-31 12:08:22 -0500, Peter Eisentraut wrote:
    >> This is inspired by the dynamic_cast operator in C++, but follows the
    >> syntax of the well-known makeNode() macro.
    
    > The analogy to dynamic_cast goes only so far, because we don't actually
    > support inheritance.  I.e. in c++ we could successfully cast SeqScanState to a
    > PlanState, ScanState and SeqScanState - but with our model only
    > SeqScanState can be checked.
    
    Yeah, I was thinking about that earlier --- this can only be used to cast
    to a concrete node type, not one of the "abstract" types like Plan * or
    Expr *.  Not sure if that's worth worrying about though; I don't think
    I've ever seen actual bugs in PG code from casting the wrong thing in that
    direction.  For the most part, passing the wrong thing would end up firing
    a default: case in a switch, or some such, so we already do have some
    defenses for that direction.
    
    			regards, tom lane
    
    
    
  17. Re: safer node casting

    Andres Freund <andres@anarazel.de> — 2017-01-27T01:34:26Z

    On 2017-01-26 20:29:06 -0500, Tom Lane wrote:
    > Andres Freund <andres@anarazel.de> writes:
    > > On 2016-12-31 12:08:22 -0500, Peter Eisentraut wrote:
    > >> This is inspired by the dynamic_cast operator in C++, but follows the
    > >> syntax of the well-known makeNode() macro.
    > 
    > > The analogy to dynamic_cast goes only so far, because we don't actually
    > > support inheritance.  I.e. in c++ we could successfully cast SeqScanState to a
    > > PlanState, ScanState and SeqScanState - but with our model only
    > > SeqScanState can be checked.
    > 
    > Yeah, I was thinking about that earlier --- this can only be used to cast
    > to a concrete node type, not one of the "abstract" types like Plan * or
    > Expr *.  Not sure if that's worth worrying about though; I don't think
    > I've ever seen actual bugs in PG code from casting the wrong thing in that
    > direction.  For the most part, passing the wrong thing would end up firing
    > a default: case in a switch, or some such, so we already do have some
    > defenses for that direction.
    
    Yea, I'm not actually worried about it - I was more generally remarking
    on the analogy made by Peter. For a second I was considering bringing up
    the analogy in a comment or such, and this was one of a number of
    arguments that made me disregard that idea.
    
    Andres
    
    
    
  18. Re: safer node casting

    Peter Eisentraut <peter.eisentraut@2ndquadrant.com> — 2017-02-21T17:00:55Z

    On 1/26/17 16:15, Andres Freund wrote:
    > On 2017-01-25 19:21:40 -0500, Tom Lane wrote:
    >> Andres Freund <andres@anarazel.de> writes:
    >>> On 2016-12-31 12:08:22 -0500, Peter Eisentraut wrote:
    >>>> RestrictInfo *rinfo = castNode(RestrictInfo, lfirst(lc));
    >>
    >>> Are you planning to add this / update this patch? Because I really would
    >>> have liked this a number of times already...  I can update it according
    >>> to my suggestions (to avoid multiple eval scenarios) if helpful
    >>
    >> Yeah, I'd like that in sooner rather than later, too.  But we do need
    >> it to be foolproof - no multiple evals.  The first draft had
    >> inadequate-parenthesization hazards,
    > 
    > How about something like the attached? The first patch just contains
    > castNode(), the second one a rebased version of Peter's changes (with
    > some long lines broken up).
    
    Thanks for finishing that up.  I have committed more uses that I had
    lying around partially done.  Looks nice now.
    
    -- 
    Peter Eisentraut              http://www.2ndQuadrant.com/
    PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
    
    
    
  19. Re: safer node casting

    Jeff Janes <jeff.janes@gmail.com> — 2017-02-21T22:49:57Z

    On Tue, Feb 21, 2017 at 9:00 AM, Peter Eisentraut <
    peter.eisentraut@2ndquadrant.com> wrote:
    
    > On 1/26/17 16:15, Andres Freund wrote:
    > > On 2017-01-25 19:21:40 -0500, Tom Lane wrote:
    > >> Andres Freund <andres@anarazel.de> writes:
    > >>> On 2016-12-31 12:08:22 -0500, Peter Eisentraut wrote:
    > >>>> RestrictInfo *rinfo = castNode(RestrictInfo, lfirst(lc));
    > >>
    > >>> Are you planning to add this / update this patch? Because I really
    > would
    > >>> have liked this a number of times already...  I can update it according
    > >>> to my suggestions (to avoid multiple eval scenarios) if helpful
    > >>
    > >> Yeah, I'd like that in sooner rather than later, too.  But we do need
    > >> it to be foolproof - no multiple evals.  The first draft had
    > >> inadequate-parenthesization hazards,
    > >
    > > How about something like the attached? The first patch just contains
    > > castNode(), the second one a rebased version of Peter's changes (with
    > > some long lines broken up).
    >
    > Thanks for finishing that up.  I have committed more uses that I had
    > lying around partially done.  Looks nice now.
    >
    >
    With commit 38d103763d14baddf3cbfe4b00b501059fc9447f, I'm now getting a
    compiler warning:
    
    indxpath.c: In function 'generate_bitmap_or_paths':
    indxpath.c:1312: warning: unused variable 'rinfo'
    
    
    I have: gcc version 4.4.7 20120313 (Red Hat 4.4.7-17) (GCC)
    
    No arguments to ./configure are needed.
    
    Cheers,
    
    Jeff
    
  20. Re: safer node casting

    Tom Lane <tgl@sss.pgh.pa.us> — 2017-02-21T22:59:08Z

    Jeff Janes <jeff.janes@gmail.com> writes:
    > With commit 38d103763d14baddf3cbfe4b00b501059fc9447f, I'm now getting a
    > compiler warning:
    > indxpath.c: In function 'generate_bitmap_or_paths':
    > indxpath.c:1312: warning: unused variable 'rinfo'
    
    Me too, without asserts.  Fixed.
    
    			regards, tom lane
    
    
    
  21. Re: safer node casting

    Andres Freund <andres@anarazel.de> — 2017-02-24T12:31:27Z

    Hi,
    
    I was about to add a few more uses of castNode, which made me think.
    
    You proposed replacing:
    
    On 2016-12-31 12:08:22 -0500, Peter Eisentraut wrote:
    > There is a common coding pattern that goes like this:
    > 
    >     RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
    >     Assert(IsA(rinfo, RestrictInfo));
    
    with
    
    > +#define castNode(_type_,nodeptr)	(AssertMacro(!nodeptr || IsA(nodeptr,_type_)), (_type_ *)(nodeptr))
    (now an inline function, but that's besides my point)
    
    Those aren't actually equivalent, because of the !nodeptr. IsA() crashes
    for NULL pointers, but the new code won't. Which means 9ba8a9ce4548b et
    al actually weakened some asserts.
    
    Should we perhaps have one NULL accepting version (castNodeNull?) and
    one that separately asserts that ptr != NULL?
    
    Greetings,
    
    Andres Freund
    
    
    
  22. Re: safer node casting

    Tom Lane <tgl@sss.pgh.pa.us> — 2017-02-24T15:54:29Z

    Andres Freund <andres@anarazel.de> writes:
    > Those aren't actually equivalent, because of the !nodeptr. IsA() crashes
    > for NULL pointers, but the new code won't. Which means 9ba8a9ce4548b et
    > al actually weakened some asserts.
    
    > Should we perhaps have one NULL accepting version (castNodeNull?) and
    > one that separately asserts that ptr != NULL?
    
    -1 ... if you're going to use something in a way that requires it not to
     be null, your code will crash quite efficiently on a null, with or
     without an assert.  I don't think we need the extra cogitive burden of
     two distinct macros for this.
    
    			regards, tom lane
    
    
    
  23. Re: safer node casting

    Peter Eisentraut <peter.eisentraut@2ndquadrant.com> — 2017-02-24T16:17:26Z

    On 2/24/17 10:54, Tom Lane wrote:
    > Andres Freund <andres@anarazel.de> writes:
    >> Those aren't actually equivalent, because of the !nodeptr. IsA() crashes
    >> for NULL pointers, but the new code won't. Which means 9ba8a9ce4548b et
    >> al actually weakened some asserts.
    > 
    >> Should we perhaps have one NULL accepting version (castNodeNull?) and
    >> one that separately asserts that ptr != NULL?
    > 
    > -1 ... if you're going to use something in a way that requires it not to
    >  be null, your code will crash quite efficiently on a null, with or
    >  without an assert.  I don't think we need the extra cogitive burden of
    >  two distinct macros for this.
    
    I think we should just add some Assert(thepointer) where necessary.
    
    -- 
    Peter Eisentraut              http://www.2ndQuadrant.com/
    PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services