From 20272b4ec1c1ac41cc6bd408b8c454794873d4fb Mon Sep 17 00:00:00 2001 From: Adam Simpkins Date: Fri, 1 Dec 2017 18:05:54 -0800 Subject: [PATCH] add makeSystemError*() helper functions 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 | 31 ++++++++++++++++++++++++++++--- folly/test/ExceptionTest.cpp | 29 +++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/folly/Exception.h b/folly/Exception.h index 379f269b..3985421a 100644 --- a/folly/Exception.h +++ b/folly/Exception.h @@ -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 +std::system_error makeSystemErrorExplicit(int err, Args&&... args) { + return makeSystemErrorExplicit( + err, to(std::forward(args)...).c_str()); +} + +inline std::system_error makeSystemError(const char* msg) { + return makeSystemErrorExplicit(errno, msg); +} + +template +std::system_error makeSystemError(Args&&... args) { + return makeSystemErrorExplicit(errno, std::forward(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 [[noreturn]] void throwSystemErrorExplicit(int err, Args&&... args) { - throwSystemErrorExplicit( - err, to(std::forward(args)...).c_str()); + throw makeSystemErrorExplicit(err, std::forward(args)...); } // Helper to throw std::system_error from errno and components of a string diff --git a/folly/test/ExceptionTest.cpp b/folly/test/ExceptionTest.cpp index 11623add..b378e91b 100644 --- a/folly/test/ExceptionTest.cpp +++ b/folly/test/ExceptionTest.cpp @@ -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 -- 2.34.1