add makeSystemError*() helper functions
authorAdam Simpkins <simpkins@fb.com>
Sat, 2 Dec 2017 02:05:54 +0000 (18:05 -0800)
committerFacebook Github Bot <facebook-github-bot@users.noreply.github.com>
Sat, 2 Dec 2017 02:22:05 +0000 (18:22 -0800)
Summary:
Add makeSystemError() helper functions that are similar to the existing
throwSystemError() functions but just return the exception rather than throwing
it.  This is helpful for callers using folly::Expected or folly::Future, where
they need to return an exception type rather than throwing it.

This also includes comments about the fact that this code is using the wrong
error category.  The C++ standard indicates that std::generic_category() for
POSIX errno values.  I am not fixing this as part of this diff, since this
change has the potential to break existing users, and would need a fair amount
of testing first.

Reviewed By: yfeldblum

Differential Revision: D6456771

fbshipit-source-id: 4724b51b8d4a7f513ae70ea1b0c4f0516cfc205f

folly/Exception.h
folly/test/ExceptionTest.cpp

index 379f269..3985421 100644 (file)
@@ -35,15 +35,40 @@ namespace folly {
 //
 // The *Explicit functions take an explicit value for errno.
 
+inline std::system_error makeSystemErrorExplicit(int err, const char* msg) {
+  // TODO: The C++ standard indicates that std::generic_category() should be
+  // used for POSIX errno codes.
+  //
+  // We should ideally change this to use std::generic_category() instead of
+  // std::system_category().  However, undertaking this change will require
+  // updating existing call sites that currently catch exceptions thrown by
+  // this code and currently expect std::system_category.
+  return std::system_error(err, std::system_category(), msg);
+}
+
+template <class... Args>
+std::system_error makeSystemErrorExplicit(int err, Args&&... args) {
+  return makeSystemErrorExplicit(
+      err, to<fbstring>(std::forward<Args>(args)...).c_str());
+}
+
+inline std::system_error makeSystemError(const char* msg) {
+  return makeSystemErrorExplicit(errno, msg);
+}
+
+template <class... Args>
+std::system_error makeSystemError(Args&&... args) {
+  return makeSystemErrorExplicit(errno, std::forward<Args>(args)...);
+}
+
 // Helper to throw std::system_error
 [[noreturn]] inline void throwSystemErrorExplicit(int err, const char* msg) {
-  throw std::system_error(err, std::system_category(), msg);
+  throw makeSystemErrorExplicit(err, msg);
 }
 
 template <class... Args>
 [[noreturn]] void throwSystemErrorExplicit(int err, Args&&... args) {
-  throwSystemErrorExplicit(
-      err, to<fbstring>(std::forward<Args>(args)...).c_str());
+  throw makeSystemErrorExplicit(err, std::forward<Args>(args)...);
 }
 
 // Helper to throw std::system_error from errno and components of a string
index 11623ad..b378e91 100644 (file)
@@ -90,5 +90,34 @@ TEST(ExceptionTest, Simple) {
                       EIO, "hello world");
 }
 
+TEST(ExceptionTest, makeSystemError) {
+  errno = ENOENT;
+  auto ex = makeSystemErrorExplicit(EDEADLK, "stuck");
+  EXPECT_EQ(EDEADLK, ex.code().value());
+  EXPECT_EQ(std::system_category(), ex.code().category());
+  EXPECT_TRUE(StringPiece{ex.what()}.contains("stuck"))
+      << "what() string missing input message: " << ex.what();
+
+  ex = makeSystemErrorExplicit(EDOM, 300, " is bigger than max=", 255);
+  EXPECT_EQ(EDOM, ex.code().value());
+  EXPECT_EQ(std::system_category(), ex.code().category());
+  EXPECT_TRUE(StringPiece{ex.what()}.contains("300 is bigger than max=255"))
+      << "what() string missing input message: " << ex.what();
+
+  errno = EINVAL;
+  ex = makeSystemError("bad argument ", 1234, ": bogus");
+  EXPECT_EQ(EINVAL, ex.code().value());
+  EXPECT_EQ(std::system_category(), ex.code().category());
+  EXPECT_TRUE(StringPiece{ex.what()}.contains("bad argument 1234: bogus"))
+      << "what() string missing input message: " << ex.what();
+
+  errno = 0;
+  ex = makeSystemError("unexpected success");
+  EXPECT_EQ(0, ex.code().value());
+  EXPECT_EQ(std::system_category(), ex.code().category());
+  EXPECT_TRUE(StringPiece{ex.what()}.contains("unexpected success"))
+      << "what() string missing input message: " << ex.what();
+}
+
 } // namespace test
 } // namespace folly