| From: | Andres Freund <andres(at)anarazel(dot)de> |
|---|---|
| To: | Peter Eisentraut <peter(at)eisentraut(dot)org> |
| Cc: | Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>, Tatsuo Ishii <ishii(at)postgresql(dot)org>, pgsql-hackers(at)postgresql(dot)org |
| Subject: | Re: warning: dereferencing type-punned pointer |
| Date: | 2026-01-22 19:46:37 |
| Message-ID: | ujkndaqmyvahxm6ob3jnljqu5ihtfzm64ndewpra3t3dpgvsoj@e2jrtgjnkn7x |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-hackers |
Hi,
On 2025-12-01 17:08:15 +0100, Peter Eisentraut wrote:
> My conclusion is that casting Node * to a different pointer-to-struct is
> always an aliasing violation. The reason why the compiler only warns in a
> few cases is probably that those are fully within the same translation unit,
> while most other ones are across file boundaries that the compiler cannot
> analyze reliably. If you dial up the warning verbosity with
> -Wstrict-aliasing=1/2 (lower = more warnings but less reliable), you get
> more warnings about this.
>
> Unlike what PostgreSQL code appears to assume, there is no rule in C (or
> C++) that overlaying similar structs is a valid aliasing. So this was never
> correct, but compilers have only gotten more aggressive about this over
> time.
It's not clear to me that this is true.
C23's §6.7.3.2 contains (and earlier versions have similar language:
A pointer to a structure object, suitably converted, points to its initial
member (or if that member is a bit-field, then to the unit in which it
resides),
Which afaict means that it'd be legal to cast an ErrorSaveContext * to a
NodeTag*. Of course, IsA(), via nodeTag(), doesn't actually cast to NodeTag *,
but to Node *.
However, you qualified your answer with "to a different pointer-to-struct",
but afaict the rules would be the same if the "initial member" of two
different structs were a struct.
There's also C23's §6.5 7):
An object shall have its stored value accessed only by an lvalue expression that has one of
the following types:
...
— an aggregate or union type that includes one of the aforementioned types among its
members (including, recursively, a member of a subaggregate or contained union), or
which afaict means that if we *can* cast between different equivalent structs,
as long as they have the same initial sequence?
The purpose of the aliasing rules is to allow for type based alias analysis,
to figure out things like whether two pointers could potentially point to the
same memory. For that aggregate types don't really matter, it's just scalars
(and I guess bitfields, however you classify them) that do. And thus whether
you have overlayed structs with the same types doesn't really matter either [1].
The language around this is near impenetrable though, and hasn't improved
meaningfully since at least C99, so it's really hard to say.
Greetings,
Andres Freund
[1] There are some nasty cases where not being careful could lead to alignment
problems, but I don't think that's typically a problem in postgres.
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Álvaro Herrera | 2026-01-22 19:50:22 | Re: Race conditions in logical decoding |
| Previous Message | Robert Treat | 2026-01-22 19:42:52 | Re: Optional skipping of unchanged relations during ANALYZE? |