Prevent erroneous code like vector<fbstring>{{"this", "that"}} from compiling
authorEric Niebler <eniebler@fb.com>
Thu, 20 Oct 2016 22:20:48 +0000 (15:20 -0700)
committerFacebook Github Bot <facebook-github-bot-bot@fb.com>
Thu, 20 Oct 2016 22:23:41 +0000 (15:23 -0700)
Summary: Someone debugged a runtime crash and traced it back to code like: `vector<fbstring>{{"this", "that"}}`. Presumably the user thought they were passing an initializer list of strings to the vector constructor. Instead, they constructed a single fbstring with two char pointers pointing into //different// strings. With the appropriate fbstring constructors, we can flag this as invalid at compile-time.

Reviewed By: yfeldblum

Differential Revision: D3927397

fbshipit-source-id: a5f335073fb55bbb703a23f06874238cbdb5d91a

folly/FBString.h
folly/test/FBStringTest.cpp

index bb3d339b2f23b85ae9faf2b03b4461107c7475a7..ab0c0d8faf90e7590738d67cf41eda7fb4253e90 100644 (file)
@@ -1176,17 +1176,30 @@ public:
       InIt begin,
       InIt end,
       typename std::enable_if<
-          !std::is_same<InIt, value_type*>::value,
+          !std::is_convertible<InIt, const value_type*>::value,
           const A>::type& /*a*/ = A()) {
     assign(begin, end);
   }
 
   // Specialization for const char*, const char*
+  // Note: it's a template to keep it from being preferred when called as
+  //       basic_fbstring("hello", "world!").
+  //       See the constructor immediately below.
+  template <class = void>
   FOLLY_MALLOC_NOINLINE
   basic_fbstring(const value_type* b, const value_type* e, const A& /*a*/ = A())
       : store_(b, e - b) {
   }
 
+  // Nonstandard constructor. To make the following code fail to compile
+  // instead of silently selecting the {Iter,Iter} constructor and crashing
+  // at runtime:
+  //     std::vector<fbtring> const foo{{"this", "that"}};
+  template <std::size_t N, std::size_t M>
+  basic_fbstring(const value_type (&/*x*/)[N],
+                 const value_type (&/*y*/)[M],
+                 const A& /*a*/ = A()) = delete;
+
   // Nonstandard constructor
   basic_fbstring(value_type *s, size_type n, size_type c,
                  AcquireMallocatedString a)
index fb4a79912f044edeb303d2abbd653f07bc7cc224..4c7ba8f7565a7233c98feb40b4617000b13b7c9a 100644 (file)
@@ -1426,3 +1426,9 @@ TEST(FBStringCtorTest, NullZeroConstruction) {
   folly::fbstring f(p, n);
   EXPECT_EQ(f.size(), 0);
 }
+
+// TEST(FBStringCtorTest, BadIteratorPair) {
+//   // Should fail to compile
+//   std::vector<fbstring> vs{{"hello", "world!"}};
+//   EXPECT_EQ(vs.size(), 2u);
+// }