Quantcast

clang-cl issue with MSVC's safeint.h and cast-to-self prvalue-ness

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

clang-cl issue with MSVC's safeint.h and cast-to-self prvalue-ness

Daniel Marjamäki via cfe-dev
I came across the following problem with clang-cl (in the context of
compiling LibreOffice) when using the MSVC-provided safeint.h (resp. its
safeinit_internal.h helper; on my machine located at C:\Program Files
(x86)\Windows Kits\10\Include\10.0.10240.0\ucrt\safeint_internal.h):

There is a specialization of some LargeIntRegMultiply::RegMultiply

> template < typename E > class LargeIntRegMultiply< signed __int64, signed __int64, E >
> {
> public:
>     static SafeIntError RegMultiply( const signed __int64& a, const signed __int64& b, signed __int64& ret )
>     {
>         bool aNegative = false;
>         bool bNegative = false;
>
>         unsigned __int64 tmp;
>         __int64 a1 = a;
>         __int64 b1 = b;
...
>
>         if( LargeIntRegMultiply< unsigned __int64, unsigned __int64, E >::
>             RegMultiply( (unsigned __int64)a1, (unsigned __int64)b1, (unsigned __int64)tmp ) == SafeIntNoError )
>         {
...

that calls another such specialization (namely

> template< typename E > class LargeIntRegMultiply< unsigned __int64, unsigned __int64, E >
> {
> public:
>     static SafeIntError RegMultiply( const unsigned __int64& a, const unsigned __int64& b, unsigned __int64& ret )
...

for unsigned) which takes its third argument by non-const
lvalue-reference.  But what gets passed at the call site above,

>                                                                      (unsigned __int64)tmp

is the result of needlessly casting tmp (which is already of type
unsigned __int64), which shall produce a prvalue, which in turn cannot
bind to a non-const lvalue-reference.  So compiling that with clang-cl
fails.

But with MSVC (at least 2013--2017) it succeeds.  That compiler
apparently has a bug or mis-feature so that the result of casting an
lvalue to its own type produces an lvalue instead of a prvalue.  (As
verified, at least for C-style cast and static_cast, and at least if the
type is some integral type).

Do we have some contact into the MSVC compiler group, so we can clarify
whether that behavior is considered a mis-feature (so we would want to
mimic it in some way in clang-cl, at least when compiling the
MSVC-provided safeint.h) or a bug (so MSVC would want to fix their
safeint.h, and we probably wouldn't want to duplicate that misbehavior
in clang-cl)?

(I would assume it is a genuine bug, which that sloppy
safeint_internal.h just happens to rely on by accident, as it makes the
below program behave in an IMO non-conforming way by printing 1 instead
of 0:

> #include <iostream>
> namespace {
>     int n = 0;
>     void f() { n = 1; }
>     int g(int const & n) { f(); return n; }
> }
> int main() {
>     std::cout << g(static_cast<int>(n)) << '\n';
> }

But who knows.)
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: clang-cl issue with MSVC's safeint.h and cast-to-self prvalue-ness

Daniel Marjamäki via cfe-dev
This bug appears to be fixed in the Win 10.0.10586.0 SDK:

        if( LargeIntRegMultiply< unsigned __int64, unsigned __int64, E >::
            RegMultiply( (unsigned __int64)a1, (unsigned __int64)b1, tmp ) == SafeIntNoError )

From the blog posts I see about safeint, it sounds like it's supposed to be a portable to many platforms and compilers, so I think we can rely on Microsoft to keep fixing bugs in this header.

Is there a reason LibreOffice uses the 10240 SDK?

On Fri, Apr 7, 2017 at 12:42 AM, Stephan Bergmann via cfe-dev <[hidden email]> wrote:
I came across the following problem with clang-cl (in the context of compiling LibreOffice) when using the MSVC-provided safeint.h (resp. its safeinit_internal.h helper; on my machine located at C:\Program Files (x86)\Windows Kits\10\Include\10.0.10240.0\ucrt\safeint_internal.h):

There is a specialization of some LargeIntRegMultiply::RegMultiply

template < typename E > class LargeIntRegMultiply< signed __int64, signed __int64, E >
{
public:
    static SafeIntError RegMultiply( const signed __int64& a, const signed __int64& b, signed __int64& ret )
    {
        bool aNegative = false;
        bool bNegative = false;

        unsigned __int64 tmp;
        __int64 a1 = a;
        __int64 b1 = b;
...

        if( LargeIntRegMultiply< unsigned __int64, unsigned __int64, E >::
            RegMultiply( (unsigned __int64)a1, (unsigned __int64)b1, (unsigned __int64)tmp ) == SafeIntNoError )
        {
...

that calls another such specialization (namely

template< typename E > class LargeIntRegMultiply< unsigned __int64, unsigned __int64, E >
{
public:
    static SafeIntError RegMultiply( const unsigned __int64& a, const unsigned __int64& b, unsigned __int64& ret )
...

for unsigned) which takes its third argument by non-const lvalue-reference.  But what gets passed at the call site above,

                                                                     (unsigned __int64)tmp

is the result of needlessly casting tmp (which is already of type unsigned __int64), which shall produce a prvalue, which in turn cannot bind to a non-const lvalue-reference.  So compiling that with clang-cl fails.

But with MSVC (at least 2013--2017) it succeeds.  That compiler apparently has a bug or mis-feature so that the result of casting an lvalue to its own type produces an lvalue instead of a prvalue.  (As verified, at least for C-style cast and static_cast, and at least if the type is some integral type).

Do we have some contact into the MSVC compiler group, so we can clarify whether that behavior is considered a mis-feature (so we would want to mimic it in some way in clang-cl, at least when compiling the MSVC-provided safeint.h) or a bug (so MSVC would want to fix their safeint.h, and we probably wouldn't want to duplicate that misbehavior in clang-cl)?

(I would assume it is a genuine bug, which that sloppy safeint_internal.h just happens to rely on by accident, as it makes the below program behave in an IMO non-conforming way by printing 1 instead of 0:

#include <iostream>
namespace {
    int n = 0;
    void f() { n = 1; }
    int g(int const & n) { f(); return n; }
}
int main() {
    std::cout << g(static_cast<int>(n)) << '\n';
}

But who knows.)
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev


_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: clang-cl issue with MSVC's safeint.h and cast-to-self prvalue-ness

Daniel Marjamäki via cfe-dev
On 04/07/2017 05:57 PM, Reid Kleckner wrote:

> This bug appears to be fixed in the Win 10.0.10586.0 SDK:
>
>             if( LargeIntRegMultiply< unsigned __int64, unsigned __int64,
>     E >::
>                 RegMultiply( (unsigned __int64)a1, (unsigned __int64)b1,
>     tmp ) == SafeIntNoError )
>
>
> From the blog posts I see about safeint, it sounds like it's supposed to
> be a portable to many platforms and compilers, so I think we can rely on
> Microsoft to keep fixing bugs in this header.
>
> Is there a reason LibreOffice uses the 10240 SDK?

Ah, great.  Thank you for checking with a later SDK.

There's probably no deeper reason why LibreOffice ended up using that
specific SDK version for me.  (The code we use to configure paths for
the various MSVC stuff is a bit "magic", and maybe that version was all
that happened to be available on the machine I tested with.  I'll have a
look.)
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Loading...