In the wake of commits 7d8f59577+80aa9848b, Coverity has begun
bleating like this:

*** CID 1659393:         Memory - illegal accesses  (USE_AFTER_FREE)
/srv/coverity/git/pgsql-git/postgresql/contrib/postgres_fdw/postgres_fdw.c: 
4930             in postgresAnalyzeForeignTable()
4924            res = pgfdw_exec_query(conn, sql.data, NULL);
4925            if (PQresultStatus(res) != PGRES_TUPLES_OK)
4926                    pgfdw_report_error(ERROR, res, conn, sql.data);
4927     
4928            if (PQntuples(res) != 1 || PQnfields(res) != 1)
4929                    elog(ERROR, "unexpected result from 
deparseAnalyzeSizeSql query");
>>>     CID 1659393:         Memory - illegal accesses  (USE_AFTER_FREE)
>>>     Calling "libpqsrv_PQgetvalue" dereferences freed pointer "res->res".
4930            *totalpages = strtoul(PQgetvalue(res, 0, 0), NULL, 10);
4931            PQclear(res);
4932     
4933            ReleaseConnection(conn);
4934     
4935            return true;

(and similarly in other places in postgres_fdw).  Now, this complaint
is nonsense because we won't get past the PQresultStatus and
pgfdw_report_error bit if we don't have a fully valid PGresult.
Evidently, Coverity is not managing to figure out that
pgfdw_report_error(ERROR, ...) doesn't return.  That's a bit
surprising because it normally does fairly deep interprocedural
analysis, but the conclusion is hard to avoid.  Certainly, any
C compiler that doesn't do deep LTO is not going to figure it
out either.  I think we have previously just dismissed similar
Coverity complaints, but it seems like we ought to try to fix
it properly this time.

I can see two, or two-and-a-half, ways to do that:

1. Wrap pgfdw_report_error in a macro that makes use of pg_unreachable
in a way similar to what we've done for elog/ereport.  The argument
for this is that we needn't touch the 30-or-so pgfdw_report_error
call sites; the argument against is that those elog/ereport macros
are messy, compiler-dependent, and keep needing changes.

2a. Split pgfdw_report_error into two functions, say
pgfdw_report_error() that hard-wires elevel as ERROR and is
labeled noreturn, and pgfdw_report_noerror() that has an
elevel argument that it asserts is less than ERROR.

2b. As 2a except the two functions are pgfdw_report_error()
and pgfdw_report_warning(), both with hard-wired elevel values.
This'd be sufficient right now, but it's plausible that this path
would lead to needing pgfdw_report_log() and some other variants
in future.

The argument for 2a/2b is that they're really simple and are
unlikely to break in the future.  The argument against is that
the changes would create back-patching hazards --- but maybe
it'd be reasonable to back-patch the changes to forestall that.

I'm kind of leaning to doing 2a and back-patching it, but
that's certainly a judgment call.  Anyone want to argue
for a different approach?

                        regards, tom lane


Reply via email to