Bug 136981 - ArgumentEncoder::encode does not support std::chrono::duration on some platforms
Summary: ArgumentEncoder::encode does not support std::chrono::duration on some platforms
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: Platform (show other bugs)
Version: 528+ (Nightly build)
Hardware: PC Other
: P2 Normal
Assignee: Nobody
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-09-20 23:58 PDT by Ting-Wei Lan
Modified: 2014-10-28 21:04 PDT (History)
8 users (show)

See Also:


Attachments
A simple patch to fix the build failure (2.01 KB, patch)
2014-09-20 23:59 PDT, Ting-Wei Lan
ap: review-
Details | Formatted Diff | Diff
Cast std::chrono::duration.count() to int64_t in ArgumentCoder (1.76 KB, patch)
2014-09-22 04:11 PDT, Ting-Wei Lan
no flags Details | Formatted Diff | Diff
Cast std::chrono::duration.count() to int64_t in ArgumentCoder (2.11 KB, patch)
2014-10-21 08:08 PDT, Ting-Wei Lan
no flags Details | Formatted Diff | Diff
Cast std::chrono::duration.count() to int64_t in ArgumentCoder (2.18 KB, patch)
2014-10-28 09:59 PDT, Ting-Wei Lan
no flags Details | Formatted Diff | Diff
Cast std::chrono::duration.count() to int64_t in ArgumentCoder (2.17 KB, patch)
2014-10-28 10:48 PDT, Ting-Wei Lan
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Ting-Wei Lan 2014-09-20 23:58:41 PDT
This bug causes build failure for both webkitgtk-2.5.90 and trunk on FreeBSD 10 amd64.

In Source/WebKit2/Shared/Network/NetworkResourceLoadParameters.cpp, line 100:
encoder << maximumBufferingTime;

maximumBufferingTime is a std::chrono::milliseconds.


I found std::chrono::milliseconds is a long long in /usr/include/c++/v1/chrono.
https://llvm.org/svn/llvm-project/libcxx/trunk/include/chrono

ArgumentEncoder::encode (in Source/WebKit2/Platform/IPC/ArgumentEncoder.h) supports int32_t and int64_t. Unfortunately, neither of them are a typedef of long long (stdint.h -> sys/_types.h -> machine/_types.h -> x86/_types.h), which causes build failure because the compiler cannot find the matching function.
Here is a copy of x86/_types.h: http://svn.freebsd.org/base/head/sys/x86/include/_types.h
__LP64__ is defined, so int32_t is a int and int64_t is a long.



The following are the error message:
In file included from /home/lantw44/gnome/source/webkit-trunk/Source/WebKit2/Shared/Network/NetworkResourceLoadParameters.cpp:29:
In file included from /home/lantw44/gnome/source/webkit-trunk/Source/WebKit2/Platform/IPC/ArgumentCoders.h:29:
In file included from /home/lantw44/gnome/source/webkit-trunk/Source/WebKit2/Platform/IPC/ArgumentDecoder.h:29:
/home/lantw44/gnome/source/webkit-trunk/Source/WebKit2/Platform/IPC/ArgumentCoder.h:37:10: error: member reference base type 'const long long' is not a structure
      or union
        t.encode(encoder);
        ~^~~~~~~
/home/lantw44/gnome/source/webkit-trunk/Source/WebKit2/Platform/IPC/ArgumentEncoder.h:56:27: note: in instantiation of member function
      'IPC::ArgumentCoder<long long>::encode' requested here
        ArgumentCoder<T>::encode(*this, t);
                          ^
/home/lantw44/gnome/source/webkit-trunk/Source/WebKit2/Platform/IPC/ArgumentEncoder.h:61:9: note: in instantiation of function template specialization
      'IPC::ArgumentEncoder::encode<long long>' requested here
        encode(t);
        ^
/home/lantw44/gnome/source/webkit-trunk/Source/WebKit2/Platform/IPC/ArgumentCoders.h:110:17: note: in instantiation of function template specialization
      'IPC::ArgumentEncoder::operator<<<long long>' requested here
        encoder << duration.count();
                ^
/home/lantw44/gnome/source/webkit-trunk/Source/WebKit2/Platform/IPC/ArgumentEncoder.h:56:27: note: in instantiation of member function
      'IPC::ArgumentCoder<std::__1::chrono::duration<long long, std::__1::ratio<1, 1000> > >::encode' requested here
        ArgumentCoder<T>::encode(*this, t);
                          ^
/home/lantw44/gnome/source/webkit-trunk/Source/WebKit2/Platform/IPC/ArgumentEncoder.h:61:9: note: in instantiation of function template specialization
      'IPC::ArgumentEncoder::encode<std::__1::chrono::duration<long long, std::__1::ratio<1, 1000> > >' requested here
        encode(t);
        ^
/home/lantw44/gnome/source/webkit-trunk/Source/WebKit2/Shared/Network/NetworkResourceLoadParameters.cpp:100:13: note: in instantiation of function template
      specialization 'IPC::ArgumentEncoder::operator<<<std::__1::chrono::duration<long long, std::__1::ratio<1, 1000> > >' requested here
    encoder << maximumBufferingTime;
            ^
In file included from /home/lantw44/gnome/source/webkit-trunk/Source/WebKit2/Shared/Network/NetworkResourceLoadParameters.cpp:29:
In file included from /home/lantw44/gnome/source/webkit-trunk/Source/WebKit2/Platform/IPC/ArgumentCoders.h:29:
In file included from /home/lantw44/gnome/source/webkit-trunk/Source/WebKit2/Platform/IPC/ArgumentDecoder.h:29:
/home/lantw44/gnome/source/webkit-trunk/Source/WebKit2/Platform/IPC/ArgumentCoder.h:42:16: error: type 'long long' cannot be used prior to '::' because it has no
      members
        return T::decode(decoder, t);
               ^
/home/lantw44/gnome/source/webkit-trunk/Source/WebKit2/Platform/IPC/ArgumentDecoder.h:89:34: note: in instantiation of member function
      'IPC::ArgumentCoder<long long>::decode' requested here
        return ArgumentCoder<T>::decode(*this, t);
                                 ^
/home/lantw44/gnome/source/webkit-trunk/Source/WebKit2/Platform/IPC/ArgumentCoders.h:116:22: note: in instantiation of function template specialization
      'IPC::ArgumentDecoder::decode<long long>' requested here
        if (!decoder.decode(count))
                     ^
/home/lantw44/gnome/source/webkit-trunk/Source/WebKit2/Platform/IPC/ArgumentDecoder.h:89:34: note: in instantiation of member function
      'IPC::ArgumentCoder<std::__1::chrono::duration<long long, std::__1::ratio<1, 1000> > >::decode' requested here
        return ArgumentCoder<T>::decode(*this, t);
                                 ^
/home/lantw44/gnome/source/webkit-trunk/Source/WebKit2/Shared/Network/NetworkResourceLoadParameters.cpp:160:18: note: in instantiation of function template
      specialization 'IPC::ArgumentDecoder::decode<std::__1::chrono::duration<long long, std::__1::ratio<1, 1000> > >' requested here
    if (!decoder.decode(result.maximumBufferingTime))
                 ^
2 errors generated.
Comment 1 Ting-Wei Lan 2014-09-20 23:59:59 PDT
Created attachment 238421 [details]
A simple patch to fix the build failure
Comment 2 Alexey Proskuryakov 2014-09-21 12:18:11 PDT
Comment on attachment 238421 [details]
A simple patch to fix the build failure

This is not the right way to fix the build failure. IPC should use fixed size types.

What C++ library are you using? It seems to be buggy or obsolete, std::chrono::milliseconds is of type std::chrono::duration, not a long long.
Comment 3 Ting-Wei Lan 2014-09-21 12:25:40 PDT
(In reply to comment #2)
> (From update of attachment 238421 [details])
> This is not the right way to fix the build failure. IPC should use fixed size types.
I know it is not good to use long long directly, but there is no fixed size type which is a typedef of long long.

> 
> What C++ library are you using? It seems to be buggy or obsolete, std::chrono::milliseconds is of type std::chrono::duration, not a long long.
It should be std::chrono::duration<long long, milli>. I am sorry for the wrong information. FreeBSD 10 uses libc++ by default.
Comment 4 Alexey Proskuryakov 2014-09-21 12:56:04 PDT
There are an encoder and a decoder for duration in ArgumentCoders.h. Are they not matched by the compiler for some reason?

template<typename Rep, typename Period> struct ArgumentCoder<std::chrono::duration<Rep, Period>> {
    static void encode(ArgumentEncoder& encoder, const std::chrono::duration<Rep, Period>& duration)
    {
        encoder << duration.count();
    }

    static bool decode(ArgumentDecoder& decoder, std::chrono::duration<Rep, Period>& result)
    {
        Rep count;
        if (!decoder.decode(count))
            return false;
        result = std::chrono::duration<Rep, Period>(count);
        return true;
    }
};
Comment 5 Ting-Wei Lan 2014-09-21 19:02:11 PDT
(In reply to comment #4)
> There are an encoder and a decoder for duration in ArgumentCoders.h. Are they not matched by the compiler for some reason?
> 
> template<typename Rep, typename Period> struct ArgumentCoder<std::chrono::duration<Rep, Period>> {
>     static void encode(ArgumentEncoder& encoder, const std::chrono::duration<Rep, Period>& duration)
>     {
>         encoder << duration.count();
>     }
> 
>     static bool decode(ArgumentDecoder& decoder, std::chrono::duration<Rep, Period>& result)
>     {
>         Rep count;
>         if (!decoder.decode(count))
>             return false;
>         result = std::chrono::duration<Rep, Period>(count);
>         return true;
>     }
> };

encoder << duration.count() causes it to go back to ArgumentEncoder. duration.count() is a long long, but there is no matching ArgumentEncoder::encode function. Neither int32_t nor int64_t is a long long.
Comment 6 Alexey Proskuryakov 2014-09-21 22:42:35 PDT
Makes sense (int64_t is a long long on OS X).

In this case, the right fix is to have an explicit cast in ArgumentCoder for duration to a type that's guaranteed to be large enough.
Comment 7 Ting-Wei Lan 2014-09-22 04:11:26 PDT
Created attachment 238475 [details]
Cast std::chrono::duration.count() to int64_t in ArgumentCoder
Comment 8 Zan Dobersek 2014-09-22 05:16:23 PDT
This also occurs on Linux when compiling with Clang and libc++. On these 64-bit systems int64_t is used to define the `long` type instead of `long long`.
Comment 9 Zan Dobersek 2014-09-22 05:17:12 PDT
Comment on attachment 238475 [details]
Cast std::chrono::duration.count() to int64_t in ArgumentCoder

Marking this patch as reviewable.
Comment 10 Alexey Proskuryakov 2014-09-22 09:27:42 PDT
Comment on attachment 238475 [details]
Cast std::chrono::duration.count() to int64_t in ArgumentCoder

View in context: https://bugs.webkit.org/attachment.cgi?id=238475&action=review

> Source/WebKit2/Platform/IPC/ArgumentCoders.h:110
> +        encoder << static_cast<int64_t>(duration.count());

What guarantees that int64_t is big enough for Rep? Or that Rep is not a double?

I think that we need either a more specific coder, or a compile time assertion.

> Source/WebKit2/Platform/IPC/ArgumentCoders.h:118
> -        result = std::chrono::duration<Rep, Period>(count);
> +        result = std::chrono::duration<Rep, Period>(static_cast<Rep>(count));

Shouldn't we verify that it doesn't overflow Rep? Data sent over IPC is untrusted.
Comment 11 Ting-Wei Lan 2014-09-22 10:31:59 PDT
(In reply to comment #10)
> (From update of attachment 238475 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=238475&action=review
> 
> > Source/WebKit2/Platform/IPC/ArgumentCoders.h:110
> > +        encoder << static_cast<int64_t>(duration.count());
> 
> What guarantees that int64_t is big enough for Rep? Or that Rep is not a double?
I don't know whether int64_t is big enough, but I can make sure Rep is an integer.
The standard says: typedef duration<signed integer type of at least 45 bits, milli> milliseconds;

Do we really needs a type which is larger than int64_t to represent time? int64_t is already very large.

> 
> I think that we need either a more specific coder, or a compile time assertion.
> 
> > Source/WebKit2/Platform/IPC/ArgumentCoders.h:118
> > -        result = std::chrono::duration<Rep, Period>(count);
> > +        result = std::chrono::duration<Rep, Period>(static_cast<Rep>(count));
> 
> Shouldn't we verify that it doesn't overflow Rep? Data sent over IPC is untrusted.
If we can solve the encoder problem, I think we can just use the same type in the decoder as in the encoder.
Comment 12 Ting-Wei Lan 2014-10-20 20:44:36 PDT
Can anyone review the patch again?
Comment 13 Alexey Proskuryakov 2014-10-20 22:56:15 PDT
I thought that it still needed to be updated to address latest comments, wasn't it?
Comment 14 Zan Dobersek 2014-10-21 00:02:47 PDT
Comment on attachment 238475 [details]
Cast std::chrono::duration.count() to int64_t in ArgumentCoder

View in context: https://bugs.webkit.org/attachment.cgi?id=238475&action=review

>>> Source/WebKit2/Platform/IPC/ArgumentCoders.h:110
>>> +        encoder << static_cast<int64_t>(duration.count());
>> 
>> What guarantees that int64_t is big enough for Rep? Or that Rep is not a double?
>> 
>> I think that we need either a more specific coder, or a compile time assertion.
> 
> I don't know whether int64_t is big enough, but I can make sure Rep is an integer.
> The standard says: typedef duration<signed integer type of at least 45 bits, milli> milliseconds;
> 
> Do we really needs a type which is larger than int64_t to represent time? int64_t is already very large.

How about a static_assert here that checks that Rep is a signed 64-bit integer type? Something like:

    static_assert(std::is_integral<Rep>::value && std::is_signed<Rep>::value && sizeof(Rep) == sizeof(int64_t), "Just to be sure.");
Comment 15 Ting-Wei Lan 2014-10-21 08:08:40 PDT
Created attachment 240204 [details]
Cast std::chrono::duration.count() to int64_t in ArgumentCoder
Comment 16 Alexey Proskuryakov 2014-10-21 09:45:24 PDT
Comment on attachment 240204 [details]
Cast std::chrono::duration.count() to int64_t in ArgumentCoder

View in context: https://bugs.webkit.org/attachment.cgi?id=240204&action=review

> Source/WebKit2/Platform/IPC/ArgumentCoders.h:110
> +        static_assert(std::is_integral<Rep>::value && std::is_signed<Rep>::value && sizeof(Rep) <= sizeof(int64_t), "Rep should be an integer which can be fit in an int64_t.");

I would phrase this differently: "Serialization of this Rep type is not supported yet." With the current phrasing, someone hitting this error will not know whether it's verifying that we never try to encode something else (for some unstated subtle reason), or if it's only documenting a current limitation.

Alternatively, we could only specialize the template for supported types.
Comment 17 Ting-Wei Lan 2014-10-28 09:59:54 PDT
Created attachment 240550 [details]
Cast std::chrono::duration.count() to int64_t in ArgumentCoder
Comment 18 Ting-Wei Lan 2014-10-28 10:48:44 PDT
Created attachment 240554 [details]
Cast std::chrono::duration.count() to int64_t in ArgumentCoder
Comment 19 WebKit Commit Bot 2014-10-28 21:04:21 PDT
Comment on attachment 240554 [details]
Cast std::chrono::duration.count() to int64_t in ArgumentCoder

Clearing flags on attachment: 240554

Committed r175299: <http://trac.webkit.org/changeset/175299>
Comment 20 WebKit Commit Bot 2014-10-28 21:04:28 PDT
All reviewed patches have been landed.  Closing bug.