Date: Sat, 26 Aug 2023 23:25:38 +0100
I reply in series to Jason, Connor, Thiago and Sebastian below.
On Sat, Aug 26, 2023 at 2:55 PM Jason McKesson wrote:
>
> The thing you actually seem to be wanting is some kind of fenced code
> block that just turns off the C++ object model entirely, replacing it
> with... well, something else. Because here's the thing: the C++ object
> model is what defines what happens when you do stuff with object in
> C++. So once you turn off the C++ object model, it is entirely unclear
> how to interpret the meaning of *any* code or what its expected
> behavior ought to be.
We were getting on fine 25 years ago with C++98 before all this
'start_lifetime_as' stuff came out.
Let me try get to the point here about what the purpose of applying
the "__verbose" marker to a function is. Take the following
translation unit as an example:
extern bool SomeFunc(int);
void Func(void)
{
for ( int i = 0; i >= 0; ++i )
{
if ( SomeFunc(i) ) break;
}
SomeFunc(-1);
}
A clever compiler won't bother checking if "i >= 0", because it's
undefined behaviour for signed integers to overflow, so it would be
optimised to:
extern bool SomeFunc(int);
void Func(void)
{
for ( int i = 0; SomeFunc(i); ++i )
SomeFunc(-1);
}
But the '__verbose' marker on a function tells the compiler:
"Inside the body of this function, if you detect the potential for
undefined behaviour, don't take any liberties that you normally
wouldn't take if such potential hadn't been detected".
Basically it's telling the compiler that all undefined behaviour is
pretty much to be treated as though it were unspecified behaviour
(sort of). The '__verbose' marker also:
(1) Treats every object in the function as though it's volatile
(2) Doesn't do any caching -- in particular it doesn't cache the
vtable of any object
(3) Makes no assumptions about aliasing rules (i.e. it doesn't take a
liberty where bad aliasing would normally be UB)
On Sat, Aug 26, 2023 at 3:27 PM connor horman wrote:
>
> You didn't answer whether "everything is treated as volatile" means everything has a volatile-qualified type, or simply the optimization implications
>
> void foo(bar x){
> x.baz(); // Does this line call `void baz();` or `void baz() volatile;` given both are defined as non-static member functions of bar?
> }
It calls "void baz() volatile" if it is accessible -- otherwise it
calls "void baz()".
On Sat, Aug 26, 2023 at 6:11 PM Thiago Macieira wrote:
>
> This is a very good counter-example of allowing such a feature. Your patch job
> is extremely non-portable: it depends on the size of pointers (it wouldn't
> work on 32- bs 64-bit ABIs), it depends on how the compiler is allocating base
> sub-objects in the object (it wouldn't work with other compilers). And
> obviously depends on your hierarchy of classes, so it's not obvious how to use
> it elsewhere either.
>
> If your fix is dependent on a single compiler's behaviour, why do we care about
> making a standard change?
I know the exact binary the customers are using so I know that it's
the x64 build I made in Visual Studio 2022.
By the way you assume that the "+8" had something to do with the size
of a pointer -- whereas it might be an array of 8 char's. I didn't
bother checking because it doesn't matter.
The change I'm proposing to the Standard is a generic way of telling
the compiler not to take any liberties where potential for undefined
behaviour is detected.
On Sat, Aug 26, 2023 at 7:31 PM Sebastian Wittmeier wrote:
>
> Are IABCComHandler and IXYZComHandler compatible? Do they have the same layout, the same
> class invariants? Or at least for the usage (member function calls) of this modified pointer?
Those two classes have the same 4 functions at the beginning of their
Vtable and that's all that matters. The customer won't create an
object of type 'IABCComHandler' nor 'IXYZComHandler', so it doesn't
matter what their size and alignment is. So long as the customer only
uses the 4 functions that both classes have in common and which are
located at the start of the Vtable, it will work fine. It's tested and
working.
On Sat, Aug 26, 2023 at 7:31 PM Sebastian Wittmeier wrote:
>
> As you cannot change the binaries at the customer, you also cannot put __verbose onto the function with the dynamic_cast.
The '__verbose' is intended to be in the customer's code where they
mess with the pointer offset.
On Sat, Aug 26, 2023 at 2:55 PM Jason McKesson wrote:
>
> The thing you actually seem to be wanting is some kind of fenced code
> block that just turns off the C++ object model entirely, replacing it
> with... well, something else. Because here's the thing: the C++ object
> model is what defines what happens when you do stuff with object in
> C++. So once you turn off the C++ object model, it is entirely unclear
> how to interpret the meaning of *any* code or what its expected
> behavior ought to be.
We were getting on fine 25 years ago with C++98 before all this
'start_lifetime_as' stuff came out.
Let me try get to the point here about what the purpose of applying
the "__verbose" marker to a function is. Take the following
translation unit as an example:
extern bool SomeFunc(int);
void Func(void)
{
for ( int i = 0; i >= 0; ++i )
{
if ( SomeFunc(i) ) break;
}
SomeFunc(-1);
}
A clever compiler won't bother checking if "i >= 0", because it's
undefined behaviour for signed integers to overflow, so it would be
optimised to:
extern bool SomeFunc(int);
void Func(void)
{
for ( int i = 0; SomeFunc(i); ++i )
SomeFunc(-1);
}
But the '__verbose' marker on a function tells the compiler:
"Inside the body of this function, if you detect the potential for
undefined behaviour, don't take any liberties that you normally
wouldn't take if such potential hadn't been detected".
Basically it's telling the compiler that all undefined behaviour is
pretty much to be treated as though it were unspecified behaviour
(sort of). The '__verbose' marker also:
(1) Treats every object in the function as though it's volatile
(2) Doesn't do any caching -- in particular it doesn't cache the
vtable of any object
(3) Makes no assumptions about aliasing rules (i.e. it doesn't take a
liberty where bad aliasing would normally be UB)
On Sat, Aug 26, 2023 at 3:27 PM connor horman wrote:
>
> You didn't answer whether "everything is treated as volatile" means everything has a volatile-qualified type, or simply the optimization implications
>
> void foo(bar x){
> x.baz(); // Does this line call `void baz();` or `void baz() volatile;` given both are defined as non-static member functions of bar?
> }
It calls "void baz() volatile" if it is accessible -- otherwise it
calls "void baz()".
On Sat, Aug 26, 2023 at 6:11 PM Thiago Macieira wrote:
>
> This is a very good counter-example of allowing such a feature. Your patch job
> is extremely non-portable: it depends on the size of pointers (it wouldn't
> work on 32- bs 64-bit ABIs), it depends on how the compiler is allocating base
> sub-objects in the object (it wouldn't work with other compilers). And
> obviously depends on your hierarchy of classes, so it's not obvious how to use
> it elsewhere either.
>
> If your fix is dependent on a single compiler's behaviour, why do we care about
> making a standard change?
I know the exact binary the customers are using so I know that it's
the x64 build I made in Visual Studio 2022.
By the way you assume that the "+8" had something to do with the size
of a pointer -- whereas it might be an array of 8 char's. I didn't
bother checking because it doesn't matter.
The change I'm proposing to the Standard is a generic way of telling
the compiler not to take any liberties where potential for undefined
behaviour is detected.
On Sat, Aug 26, 2023 at 7:31 PM Sebastian Wittmeier wrote:
>
> Are IABCComHandler and IXYZComHandler compatible? Do they have the same layout, the same
> class invariants? Or at least for the usage (member function calls) of this modified pointer?
Those two classes have the same 4 functions at the beginning of their
Vtable and that's all that matters. The customer won't create an
object of type 'IABCComHandler' nor 'IXYZComHandler', so it doesn't
matter what their size and alignment is. So long as the customer only
uses the 4 functions that both classes have in common and which are
located at the start of the Vtable, it will work fine. It's tested and
working.
On Sat, Aug 26, 2023 at 7:31 PM Sebastian Wittmeier wrote:
>
> As you cannot change the binaries at the customer, you also cannot put __verbose onto the function with the dynamic_cast.
The '__verbose' is intended to be in the customer's code where they
mess with the pointer offset.
Received on 2023-08-26 22:25:47