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.
> 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