Thread

Commits

  1. Remove special checks for pg_rewrite.ev_qual and ev_action being NULL.

  1. Explicit NULL dereference (src/backend/utils/adt/ruleutils.c)

    Ranier Vilela <ranier.vf@gmail.com> — 2020-10-31T14:49:07Z

    Hi,
    
    Per Coverity.
    
    make_ruledef function can dereference a NULL pointer (actions),
    if "ev_qual" is provided and "actions" does not exist.
    
    The comment there is contradictory: " /* these could be nulls */ "
    Because if "ev_qual" is not null, "actions" cannot be either.
    
    Solution proposed merely as a learning experience.
    
    regards,
    Ranier Vilela
    
  2. Re: Explicit NULL dereference (src/backend/utils/adt/ruleutils.c)

    Kyotaro Horiguchi <horikyota.ntt@gmail.com> — 2020-11-02T01:36:10Z

    At Sat, 31 Oct 2020 11:49:07 -0300, Ranier Vilela <ranier.vf@gmail.com> wrote in 
    > Per Coverity.
    > 
    > make_ruledef function can dereference a NULL pointer (actions),
    > if "ev_qual" is provided and "actions" does not exist.
    > 
    > The comment there is contradictory: " /* these could be nulls */ "
    > Because if "ev_qual" is not null, "actions" cannot be either.
    > 
    > Solution proposed merely as a learning experience.
    
    We cannot reach there with ev_action == NULL since it comes from a
    non-nullable column. Since most of the other columns has an assertion
    that !isnull, I think we should do the same thing for ev_action (and
    ev_qual).  SPI_getvalue() returns C-NULL for SQL-NULL (or for some
    other unexpected situations.).
    
    regards.
    
    -- 
    Kyotaro Horiguchi
    NTT Open Source Software Center
    
  3. Re: Explicit NULL dereference (src/backend/utils/adt/ruleutils.c)

    Tom Lane <tgl@sss.pgh.pa.us> — 2020-11-02T02:05:29Z

    Kyotaro Horiguchi <horikyota.ntt@gmail.com> writes:
    > We cannot reach there with ev_action == NULL since it comes from a
    > non-nullable column. Since most of the other columns has an assertion
    > that !isnull, I think we should do the same thing for ev_action (and
    > ev_qual).  SPI_getvalue() returns C-NULL for SQL-NULL (or for some
    > other unexpected situations.).
    
    Isn't the comment just above there wrong?
    
     	/* these could be nulls */
    
    I wonder just when that became outdated.
    
    			regards, tom lane
    
    
    
    
  4. Re: Explicit NULL dereference (src/backend/utils/adt/ruleutils.c)

    Kyotaro Horiguchi <horikyota.ntt@gmail.com> — 2020-11-02T02:19:09Z

    At Mon, 02 Nov 2020 10:36:10 +0900 (JST), Kyotaro Horiguchi <horikyota.ntt@gmail.com> wrote in 
    > At Sat, 31 Oct 2020 11:49:07 -0300, Ranier Vilela <ranier.vf@gmail.com> wrote in 
    > > Per Coverity.
    > > 
    > > make_ruledef function can dereference a NULL pointer (actions),
    > > if "ev_qual" is provided and "actions" does not exist.
    > > 
    > > The comment there is contradictory: " /* these could be nulls */ "
    > > Because if "ev_qual" is not null, "actions" cannot be either.
    > > 
    > > Solution proposed merely as a learning experience.
    > 
    > We cannot reach there with ev_action == NULL since it comes from a
    > non-nullable column. Since most of the other columns has an assertion
    > that !isnull, I think we should do the same thing for ev_action (and
    > ev_qual).  SPI_getvalue() returns C-NULL for SQL-NULL (or for some
    > other unexpected situations.).
    
    The following code is found there, since 1998. (15cb32d93e)
    
    >	/* If the rule has an event qualification, add it */
    >	if (ev_qual == NULL)
    >		ev_qual = "";
    
    The problem code here was written as the follows.
    
    +    fno = SPI_fnumber(rulettc, "is_instead");
    +    is_instead = (bool)SPI_getbinval(ruletup, rulettc, fno, &isnull);
    +
    +    fno = SPI_fnumber(rulettc, "ev_qual");
    +    ev_qual = SPI_getvalue(ruletup, rulettc, fno);
    +    if (isnull) ev_qual = NULL;
    +
    +    fno = SPI_fnumber(rulettc, "ev_action");
    +    ev_action = SPI_getvalue(ruletup, rulettc, fno);
    +    if (isnull) ev_action = NULL;
    +    if (ev_action != NULL) {
    +        actions = (List *)stringToNode(ev_action);
    +    }
    
    I'm not sure what the code means by just reading there but at least it
    seems impossible for the current code to return NULL for legit values.
    
    regards.
    
    -- 
    Kyotaro Horiguchi
    NTT Open Source Software Center
    
  5. Re: Explicit NULL dereference (src/backend/utils/adt/ruleutils.c)

    Kyotaro Horiguchi <horikyota.ntt@gmail.com> — 2020-11-02T04:36:23Z

    At Sun, 01 Nov 2020 21:05:29 -0500, Tom Lane <tgl@sss.pgh.pa.us> wrote in 
    > Kyotaro Horiguchi <horikyota.ntt@gmail.com> writes:
    > > We cannot reach there with ev_action == NULL since it comes from a
    > > non-nullable column. Since most of the other columns has an assertion
    > > that !isnull, I think we should do the same thing for ev_action (and
    > > ev_qual).  SPI_getvalue() returns C-NULL for SQL-NULL (or for some
    > > other unexpected situations.).
    > 
    > Isn't the comment just above there wrong?
    > 
    >  	/* these could be nulls */
    > 
    > I wonder just when that became outdated.
    
    Mmm. I investigated that.
    
    At the very beginning of CREATE RULE (d31084e9d1, 1996), InsertRule()
    did the following.
    
    >    template = "INSERT INTO pg_rewrite \
    >(rulename, ev_type, ev_class, ev_attr, action, ev_qual, is_instead) VALUES \
    >('%s', %d::char, %d::oid, %d::int2, '%s'::text, '%s'::text, \
    > '%s'::bool);";
    >    if (strlen(template) + strlen(rulname) + strlen(actionbuf) +
    >	strlen(qualbuf) + 20 /* fudge fac */ >  RULE_PLAN_SIZE) {
    >	elog(WARN, "DefineQueryRewrite: rule plan string too big.");
    >    }
    >    sprintf(rulebuf, template,
    >	    rulname, evtype, eventrel_oid, evslot_index, actionbuf,
    >	    qualbuf, is_instead);
    
    Doesn't seem that ev_qual and ev_action can be NULL.  The same
    function in the current converts action list to string using
    nodeToSTring so NIL is converted into '<>', which is not NULL.
    
    So I think ev_action cannot be null from the beginning of the history
    unless the columns is modified manually.  ev_qual and ev_action are
    marked as non-nullable (9b39b799db, in 2018). They could be null if we
    modified that columns nullable then set NULL, but that could happen on
    all other columns in pg_rewite catalog, which are Assert(!null)ed.
    
    Although ev_action cannot be a empty list using SQL interface. So we
    can get rid of the case list_length(action) == 0, but I'm not sure
    it's worth doing (but the attaches does..).
    
    regards.
    
    -- 
    Kyotaro Horiguchi
    NTT Open Source Software Center
    
  6. Re: Explicit NULL dereference (src/backend/utils/adt/ruleutils.c)

    Ranier Vilela <ranier.vf@gmail.com> — 2020-11-02T11:25:27Z

    Em seg., 2 de nov. de 2020 às 01:36, Kyotaro Horiguchi <
    horikyota.ntt@gmail.com> escreveu:
    
    > At Sun, 01 Nov 2020 21:05:29 -0500, Tom Lane <tgl@sss.pgh.pa.us> wrote in
    > > Kyotaro Horiguchi <horikyota.ntt@gmail.com> writes:
    > > > We cannot reach there with ev_action == NULL since it comes from a
    > > > non-nullable column. Since most of the other columns has an assertion
    > > > that !isnull, I think we should do the same thing for ev_action (and
    > > > ev_qual).  SPI_getvalue() returns C-NULL for SQL-NULL (or for some
    > > > other unexpected situations.).
    > >
    > > Isn't the comment just above there wrong?
    > >
    > >       /* these could be nulls */
    > >
    > > I wonder just when that became outdated.
    >
    > Mmm. I investigated that.
    >
    > At the very beginning of CREATE RULE (d31084e9d1, 1996), InsertRule()
    > did the following.
    >
    > >    template = "INSERT INTO pg_rewrite \
    > >(rulename, ev_type, ev_class, ev_attr, action, ev_qual, is_instead)
    > VALUES \
    > >('%s', %d::char, %d::oid, %d::int2, '%s'::text, '%s'::text, \
    > > '%s'::bool);";
    > >    if (strlen(template) + strlen(rulname) + strlen(actionbuf) +
    > >       strlen(qualbuf) + 20 /* fudge fac */ >  RULE_PLAN_SIZE) {
    > >       elog(WARN, "DefineQueryRewrite: rule plan string too big.");
    > >    }
    > >    sprintf(rulebuf, template,
    > >           rulname, evtype, eventrel_oid, evslot_index, actionbuf,
    > >           qualbuf, is_instead);
    >
    > Doesn't seem that ev_qual and ev_action can be NULL.  The same
    > function in the current converts action list to string using
    > nodeToSTring so NIL is converted into '<>', which is not NULL.
    >
    > So I think ev_action cannot be null from the beginning of the history
    > unless the columns is modified manually.  ev_qual and ev_action are
    > marked as non-nullable (9b39b799db, in 2018). They could be null if we
    > modified that columns nullable then set NULL, but that could happen on
    > all other columns in pg_rewite catalog, which are Assert(!null)ed.
    >
    > Although ev_action cannot be a empty list using SQL interface. So we
    > can get rid of the case list_length(action) == 0, but I'm not sure
    > it's worth doing (but the attaches does..).
    >
    I think that Assert is not the right solution here.
    
    For a function that returns NULL twice (SPI_getvalue), it is worth testing
    the result against NULL.
    In the future, any modification may cause further dereference.
    In addition, the static analysis tools would continue to note this snippet
    either as a bug or as a suspect.
    
    Checking "actions" pointer against NULL, and acting appropriately would do.
    
    regards,
    Ranier Vilela
    
  7. Re: Explicit NULL dereference (src/backend/utils/adt/ruleutils.c)

    Tom Lane <tgl@sss.pgh.pa.us> — 2020-11-02T19:49:50Z

    Ranier Vilela <ranier.vf@gmail.com> writes:
    > Em seg., 2 de nov. de 2020 às 01:36, Kyotaro Horiguchi <
    > horikyota.ntt@gmail.com> escreveu:
    >> Doesn't seem that ev_qual and ev_action can be NULL.  The same
    >> function in the current converts action list to string using
    >> nodeToSTring so NIL is converted into '<>', which is not NULL.
    
    > I think that Assert is not the right solution here.
    
    I think there's some confusion here: whether the ev_actions column can
    contain a SQL NULL is a very different thing from whether the result of
    stringToNode() on it can be a NIL list.  The latter should also not
    happen, but it's not enforced by low-level code in the same way that
    the NOT NULL property is.  So in my judgment, it's okay for us to just
    Assert that we got a not-null datum, but it's probably worth expending
    an actual test-and-elog for the NIL-list case.
    
    Of course, someone could put a string into that column that doesn't
    read out as a List at all, or it does but the elements aren't Query
    nodes, etc etc.  There's a very finite limit to how much code I'm
    willing to expend on such scenarios.  But a test for NIL list seems
    reasonable, since this function previously had what looked like sane
    handling for that case.
    
    Anyway, I adjusted Kyotaro-san's patch a bit (including fixing the
    near identical code in make_viewdef) and pushed it.
    
    			regards, tom lane
    
    
    
    
  8. Re: Explicit NULL dereference (src/backend/utils/adt/ruleutils.c)

    Kyotaro Horiguchi <horikyota.ntt@gmail.com> — 2020-11-04T01:41:07Z

    At Mon, 02 Nov 2020 14:49:50 -0500, Tom Lane <tgl@sss.pgh.pa.us> wrote in 
    > Ranier Vilela <ranier.vf@gmail.com> writes:
    > > Em seg., 2 de nov. de 2020 às 01:36, Kyotaro Horiguchi <
    > > horikyota.ntt@gmail.com> escreveu:
    > >> Doesn't seem that ev_qual and ev_action can be NULL.  The same
    > >> function in the current converts action list to string using
    > >> nodeToSTring so NIL is converted into '<>', which is not NULL.
    > 
    > > I think that Assert is not the right solution here.
    > 
    > I think there's some confusion here: whether the ev_actions column can
    > contain a SQL NULL is a very different thing from whether the result of
    > stringToNode() on it can be a NIL list.  The latter should also not
    > happen, but it's not enforced by low-level code in the same way that
    > the NOT NULL property is.  So in my judgment, it's okay for us to just
    > Assert that we got a not-null datum, but it's probably worth expending
    > an actual test-and-elog for the NIL-list case.
    > 
    > Of course, someone could put a string into that column that doesn't
    > read out as a List at all, or it does but the elements aren't Query
    > nodes, etc etc.  There's a very finite limit to how much code I'm
    > willing to expend on such scenarios.  But a test for NIL list seems
    > reasonable, since this function previously had what looked like sane
    > handling for that case.
    > 
    > Anyway, I adjusted Kyotaro-san's patch a bit (including fixing the
    > near identical code in make_viewdef) and pushed it.
    
    Thanks!
    
    -- 
    Kyotaro Horiguchi
    NTT Open Source Software Center