Dereferencing a null pointer to an array, then converting to pointer to first element

Alejandro Colomar via Gcc-help <[email protected]>
Newsgroups gmane.comp.gcc.help
Message-ID <iazvnjxf7ggycerkpdac7krawcrcemotqhc6nvtxdvdmbmbjvq@d2w5ojzt6vol>
Hi!

The wording of the ISO C standard seems to say that the following
program has undefined behavior:

	alx@devuan:~/tmp$ cat null.c 
	#include <stddef.h>

	int
	main(void)
	{
		int  (*null)[42] = NULL;
		int  *p = *null;
	}

C23::6.5.4.2 ("Address and indirection operators") is the relevant
section.

6.5.4.2p3:

	The unary & operator yields the address of its operand.
	If the operand has type "type",
	the result has type "pointer to type".
	If the operand is the result of a unary * operator,
	neither that operator nor the & operator is evaluated
	and the result is as if both were omitted,
	except that the constraints on the operators still apply
	and the result is not an lvalue.
	Similarly, if the operand is the result of a [] operator,
	neither the & operator
	nor the unary * that is implied by the []
	is evaluated
	and the result is as if
	the & operator were removed
	and the [] operator were changed to a + operator.
	Otherwise,
	the result is a pointer to the object or function
	designated by its operand.

It says that if I counter the effects of '*' or '[]' with '&', that has
well defined behavior.  However, in this case there's no '&'.  And even
if we were to understand that the implied '&' from the conversion to a
pointer to the first element in the array, we'd have to also consider
the implied '[0]' from searching the first element, so it would be this:

	int  *p = &(*null)[0];

The paragraph above seems to say that the '&' would cancel the '[0]',
but it doesn't seem to cancel the '*', so it remains.  So we need to
consider the semantics of '*', specified in the following paragraph.
According to the standard the above would be equivalent to

	int  *p = *null + 0;

6.5.4.2p4:

	The unary * operator denotes indirection.
	If the operand points to a function, [...];
	if it points to an object,
	the result is an lvalue designating the object.
	If the operand has type "pointer to type",
	the result has type "type".
	If an invalid value has been assigned to the pointer,
	the behavior of the unary * operator is undefined.101)

The last sentence says this has undefined behavior, but let's consult
the footnote.

101)
	Thus,
	&*E is equivalent to E (even if E is a null pointer),
	and &(E1[E2]) to ((E1)+(E2)).
	It is always true that if E is a function designator
	or an lvalue that is a valid operand of the unary & operator,
	*&E is a function designator
	or an lvalue equal to E.
	If *P is an lvalue and T is the name of an object pointer type,
	*(T)P is an lvalue
	that has a type compatible with that to which T points.

It doesn't seem to say anything that would allow this code, so it
remains with undefined behavior.

	alx@devuan:~/tmp$ gcc -Wall -Wextra -Wno-unused null.c 
	alx@devuan:~/tmp$ clang -Weverything -Wno-unused null.c 
	alx@devuan:~/tmp$ 

However, the usual compilers don't complain.  Is this formally supported
by GCC?  Or is it a missing diagnostic and we can't rely on that?
I don't find this documented as an extension in the GCC manual.

I'll also propose to the C Committee that the wording is improved to
allow this code, but regardless, it would be good to know if GCC already
supports this.


Have a lovely day!
Alex

-- 
<https://www.alejandro-colomar.es>
Use port 80 (that is, <...:80/>).
signature.asc (application/pgp-signature, 833 B)
-----BEGIN PGP SIGNATURE-----

iQIzBAABCgAdFiEES7Jt9u9GbmlWADAi64mZXMKQwqkFAmkcOWQACgkQ64mZXMKQ
wqn9JA//T2acqScff6GYfgF1v0IJiEHD7HNpIhbebiETNjKEiE1OcnRxnvq4zEDg
RksSiBP6rAi1k8jpaXGK/FcNZ2oHB1ztjU7NOqz+gSIV4BN0uO89YOz9yIo7Q38F
96xxWle6Kiszqwoy248nY7Qx0W416Ac/PMRsUtLB5Hzd+zYHip8DydXbDi1CSsqq
6TId5OtGSHFMgo09wX5PNhYmMAO0BHrHRqWCDR4V7JA3xqWJft9u5qPDd2MFLiea
qtUoCVLJd6HLvr3nHdGEIOcruHr2Iw1NpNsSj9vLHaDuMYBo2mMpJaAWhrHPuC9Q
5k6P1VGEMEJso1dwBCJqiDxeJXZijwPfbIOB/XDGDIfwY8bsG3Fk2Y0BJu9iRlwN
0uXsueKCF4Y3OiXUxMOpEEp3XfInVdwejh3mnV63ZT77OQZ+DVnYR7DONMzRQWBB
0Gj2eIZqk1auCpH5VgkzSyLjBvM8aoBmVDGHI/dvZJuR45B1vGgiayrpPwXivzDj
qpVU4Yeoq22ZEa11mZWtEfRocQjjyDJ8n9MawM9bwgePLy3q9nCyp4iI1SgMpf/0
f4zc6HCUPtIP9OcICtFP6bcRe1HqTfpMrg7rar5JmRwUzbYFWZUGCaIYByrYx/To
vvWoTzu8EPX1ojazYbqaN1iLJA0yzZlZM9Jj/10Mj1+rW9oL2NY=
=0xC2
-----END PGP SIGNATURE-----
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.