Discussion:
pointers to void
Add Reply
Stefan Ram
2017-05-05 15:47:45 UTC
Reply
Permalink
Raw Message
I wonder whether the wording in the standard makes it sufficiently
clear that a pointer to void cannot be dereferenced.

»The unary * operator denotes indirection. If the
operand points to a function, the result is a function
designator; 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.«

main.c

#include <stdio.h>

int main( void )
{ char const * const a = "abc";
void const * const p = a;
*p; }

transcript

warning: dereferencing 'void *' pointer

So, this is just a warning?

main.c

#include <stdio.h>

int main( void )
{ char const * const a = "abc";
void const * const p = a;
printf( "%zu\n", sizeof *p ); }

transcript

error: invalid application of 'sizeof' to a void type

So, »*p« is a legal void expression? (Only the application
of sizeof then is an error.)

Of course, there is not much one can do with »*p«.

main.c

#include <stdio.h>

int main( void )
{ char const * const a = "abc";
void const * const p = a;
printf( "%s\n", ( char * )&*p ); }

transcript

warning: dereferencing 'void *' pointer

abc

So, it seems that in C there is nothing that forbids
to dereference a pointer to void! It's only that there
is not much one can do with an expression of type void.
One cannot even return it from within a function returning void.

main.c

#include <stdio.h>

void f()
{ char const * const a = "abc";
void const * const p = a;
return *p; }

int main( void ) { }

transcript

error: ISO C forbids 'return' with expression, in function returning void [-Wpedantic]
Stefan Ram
2017-05-05 16:08:06 UTC
Reply
Permalink
Raw Message
Post by Stefan Ram
I wonder whether the wording in the standard makes it sufficiently
clear that a pointer to void cannot be dereferenced.
The following program should have undefined behavior
according to my guess.

It converts a pointer to an int object to a pointer
to double and then dereferences the result.

main.c

#include <stdio.h>
int main( void )
{ int n = 123;
int const * const a = &n;
void const * const p = a;
double const * const q = p;
double const d = *q;
printf( "%g\n", d ); }

transcript

1.6976e-313

However, I am not able to derive the UB from the standard.
Maybe the standard simply does not talk about it (and
thereby make it undefined)?

I looked at the section about the dereference operator
»*« and about the cast operator (though I do not actually
use it above).

I expected wording equivalent to the following in the
standard:

»When an address of type pointer-to-T is dereferenced,
there must be an actual object of type T at this address.
Otherwise the behavior is undefined.«

Maybe something like this can be found in the standard,
and I just did not look at the right places?
Stefan Ram
2017-05-05 16:20:58 UTC
Reply
Permalink
Raw Message
Post by Stefan Ram
However, I am not able to derive the UB from the standard.
Maybe the standard simply does not talk about it (and
thereby make it undefined)?
This interpretation would be supported by

»6.3.2.3 Pointers 1 A pointer to void may be converted
to or from a pointer to any object type. A pointer to
any object type may be converted to a pointer to void
and back again; the result shall compare equal to the
original pointer.«.

That is, this paragraph makes a guarantee for converting a
pointer to an object to a pointer to void and then back
(presumably, to the /same/ address type), but does not give
any other guarantee. So possibly the standard just remains
silent about any other pointer conversions and thus makes
them »undefined by silence«?

But it is common to convert the result of »malloc« to a
pointer to an object type, and so the standard should
give some guarantee that does not give this common usage
undefined behavior.
Ben Bacarisse
2017-05-05 16:34:00 UTC
Reply
Permalink
Raw Message
Post by Stefan Ram
Post by Stefan Ram
I wonder whether the wording in the standard makes it sufficiently
clear that a pointer to void cannot be dereferenced.
The following program should have undefined behavior
according to my guess.
It converts a pointer to an int object to a pointer
to double and then dereferences the result.
main.c
#include <stdio.h>
int main( void )
{ int n = 123;
int const * const a = &n;
void const * const p = a;
double const * const q = p;
double const d = *q;
printf( "%g\n", d ); }
transcript
1.6976e-313
However, I am not able to derive the UB from the standard.
You need 6.5 p6 and p7.

You may also get an undefined program because the pointer is incorrectly
aligned or the "target" contains a trap representation though I'm not
sure it makes sense to say "also UB because..." when something is
already undefined.

<snip>
--
Ben.
Keith Thompson
2017-05-05 16:31:57 UTC
Reply
Permalink
Raw Message
Post by Stefan Ram
I wonder whether the wording in the standard makes it sufficiently
clear that a pointer to void cannot be dereferenced.
»The unary * operator denotes indirection. If the
operand points to a function, the result is a function
designator; 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.«
[...]
Post by Stefan Ram
warning: dereferencing 'void *' pointer
So, this is just a warning?
You can't conclude anything from the fact that your compiler treats
this as a warning rather than a fatal error. The standard doesn't
distinguish between warnings and errors; it merely requires a
diagnostic message for any program that violates a syntax rule or
constraint. So *if* dereferencing a void* pointer is a constraint
violation, then your compiler has done its job by warning you
about it.

(I would have assumed that dereferencing a void* would be a
constraint violation, but I haven't found anything in the standard
that says so.)

[...]
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Tim Rentsch
2017-05-05 17:08:41 UTC
Reply
Permalink
Raw Message
Post by Keith Thompson
(I would have assumed that dereferencing a void* would be a
constraint violation, but I haven't found anything in the standard
that says so.)
Have you forgotten? We talked about this recently as
part of the thread discussing taking the address of
a register variable. It's only undefined behavior,
not a constraint violation.

Tim Rentsch
2017-05-05 17:05:56 UTC
Reply
Permalink
Raw Message
Post by Stefan Ram
I wonder whether the wording in the standard makes it sufficiently
clear that a pointer to void cannot be dereferenced.
Refer to section 6.3.2.1 paragraph 2:

If the lvalue has an incomplete type and does not have array
type, the behavior is undefined.
Loading...