MPMCQueue - FPE to invalid_argument for 0 capacity
authorDaniel Pittman <dpittman@fb.com>
Tue, 31 Mar 2015 20:33:48 +0000 (13:33 -0700)
committerafrind <afrind@fb.com>
Thu, 2 Apr 2015 19:00:58 +0000 (12:00 -0700)
Summary:
If an MPMCQueue was initialized with an explicit zero capacity, it would
try to compute stride for zero and trigger SIGFPE which pretty fatally
killed the process -- but in a way that required gdb to figure out the
root cause.

This replaces that with a std::invalid_argument exception, which
includes a description of the problem and should make fixing this user
error much faster.

Test Plan:
GTEST unit test added to verify behaviour; if this didn't work it would
SIGFPE and abort the test script, which is probably a good indicator
that something went wrong. :)

fbconfig -r folly && fbmake runtests

Reviewed By: ngbronson@fb.com

Subscribers: chalfant, folly-diffs@, yfeldblum, rkomorn

FB internal diff: D1930978

Signature: t1:1930978:1427740315:cc06a8b9f3c314b956ae41f813b2f904d3e979c9

folly/MPMCQueue.h
folly/test/MPMCQueueTest.cpp

index 46048be1805a06b903150bacc0bdb7c28d520951..45c4ef74607499be45b7284a97411976b17c9034 100644 (file)
@@ -107,14 +107,21 @@ class MPMCQueue : boost::noncopyable {
 
   explicit MPMCQueue(size_t queueCapacity)
     : capacity_(queueCapacity)
-    , slots_(new detail::SingleElementQueue<T,Atom>[queueCapacity +
-                                                    2 * kSlotPadding])
-    , stride_(computeStride(queueCapacity))
     , pushTicket_(0)
     , popTicket_(0)
     , pushSpinCutoff_(0)
     , popSpinCutoff_(0)
   {
+    if (queueCapacity == 0)
+      throw std::invalid_argument(
+        "MPMCQueue with explicit capacity 0 is impossible"
+      );
+
+    // would sigfpe if capacity is 0
+    stride_ = computeStride(queueCapacity);
+    slots_ = new detail::SingleElementQueue<T,Atom>[queueCapacity +
+                                                    2 * kSlotPadding];
+
     // ideally this would be a static assert, but g++ doesn't allow it
     assert(alignof(MPMCQueue<T,Atom>)
            >= detail::CacheLocality::kFalseSharingRange);
index e6042111a6b1ec62ace1f34a296a2e9f4534545d..e606a24e9872b16883ecbe500d11052182c96108 100644 (file)
@@ -711,6 +711,11 @@ TEST(MPMCQueue, queue_moving) {
   LIFECYCLE_STEP(DESTRUCTOR);
 }
 
+TEST(MPMCQueue, explicit_zero_capacity_fail) {
+  ASSERT_THROW(MPMCQueue<int> cq(0), std::invalid_argument);
+}
+
+
 int main(int argc, char ** argv) {
   testing::InitGoogleTest(&argc, argv);
   gflags::ParseCommandLineFlags(&argc, &argv, true);