From: | Andres Freund <andres(at)anarazel(dot)de> |
---|---|
To: | Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us> |
Cc: | pgsql-hackers(at)lists(dot)postgresql(dot)org, Robert Haas <robertmhaas(at)gmail(dot)com>, Thomas Munro <thomas(dot)munro(at)gmail(dot)com> |
Subject: | Re: Pointer subtraction with a null pointer |
Date: | 2022-03-26 17:49:53 |
Message-ID: | 20220326174953.gdeasrl5wzal42ic@alap3.anarazel.de |
Views: | Raw Message | Whole Thread | Download mbox | Resend email |
Thread: | |
Lists: | pgsql-hackers |
Hi,
On 2022-03-26 13:23:34 -0400, Tom Lane wrote:
> I wrote:
> > Andres Freund <andres(at)anarazel(dot)de> writes:
> >> On 2022-03-26 12:13:12 -0400, Tom Lane wrote:
> >>> This code is old, but mylodon wasn't doing that a week ago, so
> >>> Andres must've updated the compiler and/or changed its options.
>
> >> Yep, updated it to clang 13. It's a warning present in 13, but not in 12.
>
> > OK, that answers that.
>
> ... Actually, after looking closer, I misread what our code is doing.
> These call sites are trying to set the relptr value to "null" (zero),
> and AFAICS it should be allowed:
>
> freepage.c:188:2: warning: performing pointer subtraction with a null pointer has undefined behavior [-Wnull-pointer-subtraction]
> relptr_store(base, fpm->btree_root, (FreePageBtree *) NULL);
> ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> ../../../../src/include/utils/relptr.h:63:59: note: expanded from macro 'relptr_store'
> (rp).relptr_off = ((val) == NULL ? 0 : ((char *) (val)) - (base)))
> ~~~~~~~~~~~~~~~~ ^
>
> clang is complaining about the subtraction despite it being inside
> a conditional arm that cannot be reached when val is null.
Huh, yea. I somehow read the conditional branch as guarding against a an
uninitialized base pointer or such.
> It's hard to see how that isn't a flat-out compiler bug.
It only happens if the NULL is directly passed as an argument to the macro,
not if there's an intermediary variable. Argh.
#include <stddef.h>
#define relptr_store(base, rp, val) \
((rp).relptr_off = ((val) == NULL ? 0 : ((char *) (val)) - (base)))
typedef union { struct foo *relptr_type; size_t relptr_off; } relptr;
void
problem_not_present(relptr *rp, char *base)
{
struct foo *val = NULL;
relptr_store(base, *rp, val);
}
void
problem_present(relptr *rp, char *base)
{
relptr_store(base, *rp, NULL);
}
Looks like that warning is uttered whenever there's a subtraction from a
pointer with NULL, even if the code isn't reachable. Which I guess makes
*some* sense, outside of macros it's not something that'd ever be reasonable.
Wonder if we should try to get rid of the problem by also fixing the double
evaluation of val? I think something like
static inline void
relptr_store_internal(size_t *off, char *base, char *val)
{
if (val == NULL)
*off = 0;
else
*off = val - base;
}
#ifdef HAVE__BUILTIN_TYPES_COMPATIBLE_P
#define relptr_store(base, rp, val) \
(AssertVariableIsOfTypeMacro(base, char *), \
AssertVariableIsOfTypeMacro(val, __typeof__((rp).relptr_type)), \
relptr_store_internal(&(rp).relptr_off, base, (char *) val))
#else
...
should do the trick?
Might also be worth adding an assertion that base < val.
> However, granting that it isn't going to get fixed right away,
> we could replace these call sites with "relptr_store_null()",
> and maybe get rid of the conditional in relptr_store().
Also would be good with that.
Greetings,
Andres Freund
From | Date | Subject | |
---|---|---|---|
Next Message | Tom Lane | 2022-03-26 17:51:07 | Re: Pointer subtraction with a null pointer |
Previous Message | Dmitry Dolgov | 2022-03-26 17:40:35 | Re: pg_stat_statements and "IN" conditions |