C++ Logo


Advanced search

Re: Casts from const object type to function pointer type

From: Thiago Macieira <thiago_at_[hidden]>
Date: Thu, 27 Apr 2023 08:19:13 -0700
On Wednesday, 26 April 2023 16:19:26 PDT Myria via Std-Discussion wrote:
> C++ says that reinterpret_casting an object pointer to a function pointer
> is conditionally supported. However, there seems to be implementation
> divergence on what happens if the object pointer is cv-qualified. GCC
> allows casts from cv object * to function pointer, but Clang and Visual C++
> do not.
> I mentioned this some years ago as a possible defect report, and I sent a
> request for one, but it never got filed.
> Should something like this be a defect report? What is the correct
> interpretation of the Standard on this? Being a conditionally supported
> operation, is either interpretation allowed?

Hello Myria


I think this should not be considered a defect in the standard. Instead, it
should be a considered a defect in GCC for allowing it, because it allows for
discarding a const qualifier without a const_cast, permitting this:

    const void *cptr = &i;
    auto fptr = reinterpret_cast<void (*)()>(cptr);
    auto ptr = reinterpret_cast<int *>(fptr);
    *ptr = 1;

(don't ask me what MSVC is doing there)

> [expr.reinterpret.cast]/2 <https://eel.is/c++draft/expr.reinterpret.cast#2>
> says that reinterpret_cast "shall not cast away constness". But is casting
> to function pointer type removing constness? [expr.reinterpret.cast]/8
> <https://eel.is/c++draft/expr.reinterpret.cast#8> mentions the possibility
> of cv-qualified casts in the other direction.

I would say so. Code is not necessarily const in all circumstances -- there's
such thing as self-modifying code (SMC) after all.

> #if !defined(__x86_64__) && !defined(_M_X64)
> #error "This is an x86-64-only program"
> #endif

I don't think there's any way to get to a standards-bounded situation where
the problem arises in the first place. You always need some level of platform-
specific knowledge.

And I could rewrite your code for real-mode i386 instead:

> // movl $0x12345678, %eax
> // ret
> EXECUTABLE_SEGMENT const std::uint8_t s_code[] =
> {
> 0xB8, 0x78, 0x56, 0x34, 0x12, 0xC3
> };

std::uint8_t s_code[] = {
    0x66, 0xB8, 0x78, 0x56, 0x34, 0x12, 0xC3

Note that it differs from yours only by the 0x66 prefix and by the fact that it
doesn't need to be const or placed in any specific section.

Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
   Software Architect - Intel DCAI Cloud Engineering

Received on 2023-04-27 15:19:14