C++ Logo

std-discussion

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

WB

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;

https://gcc.godbolt.org/z/3eWP7866x
(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