// Copyright (c) 2016 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Blacklisted typedefs typedef __INTMAX_TYPE__ intmax_t; typedef __UINTMAX_TYPE__ uintmax_t; typedef int intptr_t; typedef unsigned int uintptr_t; typedef __WINT_TYPE__ wint_t; typedef __SIZE_TYPE__ size_t; typedef __SIZE_TYPE__ rsize_t; typedef long ssize_t; typedef __PTRDIFF_TYPE__ ptrdiff_t; typedef unsigned int dev_t; typedef int off_t; typedef long clock_t; typedef int time_t; typedef long suseconds_t; // Other typedefs typedef int int32_t; typedef unsigned int uint32_t; typedef long int64_t; typedef unsigned long uint64_t; namespace std { template <class T> struct allocator {}; template <class T, class A = allocator<T>> struct vector {}; template <class F, class S> struct pair {}; } // namespace std namespace base { class Pickle {}; template <class T, class... Ts> struct Tuple { T value; }; } // namespace base namespace IPC { template <class... T> struct CheckedTuple { typedef base::Tuple<T...> Tuple; }; template <class T> struct ParamTraits { static void Write(base::Pickle*, const T&) {} }; template <class T> void WriteParam(base::Pickle* pickle, const T& value) { ParamTraits<T>::Write(pickle, value); } } // namespace IPC /* Test IPC::WriteParam() usage in templates. ERRORS: 6 */ struct Data { uint32_t value; size_t size; }; template <> struct IPC::ParamTraits<Data> { static void Write(base::Pickle* pickle, const Data& p) { // OK: WriteParam() called in explicit specialization WriteParam(pickle, p.value); // OK WriteParam(pickle, p.size); // ERROR } }; template <class T> struct Container { T value; }; template <class T> struct IPC::ParamTraits<Container<T>> { static void Write(base::Pickle* pickle, const Container<T>& container) { // NOT CHECKED: T is not explicitly referenced IPC::WriteParam(pickle, container.value); // NOT CHECKED WriteParam(pickle, container.value); // NOT CHECKED // NOT CHECKED: T explicitly referenced IPC::WriteParam<T>(pickle, container.value); // NOT CHECKED WriteParam<T>(pickle, container.value); // NOT CHECKED // OK: explicit cast to non-dependent allowed type WriteParam(pickle, static_cast<uint32_t>(container.value)); // OK // ERROR: explicit cast to non-dependent banned type WriteParam(pickle, static_cast<long>(container.value)); // ERROR } }; template <class T, class... Ts> struct MultiContainer { T value; }; template <class T, class... Ts> struct IPC::ParamTraits<MultiContainer<T, Ts...>> { static void Write(base::Pickle* pickle, const MultiContainer<T, Ts...>& container) { // NOT CHECKED: template argument explicitly referenced bool helper[] = { (WriteParam<Ts>(pickle, container.value), true)... // NOT CHECKED }; (void)helper; } }; template <class T> struct SomeClass { static void Write(base::Pickle* pickle) { // NOT CHECKED: WriteParam() calls on dependent types IPC::WriteParam(pickle, T(0)); // NOT CHECKED // Non-dependent types are checked IPC::WriteParam(pickle, size_t(0)); // ERROR IPC::WriteParam(pickle, uint64_t(0)); // OK } template <class U> static void WriteEx(base::Pickle* pickle) { // NOT CHECKED: WriteParam() calls on dependent types IPC::WriteParam(pickle, U(0)); // NOT CHECKED // Non-dependent types are checked IPC::WriteParam(pickle, time_t(0)); // ERROR IPC::WriteParam(pickle, uint32_t(0)); // OK } }; template <class T> void SomeWriteFunction(base::Pickle* pickle) { // NOT CHECKED: WriteParam() calls on dependent types IPC::WriteParam(pickle, T(0)); // NOT CHECKED // Non-dependent types are checked IPC::WriteParam(pickle, long(0)); // ERROR IPC::WriteParam(pickle, char(0)); // OK [&](){ IPC::WriteParam(pickle, T(0)); // NOT CHECKED IPC::WriteParam(pickle, clock_t(0)); // ERROR IPC::WriteParam(pickle, int64_t(0)); // OK }(); } void TestWriteParamInTemplates() { // These specializations call WriteParam() on various banned types, either // because they were specified directly (long) or because non-blacklisted // typedef (uint64_t) was stripped down to its underlying type, which is // blacklisted when used as is (unsigned long). // However, since it's hard (if not impossible) to check specializations // properly, we're simply not checking them. SomeClass<long>::Write(nullptr); SomeClass<long>::WriteEx<uint64_t>(nullptr); SomeWriteFunction<uint64_t>(nullptr); } /* Test IPC::CheckedTuple. ERRORS: 5 */ #define IPC_TUPLE(...) IPC::CheckedTuple<__VA_ARGS__>::Tuple #define IPC_MESSAGE_DECL(name, id, in_tuple) \ struct name ## Meta_ ## id { \ using InTuple = in_tuple; \ }; #define IPC_TEST_MESSAGE(id, in) \ IPC_MESSAGE_DECL(TestMessage, id, IPC_TUPLE in) struct Empty {}; IPC_TEST_MESSAGE(__COUNTER__, (bool, size_t, Empty, long)) // 2 ERRORs typedef std::vector<long> long1D; typedef std::vector<long1D> long2D; IPC_TEST_MESSAGE(__COUNTER__, (bool, long2D)) // ERROR IPC_TEST_MESSAGE(__COUNTER__, (char, short, std::pair<size_t, bool>)) // ERROR IPC_TEST_MESSAGE(__COUNTER__, (std::vector<std::vector<long&>&>&)) // ERROR /* Check IPC::WriteParam() arguments. ERRORS: 30 */ // ERRORS: 21 void TestWriteParamArgument() { #define CALL_WRITEPARAM(Type) \ { \ Type p; \ IPC::WriteParam(nullptr, p); \ } // ERROR: blacklisted types / typedefs CALL_WRITEPARAM(long) // ERROR CALL_WRITEPARAM(unsigned long) // ERROR CALL_WRITEPARAM(intmax_t) // ERROR CALL_WRITEPARAM(uintmax_t) // ERROR CALL_WRITEPARAM(intptr_t) // ERROR CALL_WRITEPARAM(uintptr_t) // ERROR CALL_WRITEPARAM(wint_t) // ERROR CALL_WRITEPARAM(size_t) // ERROR CALL_WRITEPARAM(rsize_t) // ERROR CALL_WRITEPARAM(ssize_t) // ERROR CALL_WRITEPARAM(ptrdiff_t) // ERROR CALL_WRITEPARAM(dev_t) // ERROR CALL_WRITEPARAM(off_t) // ERROR CALL_WRITEPARAM(clock_t) // ERROR CALL_WRITEPARAM(time_t) // ERROR CALL_WRITEPARAM(suseconds_t) // ERROR // ERROR: typedef to blacklisted typedef typedef size_t my_size; CALL_WRITEPARAM(my_size) // ERROR // ERROR: expression ends up with type "unsigned long" { uint64_t p = 0; IPC::WriteParam(nullptr, p + 1); // ERROR } // ERROR: long chain of typedefs, ends up with blacklisted typedef { typedef size_t my_size_base; typedef const my_size_base my_size; typedef my_size& my_size_ref; my_size_ref p = 0; IPC::WriteParam(nullptr, p); // ERROR } // ERROR: template specialization references blacklisted type CALL_WRITEPARAM(std::vector<long>) // ERROR CALL_WRITEPARAM(std::vector<size_t>) // ERROR // OK: typedef to blacklisted type typedef long my_long; CALL_WRITEPARAM(my_long) // OK // OK: other types / typedefs CALL_WRITEPARAM(char) // OK CALL_WRITEPARAM(int) // OK CALL_WRITEPARAM(uint32_t) // OK CALL_WRITEPARAM(int64_t) // OK // OK: long chain of typedefs, ends up with non-blacklisted typedef { typedef uint32_t my_int_base; typedef const my_int_base my_int; typedef my_int& my_int_ref; my_int_ref p = 0; IPC::WriteParam(nullptr, p); // OK } // OK: template specialization references non-blacklisted type CALL_WRITEPARAM(std::vector<char>) // OK CALL_WRITEPARAM(std::vector<my_long>) // OK #undef CALL_WRITEPARAM } struct Provider { typedef unsigned int flags; short get_short() const { return 0; } uint64_t get_uint64() const { return 0; } long get_long() const { return 0; } unsigned int get_uint() const { return 0; } flags get_flags() const { return 0; } size_t get_size() const { return 0; } const std::vector<size_t>& get_sizes() const { return sizes_data; } const std::vector<uint64_t>& get_uint64s() const { return uint64s_data; } template <class T> T get() const { return T(); } short short_data; unsigned int uint_data; flags flags_data; long long_data; size_t size_data; uint64_t uint64_data; std::vector<size_t> sizes_data; std::vector<uint64_t> uint64s_data; }; // ERRORS: 9 void TestWriteParamMemberArgument() { Provider p; IPC::WriteParam(nullptr, p.get<short>()); // OK IPC::WriteParam(nullptr, p.get_short()); // OK IPC::WriteParam(nullptr, p.short_data); // OK IPC::WriteParam(nullptr, p.get<unsigned int>()); // OK IPC::WriteParam(nullptr, p.get_uint()); // OK IPC::WriteParam(nullptr, p.uint_data); // OK IPC::WriteParam(nullptr, p.get<Provider::flags>()); // OK IPC::WriteParam(nullptr, p.get_flags()); // OK IPC::WriteParam(nullptr, p.flags_data); // OK IPC::WriteParam(nullptr, p.get<long>()); // ERROR IPC::WriteParam(nullptr, p.get_long()); // ERROR IPC::WriteParam(nullptr, p.long_data); // ERROR // This one is flaky and depends on whether size_t is typedefed to a // blacklisted type (unsigned long). //IPC::WriteParam(nullptr, p.get<size_t>()); // ERROR IPC::WriteParam(nullptr, p.get_size()); // ERROR IPC::WriteParam(nullptr, p.size_data); // ERROR // Information about uint64_t gets lost, and plugin sees WriteParam() // call on unsigned long, which is blacklisted. IPC::WriteParam(nullptr, p.get<uint64_t>()); // ERROR IPC::WriteParam(nullptr, p.get_uint64()); // OK IPC::WriteParam(nullptr, p.uint64_data); // OK // Same thing here, WriteParam() sees vector<unsigned long>, and denies it. IPC::WriteParam(nullptr, p.get<std::vector<uint64_t>>()); // ERROR IPC::WriteParam(nullptr, p.get_uint64s()); // OK IPC::WriteParam(nullptr, p.uint64s_data); // OK // This one is flaky and depends on whether size_t is typedefed to a // blacklisted type (unsigned long). //IPC::WriteParam(nullptr, p.get<std::vector<size_t>>()); IPC::WriteParam(nullptr, p.get_sizes()); // ERROR IPC::WriteParam(nullptr, p.sizes_data); // ERROR } /* ERRORS: 41 */