llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.45k stars 11.76k forks source link

Dereferencing void pointer shouldn't be rejected #112121

Open Halalaluyafail3 opened 2 hours ago

Halalaluyafail3 commented 2 hours ago

Clang rejects dereferencing a void pointer, for example:

*(void*)0;

I don't see any constraints that this would violate so this should be OK I think, at least as long as the expression goes unevaluated. GCC accepts this (with a warning by default), MSVC rejects it but even in contexts that should make sense like &*(void*)0.

llvmbot commented 2 hours ago

@llvm/issue-subscribers-clang-frontend

Author: None (Halalaluyafail3)

Clang rejects dereferencing a void pointer, for example: ```c *(void*)0; ``` I don't see any constraints that this would violate so this should be OK I think, at least as long as the expression goes unevaluated. GCC accepts this (with a warning by default), MSVC rejects it but even in contexts that should make sense like `&*(void*)0`.
frederick-vs-ja commented 1 hour ago

C++ clearly rejects this, see [expr.unary.op]/1.

The situation in C is somehow weird. Let's talk about a "possibly more well-defined" example instead:

int main(void)
{
    int i;
    *(void*)&i;
}

Quoting from N3220:

6.3.2.1 Lvalues, arrays, and function designators

1 An lvalue is an expression (with an object type other than void) that potentially designates an object55); if an lvalue does not designate an object when it is evaluated, the behavior is undefined.

(Note that cv void are object types in C.)

6.5.4.2 Address and indirection operators

4 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.101)

In the example above, the void* pointer does point to the i object, so the situation doesn't fall into UB by omission, and the result of dereferencing is an lvalue designating the object the i object. It's also specified that the operand has type “pointer to void”, so the result has type void. So "lvalue of type void" is formed here, which conflicts with 6.3.2.1/1.

60243 is related, although this issue is not its exact duplicate. CC @AaronBallman.