From d54b479c9911a8ce608dd4927de9dd076d760ada Mon Sep 17 00:00:00 2001 From: Marco Magdy Date: Wed, 26 Jun 2019 12:04:12 -0700 Subject: [PATCH 01/84] Handle linking to the loader's symlink Fixes https://github.com/awslabs/aws-lambda-cpp/issues/51 --- packaging/packager | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/packaging/packager b/packaging/packager index efcafcc..a02df12 100755 --- a/packaging/packager +++ b/packaging/packager @@ -115,7 +115,7 @@ do filename=$(basename "$i") if [[ -z "${filename##ld-*}" ]]; then PKG_LD=$filename # Use this file as the loader - cp "$i" $PKG_DIR/lib + cp "$i" "$PKG_DIR/lib" fi continue fi @@ -128,12 +128,23 @@ if [[ $INCLUDE_LIBC == true ]]; then do filename=$(basename "$i") if [[ -z "${filename##ld-*}" ]]; then + # if the loader is empty, then the binary is probably linked to a symlink of the loader. The symlink will + # not show up when quering the package manager for libc files. So, in this case, we want to copy the loader + if [[ -z "$PKG_LD" ]]; then + PKG_LD=$filename + cp "$i" "$PKG_DIR/lib" # we want to follow the symlink (default behavior) + fi continue # We don't want the dynamic loader's symlink because its target is an absolute path (/lib/ld-*). fi cp --no-dereference "$i" "$PKG_DIR/lib" done fi +if [[ -z "$PKG_LD" ]]; then + echo "Failed to identify, locate or package the loader. Please file an issue on Github!" 1>&2 + exit 1 +fi + bootstrap_script=$(cat < Date: Wed, 26 Jun 2019 12:17:12 -0700 Subject: [PATCH 02/84] Use grep instead of sed to test for Arch Linux pacman is more of a common name that is not unique to package managers (e.g. retro game) so check the distro is Arch Linux first before assuming pacman is a package manager --- packaging/packager | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/packager b/packaging/packager index a02df12..3fa746a 100755 --- a/packaging/packager +++ b/packaging/packager @@ -56,7 +56,7 @@ if ! type zip > /dev/null 2>&1; then exit 1 fi function package_libc_via_pacman { - if [[ $(sed '/ID_LIKE/!d;s/ID_LIKE=//' < /etc/os-release) == "archlinux" ]]; then + if grep "Arch Linux" < /etc/os-release > /dev/null 2>&1; then if type pacman > /dev/null 2>&1; then pacman --files --list --quiet glibc | sed -E '/\.so$|\.so\.[0-9]+$/!d' fi From 43689287a5289b90c3639e972fb9f276e2e20830 Mon Sep 17 00:00:00 2001 From: Marco Magdy Date: Thu, 25 Jul 2019 23:29:03 +0000 Subject: [PATCH 03/84] Use --query instead of --files in pacman --query yields absolute paths to the package files while --files yields relative paths. --- packaging/packager | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/packager b/packaging/packager index 3fa746a..32b2db0 100755 --- a/packaging/packager +++ b/packaging/packager @@ -58,7 +58,7 @@ fi function package_libc_via_pacman { if grep "Arch Linux" < /etc/os-release > /dev/null 2>&1; then if type pacman > /dev/null 2>&1; then - pacman --files --list --quiet glibc | sed -E '/\.so$|\.so\.[0-9]+$/!d' + pacman --query --list --quiet glibc | sed -E '/\.so$|\.so\.[0-9]+$/!d' fi fi } From fc9f7856335c2cc43fd053235267260819275f4e Mon Sep 17 00:00:00 2001 From: Jake Stoeffler Date: Fri, 2 Aug 2019 22:07:35 -0500 Subject: [PATCH 04/84] Fix dynamodb example README --- examples/dynamodb/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/dynamodb/README.md b/examples/dynamodb/README.md index 24167c5..db84fd8 100644 --- a/examples/dynamodb/README.md +++ b/examples/dynamodb/README.md @@ -13,7 +13,7 @@ $ git clone https://github.com/aws/aws-sdk-cpp.git $ cd aws-sdk-cpp $ mkdir build $ cd build -$ cmake .. -DBUILD_ONLY="s3" \ +$ cmake .. -DBUILD_ONLY="dynamodb" \ -DCMAKE_BUILD_TYPE=Release \ -DBUILD_SHARED_LIBS=OFF \ -DENABLE_UNITY_BUILD=ON \ From 681652d9410bb4adb66e5afa9e8a3662a5f7b606 Mon Sep 17 00:00:00 2001 From: Marco Magdy Date: Fri, 9 Aug 2019 20:33:12 +0000 Subject: [PATCH 05/84] Update the version of project to match the release --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a83a8b8..9e600ac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.5) set(CMAKE_CXX_STANDARD 11) project(aws-lambda-runtime - VERSION 0.2.3 + VERSION 0.2.4 LANGUAGES CXX) option(ENABLE_TESTS "Enables building the test project, requires AWS C++ SDK." OFF) From 66b5af9b1fe6b792ec92ad495299ba25ee289410 Mon Sep 17 00:00:00 2001 From: Bryan Moffatt Date: Tue, 27 Aug 2019 04:30:18 +0100 Subject: [PATCH 06/84] Move runtime class to runtime.h (#55) Enables integration with other runtimes. --- CMakeLists.txt | 8 +++++- include/aws/lambda-runtime/runtime.h | 43 ++++++++++++++++++++++++++++ src/runtime.cpp | 39 ------------------------- 3 files changed, 50 insertions(+), 40 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9e600ac..4f98a45 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,7 +82,13 @@ configure_file( NEWLINE_STYLE LF) # installation -install(FILES "include/aws/lambda-runtime/runtime.h" "include/aws/lambda-runtime/version.h" +install(FILES "include/aws/http/response.h" + DESTINATION "include/aws/http") + +install(FILES + "include/aws/lambda-runtime/runtime.h" + "include/aws/lambda-runtime/version.h" + "include/aws/lambda-runtime/outcome.h" DESTINATION "include/aws/lambda-runtime") install(FILES "include/aws/logging/logging.h" diff --git a/include/aws/lambda-runtime/runtime.h b/include/aws/lambda-runtime/runtime.h index d73c2e8..e14b804 100644 --- a/include/aws/lambda-runtime/runtime.h +++ b/include/aws/lambda-runtime/runtime.h @@ -14,9 +14,13 @@ * permissions and limitations under the License. */ +#include #include #include #include +#include +#include "aws/lambda-runtime/outcome.h" +#include "aws/http/response.h" namespace aws { namespace lambda_runtime { @@ -115,6 +119,45 @@ class invocation_response { bool is_success() const { return m_success; } }; +struct no_result { +}; + +class runtime { +public: + using next_outcome = aws::lambda_runtime::outcome; + using post_outcome = aws::lambda_runtime::outcome; + + runtime(std::string const& endpoint); + ~runtime(); + + /** + * Ask lambda for an invocation. + */ + next_outcome get_next(); + + /** + * Tells lambda that the function has succeeded. + */ + post_outcome post_success(std::string const& request_id, invocation_response const& handler_response); + + /** + * Tells lambda that the function has failed. + */ + post_outcome post_failure(std::string const& request_id, invocation_response const& handler_response); + +private: + void set_curl_next_options(); + void set_curl_post_result_options(); + post_outcome do_post( + std::string const& url, + std::string const& request_id, + invocation_response const& handler_response); + +private: + std::array const m_endpoints; + CURL* const m_curl_handle; +}; + inline std::chrono::milliseconds invocation_request::get_time_remaining() const { using namespace std::chrono; diff --git a/src/runtime.cpp b/src/runtime.cpp index 0af68b2..6a4b5cf 100644 --- a/src/runtime.cpp +++ b/src/runtime.cpp @@ -145,45 +145,6 @@ static int rt_curl_debug_callback(CURL* handle, curl_infotype type, char* data, } #endif -struct no_result { -}; - -class runtime { -public: - using next_outcome = aws::lambda_runtime::outcome; - using post_outcome = aws::lambda_runtime::outcome; - - runtime(std::string const& endpoint); - ~runtime(); - - /** - * Ask lambda for an invocation. - */ - next_outcome get_next(); - - /** - * Tells lambda that the function has succeeded. - */ - post_outcome post_success(std::string const& request_id, invocation_response const& handler_response); - - /** - * Tells lambda that the function has failed. - */ - post_outcome post_failure(std::string const& request_id, invocation_response const& handler_response); - -private: - void set_curl_next_options(); - void set_curl_post_result_options(); - post_outcome do_post( - std::string const& url, - std::string const& request_id, - invocation_response const& handler_response); - -private: - std::array const m_endpoints; - CURL* const m_curl_handle; -}; - runtime::runtime(std::string const& endpoint) : m_endpoints{{endpoint + "/2018-06-01/runtime/init/error", endpoint + "/2018-06-01/runtime/invocation/next", From 14abc9ef2fcf64b3c9bf330d2d05cb5a92261951 Mon Sep 17 00:00:00 2001 From: Marco Magdy Date: Tue, 27 Aug 2019 03:23:51 +0000 Subject: [PATCH 07/84] add compile_commands.json to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 1f476fc..0270914 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ build tags TODO +compile_commands.json From f927cd0de7e5c888c29415e04f2921669a6d2680 Mon Sep 17 00:00:00 2001 From: Marco Magdy Date: Tue, 27 Aug 2019 04:24:48 +0000 Subject: [PATCH 08/84] Fix format specifier to work with libc++ Fixes https://github.com/awslabs/aws-lambda-cpp/issues/56 --- src/runtime.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/runtime.cpp b/src/runtime.cpp index 6a4b5cf..055028e 100644 --- a/src/runtime.cpp +++ b/src/runtime.cpp @@ -26,6 +26,7 @@ #include #include #include // for strtoul +#include #define AWS_LAMBDA_RUNTIME_API __attribute__((visibility("default"))) @@ -277,9 +278,9 @@ runtime::next_outcome runtime::get_next() req.deadline += std::chrono::milliseconds(ms); logging::log_info( LOG_TAG, - "Received payload: %s\nTime remaining: %ld", + "Received payload: %s\nTime remaining: %" PRId64, req.payload.c_str(), - req.get_time_remaining().count()); + static_cast(req.get_time_remaining().count())); } return next_outcome(req); } From 1c884fe4392b2d73947d6d6dc8da6a4b146e412b Mon Sep 17 00:00:00 2001 From: Marco Magdy Date: Tue, 27 Aug 2019 04:25:20 +0000 Subject: [PATCH 09/84] Add version information to initialization logs --- src/runtime.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime.cpp b/src/runtime.cpp index 055028e..134c219 100644 --- a/src/runtime.cpp +++ b/src/runtime.cpp @@ -375,7 +375,7 @@ static bool handle_post_outcome(runtime::post_outcome const& o, std::string cons AWS_LAMBDA_RUNTIME_API void run_handler(std::function const& handler) { - logging::log_info(LOG_TAG, "Initializing the C++ Lambda Runtime."); + logging::log_info(LOG_TAG, "Initializing the C++ Lambda Runtime version %s", aws::lambda_runtime::get_version()); std::string endpoint("http://"); if (auto ep = std::getenv("AWS_LAMBDA_RUNTIME_API")) { assert(ep); From 38e2b138adffdd4d1aa1c0a60d6825aa78049e5f Mon Sep 17 00:00:00 2001 From: Bryan Moffatt Date: Thu, 28 Nov 2019 18:22:00 +0000 Subject: [PATCH 10/84] disable use of an http proxy --- src/runtime.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/runtime.cpp b/src/runtime.cpp index 134c219..7f785d0 100644 --- a/src/runtime.cpp +++ b/src/runtime.cpp @@ -179,6 +179,8 @@ void runtime::set_curl_next_options() curl_easy_setopt(m_curl_handle, CURLOPT_WRITEFUNCTION, write_data); curl_easy_setopt(m_curl_handle, CURLOPT_HEADERFUNCTION, write_header); + curl_easy_setopt(m_curl_handle, CURLOPT_PROXY, ""); + #ifndef NDEBUG curl_easy_setopt(m_curl_handle, CURLOPT_VERBOSE, 1); curl_easy_setopt(m_curl_handle, CURLOPT_DEBUGFUNCTION, rt_curl_debug_callback); @@ -199,6 +201,8 @@ void runtime::set_curl_post_result_options() curl_easy_setopt(m_curl_handle, CURLOPT_WRITEFUNCTION, write_data); curl_easy_setopt(m_curl_handle, CURLOPT_HEADERFUNCTION, write_header); + curl_easy_setopt(m_curl_handle, CURLOPT_PROXY, ""); + #ifndef NDEBUG curl_easy_setopt(m_curl_handle, CURLOPT_VERBOSE, 1); curl_easy_setopt(m_curl_handle, CURLOPT_DEBUGFUNCTION, rt_curl_debug_callback); From 910128f576cf13f337650334cc8612891c1f7698 Mon Sep 17 00:00:00 2001 From: Bryan Moffatt Date: Mon, 2 Dec 2019 19:10:01 +0000 Subject: [PATCH 11/84] add arbitrary payload constructor for invocation_response (#66) invocation_response::failure doesn't allow for arbitrary payloads. To support clients that need to control the entire error response body (ex: adding a stack trace), i've added a new constructor. We couldn't add an overload to 'failure' because the parameter types would be the same as the existing one. --- include/aws/lambda-runtime/runtime.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/aws/lambda-runtime/runtime.h b/include/aws/lambda-runtime/runtime.h index e14b804..0a62c2a 100644 --- a/include/aws/lambda-runtime/runtime.h +++ b/include/aws/lambda-runtime/runtime.h @@ -92,6 +92,11 @@ class invocation_response { invocation_response() = default; public: + invocation_response(std::string const& payload, std::string const& content_type, bool success) + : m_payload(payload), m_content_type(content_type), m_success(success) + { + } + /** * Create a successful invocation response with the given payload and content-type. */ From a31cc25324f9c97507417ff0ad1218117ca2ec11 Mon Sep 17 00:00:00 2001 From: Marco Magdy Date: Mon, 2 Dec 2019 12:10:31 -0800 Subject: [PATCH 12/84] Add a description for the new constructor Signed-off-by: Marco Magdy --- include/aws/lambda-runtime/runtime.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/aws/lambda-runtime/runtime.h b/include/aws/lambda-runtime/runtime.h index 0a62c2a..0dc292c 100644 --- a/include/aws/lambda-runtime/runtime.h +++ b/include/aws/lambda-runtime/runtime.h @@ -92,6 +92,11 @@ class invocation_response { invocation_response() = default; public: + // Create a success or failure response. Typically, you should use the static functions invocation_response::success + // and invocation_response::failure, however, invocation_response::failure doesn't allow for arbitrary payloads. + // To support clients that need to control the entire error response body (e.g. adding a stack trace), this + // constructor should be used instead. + // Note: adding an overload to invocation_response::failure is not feasible since the parameter types are the same. invocation_response(std::string const& payload, std::string const& content_type, bool success) : m_payload(payload), m_content_type(content_type), m_success(success) { From 4e820f924616816f50ccfb197a9fc6a6888c5c90 Mon Sep 17 00:00:00 2001 From: Marco Magdy Date: Tue, 3 Dec 2019 08:03:18 -0800 Subject: [PATCH 13/84] Apply warnings/suggestions reported by clang-tidy v9 (#67) Clang-tidy version 9 reported a few warnings, and since we treat errors as warnings we better address them. I've disabled the trailing-return-type suggestion because I believe it's ridiculous. Signed-off-by: Marco Magdy --- .clang-tidy | 6 ++-- .gitignore | 1 + include/aws/lambda-runtime/outcome.h | 3 +- src/logging.cpp | 10 +++--- src/runtime.cpp | 54 +++++++++++++++++++--------- 5 files changed, 50 insertions(+), 24 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 8b4d3ae..0dd63c2 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,5 +1,6 @@ --- -Checks: 'clang-diagnostic-*,clang-analyzer-*,performance-*,readability-*,modernize-*,bugprone-*,misc-*' +Checks: +'clang-diagnostic-*,clang-analyzer-*,performance-*,readability-*,modernize-*,bugprone-*,misc-*,-modernize-use-trailing-return-type' WarningsAsErrors: '*' HeaderFilterRegex: '' FormatStyle: 'none' @@ -10,6 +11,7 @@ CheckOptions: value: '1' - key: readability-implicit-bool-conversion.AllowIntegerConditions value: '1' - + - key: misc-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic + value: '1' ... diff --git a/.gitignore b/.gitignore index 0270914..647f449 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ build tags TODO compile_commands.json +.clangd diff --git a/include/aws/lambda-runtime/outcome.h b/include/aws/lambda-runtime/outcome.h index 5d0af4a..ac3c9f1 100644 --- a/include/aws/lambda-runtime/outcome.h +++ b/include/aws/lambda-runtime/outcome.h @@ -15,6 +15,7 @@ */ #include +#include namespace aws { namespace lambda_runtime { @@ -26,7 +27,7 @@ class outcome { outcome(TFailure const& f) : f(f), success(false) {} - outcome(outcome&& other) : success(other.success) + outcome(outcome&& other) noexcept : success(other.success) { if (success) { s = std::move(other.s); diff --git a/src/logging.cpp b/src/logging.cpp index b01a4a2..e68aafa 100644 --- a/src/logging.cpp +++ b/src/logging.cpp @@ -13,6 +13,7 @@ * permissions and limitations under the License. */ #include "aws/logging/logging.h" +#include #include #include @@ -46,9 +47,10 @@ void log(verbosity v, char const* tag, char const* msg, va_list args) va_end(copy); return; } - char buf[512]; - char* out = buf; - if (sz >= static_cast(sizeof(buf))) { + constexpr int max_stack_buffer_size = 512; + std::array buf; + char* out = buf.data(); + if (sz >= max_stack_buffer_size) { out = new char[sz]; } @@ -60,7 +62,7 @@ void log(verbosity v, char const* tag, char const* msg, va_list args) // stdout is not line-buffered when redirected (for example to a file or to another process) so we must flush it // manually. fflush(stdout); - if (out != buf) { + if (out != buf.data()) { delete[] out; } } diff --git a/src/runtime.cpp b/src/runtime.cpp index 7f785d0..9dba310 100644 --- a/src/runtime.cpp +++ b/src/runtime.cpp @@ -33,13 +33,13 @@ namespace aws { namespace lambda_runtime { -static char const LOG_TAG[] = "LAMBDA_RUNTIME"; -static char const REQUEST_ID_HEADER[] = "lambda-runtime-aws-request-id"; -static char const TRACE_ID_HEADER[] = "lambda-runtime-trace-id"; -static char const CLIENT_CONTEXT_HEADER[] = "lambda-runtime-client-context"; -static char const COGNITO_IDENTITY_HEADER[] = "lambda-runtime-cognito-identity"; -static char const DEADLINE_MS_HEADER[] = "lambda-runtime-deadline-ms"; -static char const FUNCTION_ARN_HEADER[] = "lambda-runtime-invoked-function-arn"; +static constexpr auto LOG_TAG = "LAMBDA_RUNTIME"; +static constexpr auto REQUEST_ID_HEADER = "lambda-runtime-aws-request-id"; +static constexpr auto TRACE_ID_HEADER = "lambda-runtime-trace-id"; +static constexpr auto CLIENT_CONTEXT_HEADER = "lambda-runtime-client-context"; +static constexpr auto COGNITO_IDENTITY_HEADER = "lambda-runtime-cognito-identity"; +static constexpr auto DEADLINE_MS_HEADER = "lambda-runtime-deadline-ms"; +static constexpr auto FUNCTION_ARN_HEADER = "lambda-runtime-invoked-function-arn"; enum Endpoints { INIT, @@ -49,8 +49,10 @@ enum Endpoints { static bool is_success(aws::http::response_code httpcode) { + constexpr auto http_first_success_error_code = 200; + constexpr auto http_last_success_error_code = 299; auto const code = static_cast(httpcode); - return code >= 200 && code <= 299; + return code >= http_first_success_error_code && code <= http_last_success_error_code; } static size_t write_data(char* ptr, size_t size, size_t nmemb, void* userdata) @@ -67,13 +69,28 @@ static size_t write_data(char* ptr, size_t size, size_t nmemb, void* userdata) return nmemb; } +// std::isspace has a few edge cases that would trigger UB. In particular, the documentation says: +// "The behavior is undefined if the value of the input is not representable as unsigned char and is not equal to EOF." +// So, this function does the simple obvious thing instead. static inline bool IsSpace(int ch) { - if (ch < -1 || ch > 255) { - return false; + constexpr int space = 0x20; // space (0x20, ' ') + constexpr int form_feed = 0x0c; // form feed (0x0c, '\f') + constexpr int line_feed = 0x0a; // line feed (0x0a, '\n') + constexpr int carriage_return = 0x0d; // carriage return (0x0d, '\r') + constexpr int horizontal_tab = 0x09; // horizontal tab (0x09, '\t') + constexpr int vertical_tab = 0x0b; // vertical tab (0x0b, '\v') + switch (ch) { + case space: + case form_feed: + case line_feed: + case carriage_return: + case horizontal_tab: + case vertical_tab: + return true; + default: + return false; } - - return ::isspace(ch) != 0; } static inline std::string trim(std::string s) @@ -276,7 +293,8 @@ runtime::next_outcome runtime::get_next() if (resp.has_header(DEADLINE_MS_HEADER)) { auto const& deadline_string = resp.get_header(DEADLINE_MS_HEADER); - unsigned long ms = strtoul(deadline_string.c_str(), nullptr, 10); + constexpr int base = 10; + unsigned long ms = strtoul(deadline_string.c_str(), nullptr, base); assert(ms > 0); assert(ms < ULONG_MAX); req.deadline += std::chrono::milliseconds(ms); @@ -437,10 +455,11 @@ void run_handler(std::function c static std::string json_escape(std::string const& in) { + constexpr char last_non_printable_character = 31; std::string out; out.reserve(in.length()); // most strings will end up identical for (char ch : in) { - if (ch > 31 && ch != '\"' && ch != '\\') { + if (ch > last_non_printable_character && ch != '\"' && ch != '\\') { out.append(1, ch); } else { @@ -469,9 +488,10 @@ static std::string json_escape(std::string const& in) break; default: // escape and print as unicode codepoint - char buf[6]; // 4 hex + letter 'u' + \0 - sprintf(buf, "u%04x", ch); - out.append(buf, 5); // add only five, discarding the null terminator. + constexpr int printed_unicode_length = 6; // 4 hex + letter 'u' + \0 + std::array buf; + sprintf(buf.data(), "u%04x", ch); + out.append(buf.data(), buf.size() - 1); // add only five, discarding the null terminator. break; } } From b81d49082f1c99e035fb3c80f1ac2f6515a4463b Mon Sep 17 00:00:00 2001 From: Marco Magdy Date: Tue, 3 Dec 2019 10:32:19 -0800 Subject: [PATCH 14/84] A few CMake improvements (#68) - Set the SONAME on the library to generate correct symlinks - Set visibility of inline functions to hidden (didn't use CMake since this library is linux only) - Use the built-in LTO detection mechanism instead of rolling my own --- CMakeLists.txt | 47 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f98a45..0521987 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.9) set(CMAKE_CXX_STANDARD 11) project(aws-lambda-runtime VERSION 0.2.4 @@ -6,9 +6,7 @@ project(aws-lambda-runtime option(ENABLE_TESTS "Enables building the test project, requires AWS C++ SDK." OFF) -include(CheckCXXCompilerFlag) - -check_cxx_compiler_flag("-Wl,-flto" LTO_CAPABLE) +include(CheckIPOSupported) add_library(${PROJECT_NAME} "src/logging.cpp" @@ -17,12 +15,21 @@ add_library(${PROJECT_NAME} "${CMAKE_CURRENT_BINARY_DIR}/version.cpp" ) -set_target_properties(${PROJECT_NAME} PROPERTIES VERSION ${PROJECT_VERSION}) +set_target_properties(${PROJECT_NAME} PROPERTIES + SOVERSION 0 + VERSION ${PROJECT_VERSION}) target_include_directories(${PROJECT_NAME} PUBLIC $ $) +check_ipo_supported(RESULT has_lto OUTPUT lto_check_output) +if(has_lto) + set_property(TARGET ${PROJECT_NAME} PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE) +else() + message(WARNING "Link-time optimization (LTO) is not supported: ${lto_check_output}") +endif() + find_package(CURL REQUIRED) if (CMAKE_VERSION VERSION_LESS 3.12) target_link_libraries(${PROJECT_NAME} PRIVATE ${CURL_LIBRARIES}) @@ -36,6 +43,7 @@ target_compile_options(${PROJECT_NAME} PRIVATE "-fno-exceptions" "-fno-rtti" "-fvisibility=hidden" + "-fvisibility-inlines-hidden" "-Wall" "-Wextra" "-Werror" @@ -64,11 +72,6 @@ else () target_compile_definitions(${PROJECT_NAME} PRIVATE "AWS_LAMBDA_LOG=0") endif() -if ((BUILD_SHARED_LIBS) AND (LTO_CAPABLE)) - target_compile_options(${PROJECT_NAME} PRIVATE "-flto") - target_link_libraries(${PROJECT_NAME} PRIVATE "-flto") -endif() - #tests if (ENABLE_TESTS) enable_testing() @@ -81,24 +84,37 @@ configure_file( "${CMAKE_CURRENT_BINARY_DIR}/version.cpp" NEWLINE_STYLE LF) +include (CMakePackageConfigHelpers) + +write_basic_package_version_file("${PROJECT_NAME}-config-version.cmake" + VERSION ${PROJECT_VERSION} + COMPATIBILITY SameMajorVersion) + # installation install(FILES "include/aws/http/response.h" DESTINATION "include/aws/http") -install(FILES +install(FILES "include/aws/lambda-runtime/runtime.h" "include/aws/lambda-runtime/version.h" "include/aws/lambda-runtime/outcome.h" - DESTINATION "include/aws/lambda-runtime") + DESTINATION "include/aws/lambda-runtime" + COMPONENT ${PROJECT_NAME}-Development) install(FILES "include/aws/logging/logging.h" DESTINATION "include/aws/logging") +include(GNUInstallDirs) install(TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME}-targets - ARCHIVE DESTINATION lib - LIBRARY DESTINATION lib - RUNTIME DESTINATION bin) + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + COMPONENT ${PROJECT_NAME}-Development + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + COMPONENT ${PROJECT_NAME}-Runtime + NAMELINK_COMPONENT ${PROJECT_NAME}-Developemnt + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + COMPONENT ${PROJECT_NAME}-Runtime + ) configure_file("${CMAKE_SOURCE_DIR}/cmake/${PROJECT_NAME}-config.cmake" "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake" @@ -111,6 +127,7 @@ install(EXPORT "${PROJECT_NAME}-targets" NAMESPACE AWS::) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake" + ${PROJECT_NAME}-config-version.cmake DESTINATION "lib/${PROJECT_NAME}/cmake/") install(PROGRAMS "${CMAKE_SOURCE_DIR}/packaging/packager" From 25b19204236057ff3f63a21618341b5b27ff6840 Mon Sep 17 00:00:00 2001 From: Marco Magdy Date: Tue, 3 Dec 2019 10:49:11 -0800 Subject: [PATCH 15/84] Revert "A few CMake improvements (#68)" This reverts commit b81d49082f1c99e035fb3c80f1ac2f6515a4463b. --- CMakeLists.txt | 47 +++++++++++++++-------------------------------- 1 file changed, 15 insertions(+), 32 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0521987..4f98a45 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.9) +cmake_minimum_required(VERSION 3.5) set(CMAKE_CXX_STANDARD 11) project(aws-lambda-runtime VERSION 0.2.4 @@ -6,7 +6,9 @@ project(aws-lambda-runtime option(ENABLE_TESTS "Enables building the test project, requires AWS C++ SDK." OFF) -include(CheckIPOSupported) +include(CheckCXXCompilerFlag) + +check_cxx_compiler_flag("-Wl,-flto" LTO_CAPABLE) add_library(${PROJECT_NAME} "src/logging.cpp" @@ -15,21 +17,12 @@ add_library(${PROJECT_NAME} "${CMAKE_CURRENT_BINARY_DIR}/version.cpp" ) -set_target_properties(${PROJECT_NAME} PROPERTIES - SOVERSION 0 - VERSION ${PROJECT_VERSION}) +set_target_properties(${PROJECT_NAME} PROPERTIES VERSION ${PROJECT_VERSION}) target_include_directories(${PROJECT_NAME} PUBLIC $ $) -check_ipo_supported(RESULT has_lto OUTPUT lto_check_output) -if(has_lto) - set_property(TARGET ${PROJECT_NAME} PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE) -else() - message(WARNING "Link-time optimization (LTO) is not supported: ${lto_check_output}") -endif() - find_package(CURL REQUIRED) if (CMAKE_VERSION VERSION_LESS 3.12) target_link_libraries(${PROJECT_NAME} PRIVATE ${CURL_LIBRARIES}) @@ -43,7 +36,6 @@ target_compile_options(${PROJECT_NAME} PRIVATE "-fno-exceptions" "-fno-rtti" "-fvisibility=hidden" - "-fvisibility-inlines-hidden" "-Wall" "-Wextra" "-Werror" @@ -72,6 +64,11 @@ else () target_compile_definitions(${PROJECT_NAME} PRIVATE "AWS_LAMBDA_LOG=0") endif() +if ((BUILD_SHARED_LIBS) AND (LTO_CAPABLE)) + target_compile_options(${PROJECT_NAME} PRIVATE "-flto") + target_link_libraries(${PROJECT_NAME} PRIVATE "-flto") +endif() + #tests if (ENABLE_TESTS) enable_testing() @@ -84,37 +81,24 @@ configure_file( "${CMAKE_CURRENT_BINARY_DIR}/version.cpp" NEWLINE_STYLE LF) -include (CMakePackageConfigHelpers) - -write_basic_package_version_file("${PROJECT_NAME}-config-version.cmake" - VERSION ${PROJECT_VERSION} - COMPATIBILITY SameMajorVersion) - # installation install(FILES "include/aws/http/response.h" DESTINATION "include/aws/http") -install(FILES +install(FILES "include/aws/lambda-runtime/runtime.h" "include/aws/lambda-runtime/version.h" "include/aws/lambda-runtime/outcome.h" - DESTINATION "include/aws/lambda-runtime" - COMPONENT ${PROJECT_NAME}-Development) + DESTINATION "include/aws/lambda-runtime") install(FILES "include/aws/logging/logging.h" DESTINATION "include/aws/logging") -include(GNUInstallDirs) install(TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME}-targets - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - COMPONENT ${PROJECT_NAME}-Development - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - COMPONENT ${PROJECT_NAME}-Runtime - NAMELINK_COMPONENT ${PROJECT_NAME}-Developemnt - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - COMPONENT ${PROJECT_NAME}-Runtime - ) + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + RUNTIME DESTINATION bin) configure_file("${CMAKE_SOURCE_DIR}/cmake/${PROJECT_NAME}-config.cmake" "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake" @@ -127,7 +111,6 @@ install(EXPORT "${PROJECT_NAME}-targets" NAMESPACE AWS::) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake" - ${PROJECT_NAME}-config-version.cmake DESTINATION "lib/${PROJECT_NAME}/cmake/") install(PROGRAMS "${CMAKE_SOURCE_DIR}/packaging/packager" From a9e34da599d4ecc89dcc4590720c79a54fbba903 Mon Sep 17 00:00:00 2001 From: Marco Magdy Date: Tue, 3 Dec 2019 11:07:00 -0800 Subject: [PATCH 16/84] A few CMake improvements (see below) - Set the SONAME on the library to generate correct symlinks - Set visibility of inline functions to hidden (didn't use CMake since this library is linux only) - Use the built-in LTO detection mechanism instead of rolling my own Signed-off-by: Marco Magdy --- CMakeLists.txt | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f98a45..d704b89 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.9) set(CMAKE_CXX_STANDARD 11) project(aws-lambda-runtime VERSION 0.2.4 @@ -6,9 +6,7 @@ project(aws-lambda-runtime option(ENABLE_TESTS "Enables building the test project, requires AWS C++ SDK." OFF) -include(CheckCXXCompilerFlag) - -check_cxx_compiler_flag("-Wl,-flto" LTO_CAPABLE) +include(CheckIPOSupported) add_library(${PROJECT_NAME} "src/logging.cpp" @@ -17,12 +15,21 @@ add_library(${PROJECT_NAME} "${CMAKE_CURRENT_BINARY_DIR}/version.cpp" ) -set_target_properties(${PROJECT_NAME} PROPERTIES VERSION ${PROJECT_VERSION}) +set_target_properties(${PROJECT_NAME} PROPERTIES + SOVERSION 0 + VERSION ${PROJECT_VERSION}) target_include_directories(${PROJECT_NAME} PUBLIC $ $) +check_ipo_supported(RESULT has_lto OUTPUT lto_check_output) +if(has_lto) + set_property(TARGET ${PROJECT_NAME} PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE) +else() + message(WARNING "Link-time optimization (LTO) is not supported: ${lto_check_output}") +endif() + find_package(CURL REQUIRED) if (CMAKE_VERSION VERSION_LESS 3.12) target_link_libraries(${PROJECT_NAME} PRIVATE ${CURL_LIBRARIES}) @@ -36,6 +43,7 @@ target_compile_options(${PROJECT_NAME} PRIVATE "-fno-exceptions" "-fno-rtti" "-fvisibility=hidden" + "-fvisibility-inlines-hidden" "-Wall" "-Wextra" "-Werror" @@ -64,11 +72,6 @@ else () target_compile_definitions(${PROJECT_NAME} PRIVATE "AWS_LAMBDA_LOG=0") endif() -if ((BUILD_SHARED_LIBS) AND (LTO_CAPABLE)) - target_compile_options(${PROJECT_NAME} PRIVATE "-flto") - target_link_libraries(${PROJECT_NAME} PRIVATE "-flto") -endif() - #tests if (ENABLE_TESTS) enable_testing() @@ -81,6 +84,12 @@ configure_file( "${CMAKE_CURRENT_BINARY_DIR}/version.cpp" NEWLINE_STYLE LF) +include (CMakePackageConfigHelpers) + +write_basic_package_version_file("${PROJECT_NAME}-config-version.cmake" + VERSION ${PROJECT_VERSION} + COMPATIBILITY SameMajorVersion) + # installation install(FILES "include/aws/http/response.h" DESTINATION "include/aws/http") @@ -94,11 +103,13 @@ install(FILES install(FILES "include/aws/logging/logging.h" DESTINATION "include/aws/logging") +include(GNUInstallDirs) install(TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME}-targets - ARCHIVE DESTINATION lib - LIBRARY DESTINATION lib - RUNTIME DESTINATION bin) + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + ) configure_file("${CMAKE_SOURCE_DIR}/cmake/${PROJECT_NAME}-config.cmake" "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake" @@ -111,6 +122,7 @@ install(EXPORT "${PROJECT_NAME}-targets" NAMESPACE AWS::) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake" DESTINATION "lib/${PROJECT_NAME}/cmake/") install(PROGRAMS "${CMAKE_SOURCE_DIR}/packaging/packager" From 1d1373d1d815fe73dc0118941b0c1609113f3f50 Mon Sep 17 00:00:00 2001 From: Marco Magdy Date: Tue, 3 Dec 2019 11:19:53 -0800 Subject: [PATCH 17/84] Bump the version to 0.2.5 Signed-off-by: Marco Magdy --- CMakeLists.txt | 2 +- src/version.cpp.in | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d704b89..45c208a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.9) set(CMAKE_CXX_STANDARD 11) project(aws-lambda-runtime - VERSION 0.2.4 + VERSION 0.2.5 LANGUAGES CXX) option(ENABLE_TESTS "Enables building the test project, requires AWS C++ SDK." OFF) diff --git a/src/version.cpp.in b/src/version.cpp.in index cb91ad4..e13b1e1 100644 --- a/src/version.cpp.in +++ b/src/version.cpp.in @@ -22,19 +22,19 @@ namespace lambda_runtime { AWS_LAMBDA_RUNTIME_API unsigned get_version_major() { - return @PROJECT_VERSION_MAJOR@; + return @PROJECT_VERSION_MAJOR@; // NOLINT } AWS_LAMBDA_RUNTIME_API unsigned get_version_minor() { - return @PROJECT_VERSION_MINOR@; + return @PROJECT_VERSION_MINOR@; // NOLINT } AWS_LAMBDA_RUNTIME_API unsigned get_version_patch() { - return @PROJECT_VERSION_PATCH@; + return @PROJECT_VERSION_PATCH@; // NOLINT } /* clang-format on */ From 6679a7188e772f1eaa2753d85d4cbb542d70ed25 Mon Sep 17 00:00:00 2001 From: Bryan Moffatt Date: Wed, 4 Dec 2019 02:04:16 +0000 Subject: [PATCH 18/84] set CURLOPT_HTTPHEADER to include User-Agent --- src/runtime.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/runtime.cpp b/src/runtime.cpp index 9dba310..e2ee7cd 100644 --- a/src/runtime.cpp +++ b/src/runtime.cpp @@ -235,6 +235,7 @@ runtime::next_outcome runtime::get_next() curl_slist* headers = nullptr; headers = curl_slist_append(headers, get_user_agent_header().c_str()); + curl_easy_setopt(m_curl_handle, CURLOPT_HTTPHEADER, headers); logging::log_debug(LOG_TAG, "Making request to %s", m_endpoints[Endpoints::NEXT].c_str()); CURLcode curl_code = curl_easy_perform(m_curl_handle); From 55276cef2efe18fe13457ebf85df53a81d68be59 Mon Sep 17 00:00:00 2001 From: Marco Magdy Date: Thu, 5 Dec 2019 09:15:22 -0800 Subject: [PATCH 19/84] Bump the version to 0.2.6 Signed-off-by: Marco Magdy --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 45c208a..58a72c8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.9) set(CMAKE_CXX_STANDARD 11) project(aws-lambda-runtime - VERSION 0.2.5 + VERSION 0.2.6 LANGUAGES CXX) option(ENABLE_TESTS "Enables building the test project, requires AWS C++ SDK." OFF) From 53a82645fcb3dfcc9a93b84d8c8a9e76b83a8c94 Mon Sep 17 00:00:00 2001 From: Thomas Bodner Date: Thu, 16 Jan 2020 16:12:37 +0100 Subject: [PATCH 20/84] Enable inclusion via CMake add_subdirectory - When included in other projects as a git submodule, aws-lambda-cpp CMakeLists.txt's use of CMAKE_SOURCE_DIR prohibits convenient build inclusion via add_subdirectory. - This is because CMAKE_SOURCE_DIR always points to the top-level project's source directory, preventing, .e.g, find_package to work properly --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 58a72c8..eb8327f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,7 @@ set_target_properties(${PROJECT_NAME} PROPERTIES VERSION ${PROJECT_VERSION}) target_include_directories(${PROJECT_NAME} PUBLIC - $ + $ $) check_ipo_supported(RESULT has_lto OUTPUT lto_check_output) @@ -111,7 +111,7 @@ install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) -configure_file("${CMAKE_SOURCE_DIR}/cmake/${PROJECT_NAME}-config.cmake" +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/${PROJECT_NAME}-config.cmake" "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake" @ONLY) @@ -125,6 +125,6 @@ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake" "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake" DESTINATION "lib/${PROJECT_NAME}/cmake/") -install(PROGRAMS "${CMAKE_SOURCE_DIR}/packaging/packager" +install(PROGRAMS "${CMAKE_CURRENT_SOURCE_DIR}/packaging/packager" DESTINATION "lib/${PROJECT_NAME}/cmake/") From 80bfd5decd5161a797ed124c85c4018b0326d50a Mon Sep 17 00:00:00 2001 From: Thomas Bodner Date: Thu, 16 Jan 2020 15:57:10 +0100 Subject: [PATCH 21/84] Bump minimum required CMake version in README - Commit #a9e34da5 bumped the required CMake version in the CMakeLists.txt file, but not in the README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7fde5d9..7e7cd94 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ $ make && make install To consume this library in a project that is also using CMake, you would do: ```cmake -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.9) set(CMAKE_CXX_STANDARD 11) project(demo LANGUAGES CXX) find_package(aws-lambda-runtime) From c93cfe64c2e68ef691d1d9904d7f40453be0d876 Mon Sep 17 00:00:00 2001 From: Thomas Bodner Date: Fri, 31 Jan 2020 15:55:32 +0100 Subject: [PATCH 22/84] Make LTO optional in CMake Currently, there is a verbose warning if LTO is not supported by the compiler. This change makes LTO optional, such that users can prevent the warning. The default behavior (enabled) is preserved. --- CMakeLists.txt | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index eb8327f..e6eeda5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,10 +4,9 @@ project(aws-lambda-runtime VERSION 0.2.6 LANGUAGES CXX) +option(ENABLE_LTO "Enables link-time optimization, requires compiler support." ON) option(ENABLE_TESTS "Enables building the test project, requires AWS C++ SDK." OFF) -include(CheckIPOSupported) - add_library(${PROJECT_NAME} "src/logging.cpp" "src/runtime.cpp" @@ -23,11 +22,14 @@ target_include_directories(${PROJECT_NAME} PUBLIC $ $) -check_ipo_supported(RESULT has_lto OUTPUT lto_check_output) -if(has_lto) - set_property(TARGET ${PROJECT_NAME} PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE) -else() - message(WARNING "Link-time optimization (LTO) is not supported: ${lto_check_output}") +if (ENABLE_LTO) + include(CheckIPOSupported) + check_ipo_supported(RESULT has_lto OUTPUT lto_check_output) + if(has_lto) + set_property(TARGET ${PROJECT_NAME} PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE) + else() + message(WARNING "Link-time optimization (LTO) is not supported: ${lto_check_output}") + endif() endif() find_package(CURL REQUIRED) From 4fdc736d461849058b99ab2e368b75abffc55d97 Mon Sep 17 00:00:00 2001 From: Marco Magdy Date: Mon, 17 Feb 2020 15:37:29 -0800 Subject: [PATCH 23/84] Set clang-tidy header filter (#80) The filter tells clang-tidy which headers to scan in every TU it scans. Errors and warnings in a TU are turned on by default. But the headers included in the TU will only be scanned if they match the regex. --- .clang-tidy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.clang-tidy b/.clang-tidy index 0dd63c2..63f498c 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -2,7 +2,7 @@ Checks: 'clang-diagnostic-*,clang-analyzer-*,performance-*,readability-*,modernize-*,bugprone-*,misc-*,-modernize-use-trailing-return-type' WarningsAsErrors: '*' -HeaderFilterRegex: '' +HeaderFilterRegex: 'include/aws/.*\.h$' FormatStyle: 'none' CheckOptions: - key: modernize-pass-by-value.ValuesOnly From 3d25be0dddf805a9bee9ac6788af127286d58fca Mon Sep 17 00:00:00 2001 From: Bryan Moffatt Date: Tue, 25 Feb 2020 19:26:05 +0000 Subject: [PATCH 24/84] Update README.md Update README.md to reflect newer CMake dependency for in #68 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7e7cd94..3407b45 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Since AWS Lambda runs on GNU/Linux, you should build this runtime library and yo ### Prerequisites Make sure you have the following packages installed first: -1. CMake (version 3.5 or later) +1. CMake (version 3.9 or later) 1. git 1. Make or Ninja 1. zip From 7120b482525f0456920f3a8193160f4bac5b7614 Mon Sep 17 00:00:00 2001 From: Markus Rothe Date: Fri, 6 Mar 2020 19:29:44 +0000 Subject: [PATCH 25/84] packager: include 64-bit glibc on RPM based hosts `rpm --query --list glibc` may list files from glibc.i686 and glibc.x86_64 if both are installed. Make sure that only the 64-bit libraries are included. This fixes #83. --- packaging/packager | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packaging/packager b/packaging/packager index 32b2db0..3d689c0 100755 --- a/packaging/packager +++ b/packaging/packager @@ -73,8 +73,8 @@ function package_libc_via_dpkg() { function package_libc_via_rpm() { if type rpm > /dev/null 2>&1; then - if [[ $(rpm --query --list glibc | wc -l) -gt 1 ]]; then - rpm --query --list glibc | sed -E '/\.so$|\.so\.[0-9]+$/!d' + if [[ $(rpm --query --list glibc.x86_64 | wc -l) -gt 1 ]]; then + rpm --query --list glibc.x86_64 | sed -E '/\.so$|\.so\.[0-9]+$/!d' fi fi } From de9d3389d299be5b4008a3073e7934dc2f349829 Mon Sep 17 00:00:00 2001 From: Markus Rothe Date: Tue, 10 Mar 2020 08:49:38 +0000 Subject: [PATCH 26/84] CMakeLists.txt: use proper libdir --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e6eeda5..b3869a6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -120,13 +120,13 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/${PROJECT_NAME}-config.cmake" export(EXPORT "${PROJECT_NAME}-targets" NAMESPACE AWS::) install(EXPORT "${PROJECT_NAME}-targets" - DESTINATION "lib/${PROJECT_NAME}/cmake/" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/${PROJECT_NAME}/cmake/" NAMESPACE AWS::) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake" "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake" - DESTINATION "lib/${PROJECT_NAME}/cmake/") + DESTINATION "${CMAKE_INSTALL_LIBDIR}/${PROJECT_NAME}/cmake/") install(PROGRAMS "${CMAKE_CURRENT_SOURCE_DIR}/packaging/packager" - DESTINATION "lib/${PROJECT_NAME}/cmake/") + DESTINATION "${CMAKE_INSTALL_LIBDIR}/${PROJECT_NAME}/cmake/") From 6ac045cbe8a154745d13e0c0f23db8c31496aed3 Mon Sep 17 00:00:00 2001 From: Marco Magdy Date: Mon, 24 Feb 2020 12:41:28 -0800 Subject: [PATCH 27/84] move backward header into src --- {include => src}/backward.h | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {include => src}/backward.h (100%) diff --git a/include/backward.h b/src/backward.h similarity index 100% rename from include/backward.h rename to src/backward.h From a4b8f4553e1883cbf059eb0ba93d7f8030605ed5 Mon Sep 17 00:00:00 2001 From: Marco Magdy Date: Tue, 24 Mar 2020 10:14:12 -0700 Subject: [PATCH 28/84] Add clang-tidy identifier naming rules (#87) --- .clang-tidy | 24 ++++ include/aws/lambda-runtime/outcome.h | 18 +-- src/runtime.cpp | 6 +- tests/main.cpp | 14 +-- tests/resources/lambda_function.cpp | 164 ++++++++++++++------------- tests/runtime_tests.cpp | 131 ++++++++++----------- 6 files changed, 192 insertions(+), 165 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 63f498c..7d343ea 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -13,5 +13,29 @@ CheckOptions: value: '1' - key: misc-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic value: '1' + - key: readability-identifier-naming.ClassCase + value: 'lower_case' + - key: readability-identifier-naming.StructCase + value: 'lower_case' + - key: readability-identifier-naming.StructCase + value: 'lower_case' + - key: readability-identifier-naming.ParameterCase + value: 'lower_case' + - key: readability-identifier-naming.PrivateMemberCase + value: 'lower_case' + - key: readability-identifier-naming.LocalVariableCase + value: 'lower_case' + - key: readability-identifier-naming.TypeAliasCase + value: 'lower_case' + - key: readability-identifier-naming.UnionCase + value: 'lower_case' + - key: readability-identifier-naming.FunctionCase + value: 'lower_case' + - key: readability-identifier-naming.NamespaceCase + value: 'lower_case' + - key: readability-identifier-naming.GlobalConstantCase + value: 'UPPER_CASE' + - key: readability-identifier-naming.PrivateMemberPrefix + value: 'm_' ... diff --git a/include/aws/lambda-runtime/outcome.h b/include/aws/lambda-runtime/outcome.h index ac3c9f1..e587e39 100644 --- a/include/aws/lambda-runtime/outcome.h +++ b/include/aws/lambda-runtime/outcome.h @@ -23,13 +23,13 @@ namespace lambda_runtime { template class outcome { public: - outcome(TResult const& s) : s(s), success(true) {} + outcome(TResult const& s) : s(s), m_success(true) {} - outcome(TFailure const& f) : f(f), success(false) {} + outcome(TFailure const& f) : f(f), m_success(false) {} - outcome(outcome&& other) noexcept : success(other.success) + outcome(outcome&& other) noexcept : m_success(other.m_success) { - if (success) { + if (m_success) { s = std::move(other.s); } else { @@ -39,7 +39,7 @@ class outcome { ~outcome() { - if (success) { + if (m_success) { s.~TResult(); } else { @@ -49,24 +49,24 @@ class outcome { TResult const& get_result() const { - assert(success); + assert(m_success); return s; } TFailure const& get_failure() const { - assert(!success); + assert(!m_success); return f; } - bool is_success() const { return success; } + bool is_success() const { return m_success; } private: union { TResult s; TFailure f; }; - bool success; + bool m_success; }; } // namespace lambda_runtime } // namespace aws diff --git a/src/runtime.cpp b/src/runtime.cpp index e2ee7cd..2c12542 100644 --- a/src/runtime.cpp +++ b/src/runtime.cpp @@ -72,7 +72,7 @@ static size_t write_data(char* ptr, size_t size, size_t nmemb, void* userdata) // std::isspace has a few edge cases that would trigger UB. In particular, the documentation says: // "The behavior is undefined if the value of the input is not representable as unsigned char and is not equal to EOF." // So, this function does the simple obvious thing instead. -static inline bool IsSpace(int ch) +static inline bool is_whitespace(int ch) { constexpr int space = 0x20; // space (0x20, ' ') constexpr int form_feed = 0x0c; // form feed (0x0c, '\f') @@ -96,9 +96,9 @@ static inline bool IsSpace(int ch) static inline std::string trim(std::string s) { // trim right - s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) { return !IsSpace(ch); }).base(), s.end()); + s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) { return !is_whitespace(ch); }).base(), s.end()); // trim left - s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) { return !IsSpace(ch); })); + s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) { return !is_whitespace(ch); })); return s; } diff --git a/tests/main.cpp b/tests/main.cpp index 33c882f..d7700e8 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -2,7 +2,7 @@ #include #include "gtest/gtest.h" -std::function()> GetConsoleLoggerFactory() +std::function()> get_console_logger_factory() { return [] { return Aws::MakeShared( @@ -14,11 +14,11 @@ std::string aws_prefix; void parse_args(int argc, char** argv) { - const std::string resourcePrefixOption = "--aws_prefix="; + const std::string resource_prefix_option = "--aws_prefix="; for (int i = 1; i < argc; i++) { std::string arg = argv[i]; - if (arg.find(resourcePrefixOption) == 0) { - aws_prefix = arg.substr(resourcePrefixOption.length()); // get whatever value after the '=' + if (arg.find(resource_prefix_option) == 0) { + aws_prefix = arg.substr(resource_prefix_option.length()); // get whatever value after the '=' break; } } @@ -29,10 +29,10 @@ int main(int argc, char** argv) parse_args(argc, argv); Aws::SDKOptions options; options.loggingOptions.logLevel = Aws::Utils::Logging::LogLevel::Warn; - options.loggingOptions.logger_create_fn = GetConsoleLoggerFactory(); + options.loggingOptions.logger_create_fn = get_console_logger_factory(); Aws::InitAPI(options); ::testing::InitGoogleTest(&argc, argv); - int exitCode = RUN_ALL_TESTS(); + int exit_code = RUN_ALL_TESTS(); Aws::ShutdownAPI(options); - return exitCode; + return exit_code; } diff --git a/tests/resources/lambda_function.cpp b/tests/resources/lambda_function.cpp index 6fbc588..43f3dac 100644 --- a/tests/resources/lambda_function.cpp +++ b/tests/resources/lambda_function.cpp @@ -7,8 +7,8 @@ using namespace aws::lambda_runtime; -constexpr unsigned int awslogo_png_len = 1451; -extern unsigned char awslogo_png[awslogo_png_len]; +constexpr unsigned int AWSLOGO_PNG_LEN = 1451; +extern unsigned char awslogo_png[AWSLOGO_PNG_LEN]; // NOLINT invocation_response echo_success(invocation_request const& request) { @@ -22,7 +22,7 @@ invocation_response echo_failure(invocation_request const& /*request*/) invocation_response binary_response(invocation_request const& /*request*/) { - const std::string png((char*)awslogo_png, awslogo_png_len); + const std::string png((char*)awslogo_png, AWSLOGO_PNG_LEN); return invocation_response::success(png, "image/png"); } @@ -47,81 +47,83 @@ int main(int argc, char* argv[]) return 0; } -unsigned char awslogo_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x0e, 0x08, 0x06, 0x00, 0x00, 0x00, 0x35, 0xf8, 0xdc, 0x7e, 0x00, 0x00, 0x00, 0x04, 0x67, - 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, 0x4d, - 0x00, 0x00, 0x7a, 0x26, 0x00, 0x00, 0x80, 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, 0xe8, 0x00, 0x00, 0x75, - 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, 0x98, 0x00, 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, - 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18, - 0x00, 0x00, 0x01, 0x59, 0x69, 0x54, 0x58, 0x74, 0x58, 0x4d, 0x4c, 0x3a, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x64, 0x6f, - 0x62, 0x65, 0x2e, 0x78, 0x6d, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x78, 0x3a, 0x78, 0x6d, 0x70, 0x6d, 0x65, - 0x74, 0x61, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x78, 0x3d, 0x22, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x3a, 0x6e, - 0x73, 0x3a, 0x6d, 0x65, 0x74, 0x61, 0x2f, 0x22, 0x20, 0x78, 0x3a, 0x78, 0x6d, 0x70, 0x74, 0x6b, 0x3d, 0x22, 0x58, - 0x4d, 0x50, 0x20, 0x43, 0x6f, 0x72, 0x65, 0x20, 0x35, 0x2e, 0x34, 0x2e, 0x30, 0x22, 0x3e, 0x0a, 0x20, 0x20, 0x20, - 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x52, 0x44, 0x46, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x72, 0x64, 0x66, 0x3d, - 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x77, 0x33, 0x2e, 0x6f, 0x72, 0x67, 0x2f, - 0x31, 0x39, 0x39, 0x39, 0x2f, 0x30, 0x32, 0x2f, 0x32, 0x32, 0x2d, 0x72, 0x64, 0x66, 0x2d, 0x73, 0x79, 0x6e, 0x74, - 0x61, 0x78, 0x2d, 0x6e, 0x73, 0x23, 0x22, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x72, 0x64, 0x66, - 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x72, 0x64, 0x66, 0x3a, 0x61, 0x62, - 0x6f, 0x75, 0x74, 0x3d, 0x22, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x74, 0x69, 0x66, 0x66, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, - 0x6e, 0x73, 0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x69, 0x66, 0x66, 0x2f, 0x31, - 0x2e, 0x30, 0x2f, 0x22, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x74, 0x69, 0x66, - 0x66, 0x3a, 0x4f, 0x72, 0x69, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x31, 0x3c, 0x2f, 0x74, 0x69, - 0x66, 0x66, 0x3a, 0x4f, 0x72, 0x69, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x52, 0x44, 0x46, 0x3e, 0x0a, 0x3c, 0x2f, - 0x78, 0x3a, 0x78, 0x6d, 0x70, 0x6d, 0x65, 0x74, 0x61, 0x3e, 0x0a, 0x4c, 0xc2, 0x27, 0x59, 0x00, 0x00, 0x03, 0xbc, - 0x49, 0x44, 0x41, 0x54, 0x38, 0x11, 0x65, 0x54, 0x6f, 0x6c, 0x53, 0x55, 0x14, 0x3f, 0xe7, 0xbe, 0xd7, 0x75, 0xf2, - 0x18, 0x1a, 0x24, 0xc4, 0xc1, 0x20, 0x0a, 0x6b, 0x27, 0x1b, 0xa3, 0x85, 0xa4, 0x92, 0x29, 0x5d, 0xbb, 0x25, 0x82, - 0xc6, 0x48, 0x0c, 0x61, 0x43, 0x0d, 0x4a, 0x98, 0x91, 0x19, 0xa3, 0x7e, 0x22, 0x41, 0x09, 0xc9, 0xe0, 0x83, 0x06, - 0x35, 0x31, 0x46, 0x8c, 0xc1, 0x05, 0x25, 0xc1, 0xc8, 0x97, 0xc5, 0xc4, 0x38, 0xd0, 0x84, 0x60, 0x52, 0xba, 0x2d, - 0x68, 0xd0, 0x6c, 0x65, 0x56, 0xb1, 0xab, 0x3a, 0x70, 0x09, 0x68, 0x84, 0x0f, 0xba, 0xd5, 0xba, 0xbe, 0x77, 0x8f, - 0xbf, 0x7b, 0xcb, 0x32, 0xff, 0x9c, 0xe6, 0xdc, 0x73, 0xcf, 0xb9, 0xbf, 0xf3, 0xf7, 0xde, 0x57, 0x26, 0x50, 0x74, - 0x7d, 0x47, 0x4c, 0x74, 0xf0, 0x2a, 0xb6, 0x2b, 0x88, 0x69, 0x21, 0x6b, 0x1a, 0xd5, 0x25, 0x6f, 0x07, 0x79, 0x33, - 0x29, 0x26, 0xea, 0xad, 0xf1, 0xd5, 0xae, 0x7c, 0x3e, 0x33, 0x1d, 0x8d, 0xa7, 0x1f, 0x21, 0x09, 0x7a, 0x1d, 0x97, - 0x7a, 0xbe, 0xfb, 0x7a, 0xe8, 0x6a, 0x34, 0x9e, 0x4a, 0x88, 0x48, 0x9f, 0x2a, 0x07, 0x8f, 0x05, 0x61, 0xa7, 0x43, - 0x31, 0xbd, 0x6e, 0xe2, 0x09, 0xd1, 0x34, 0x2b, 0xb5, 0xaf, 0x30, 0x9a, 0x39, 0xab, 0xac, 0x41, 0xcb, 0x0a, 0x04, - 0x1a, 0x55, 0x4a, 0xed, 0x12, 0x96, 0x27, 0x85, 0x69, 0x33, 0x7b, 0x33, 0x6f, 0x6a, 0xd2, 0x93, 0x8e, 0x1b, 0xda, - 0x56, 0x76, 0x25, 0x61, 0x71, 0xa2, 0x77, 0x86, 0x6a, 0xbd, 0x07, 0xfc, 0x0a, 0xdd, 0x5b, 0x0d, 0xa4, 0x77, 0x43, - 0xc6, 0xb4, 0xe7, 0x34, 0x30, 0xd3, 0xc7, 0x9a, 0xf8, 0xa8, 0x62, 0xb5, 0x85, 0x99, 0xdf, 0xd5, 0x5a, 0xdb, 0xd8, - 0x8a, 0xba, 0xba, 0x9c, 0x89, 0x5c, 0xe6, 0x54, 0x21, 0x97, 0x7d, 0xa9, 0xfe, 0x56, 0x1a, 0x2b, 0x8e, 0x0e, 0x9d, - 0x43, 0x09, 0x6f, 0xa0, 0x8a, 0xce, 0x1f, 0x73, 0xc3, 0x85, 0xc0, 0xaf, 0x14, 0x1d, 0xd2, 0x69, 0x13, 0x10, 0xb4, - 0x74, 0xb6, 0x5c, 0xba, 0x40, 0xc4, 0x49, 0xab, 0x09, 0xa7, 0x44, 0xe8, 0x98, 0x2f, 0x7e, 0xc9, 0x71, 0x5c, 0x56, - 0x22, 0x37, 0x2e, 0x8d, 0x65, 0x26, 0x0b, 0x63, 0xe7, 0xfa, 0x8b, 0xb9, 0xec, 0x19, 0x13, 0x1b, 0x85, 0x63, 0x44, - 0xad, 0x9b, 0x56, 0x91, 0x52, 0xc7, 0x10, 0xb4, 0x01, 0xea, 0x15, 0xc8, 0x16, 0x1c, 0x5c, 0x9d, 0xc8, 0x65, 0x37, - 0x44, 0xe2, 0xc9, 0x77, 0x88, 0x54, 0x84, 0x39, 0xd8, 0x2b, 0x5a, 0x1d, 0x11, 0x92, 0x7e, 0x26, 0xde, 0xa3, 0xc5, - 0xdf, 0xae, 0xd8, 0x2d, 0x90, 0xa6, 0xad, 0x13, 0xe3, 0xd9, 0x6c, 0x34, 0x96, 0x3c, 0x24, 0xc4, 0x07, 0xe0, 0xff, - 0x3b, 0xf8, 0x74, 0xc5, 0x57, 0x7b, 0x27, 0xf3, 0x99, 0x6b, 0xb6, 0x0d, 0xad, 0xd4, 0x09, 0x4d, 0xb4, 0x44, 0x09, - 0x6d, 0x91, 0x19, 0xef, 0x21, 0x62, 0x3e, 0x05, 0x50, 0x18, 0x4c, 0x1c, 0xa8, 0x41, 0x12, 0x69, 0xd0, 0xe2, 0xec, - 0x40, 0xe0, 0xcb, 0x61, 0xdf, 0xff, 0x14, 0x23, 0x58, 0xc0, 0xec, 0xf6, 0xe0, 0xf8, 0x67, 0xf9, 0xd3, 0xfb, 0xd2, - 0xe0, 0x0a, 0xb9, 0xa1, 0x3e, 0xdc, 0xd5, 0x72, 0x8c, 0xf7, 0x39, 0xa8, 0xf7, 0x87, 0x42, 0xf2, 0x81, 0xb1, 0xdb, - 0x04, 0xa8, 0x76, 0x0d, 0x78, 0xe4, 0xfb, 0x8b, 0xd9, 0x9f, 0x8a, 0xc5, 0xcf, 0xfe, 0x82, 0x71, 0x3d, 0xba, 0x58, - 0x6c, 0x00, 0x21, 0xbd, 0xf4, 0x73, 0x88, 0x32, 0x8b, 0xec, 0x43, 0xf5, 0xc3, 0xf9, 0xfc, 0xf9, 0x1b, 0xb8, 0xd8, - 0xeb, 0xc0, 0xbf, 0x0c, 0x3e, 0x6d, 0xf0, 0xd1, 0x58, 0xe7, 0xf2, 0xa6, 0x75, 0xed, 0x77, 0xe1, 0x21, 0x5c, 0x2b, - 0x8e, 0x65, 0x3f, 0x0c, 0x84, 0x4e, 0x6a, 0x2d, 0xeb, 0x8c, 0xbf, 0x6b, 0x16, 0x12, 0x3e, 0x8c, 0x54, 0xaf, 0x45, - 0x62, 0xed, 0x1b, 0xf0, 0x8a, 0xca, 0x98, 0xeb, 0x38, 0x9c, 0x17, 0x47, 0x5b, 0xd3, 0x77, 0xe7, 0xc7, 0x07, 0x2e, - 0xc1, 0x9e, 0x55, 0xca, 0x89, 0xfb, 0x81, 0x8c, 0x54, 0xf1, 0x74, 0xc1, 0x09, 0x85, 0x36, 0x57, 0x82, 0xca, 0x27, - 0x55, 0xf7, 0xa0, 0x19, 0x05, 0x1d, 0x8f, 0xc4, 0x92, 0x53, 0x0b, 0x1c, 0xf6, 0x6a, 0x58, 0x56, 0xdf, 0x1e, 0xa6, - 0x9e, 0x1f, 0x2c, 0xf8, 0xe6, 0x92, 0x48, 0xa4, 0x12, 0x2b, 0xd7, 0x26, 0x77, 0x9a, 0x4a, 0x8c, 0xe9, 0xce, 0x96, - 0xf4, 0x1d, 0x10, 0xb6, 0xc3, 0xa6, 0xa6, 0xfb, 0xea, 0x1a, 0xd7, 0x76, 0xae, 0x9e, 0xd3, 0x1b, 0x1b, 0x37, 0x2e, - 0x5a, 0x15, 0x6f, 0x8f, 0x40, 0x47, 0x1d, 0x55, 0x5a, 0x03, 0xbd, 0xa1, 0xb5, 0xfd, 0x71, 0xa2, 0x8e, 0x6d, 0x44, - 0x4f, 0x78, 0x73, 0x76, 0x46, 0x66, 0xbc, 0x30, 0xf3, 0x74, 0xe7, 0xe9, 0xe0, 0x41, 0x52, 0x60, 0x5c, 0x8b, 0x25, - 0x13, 0xe4, 0x9f, 0xe7, 0xff, 0xd5, 0x6f, 0xc2, 0xaa, 0x42, 0xbe, 0xa2, 0x7a, 0x1a, 0xa7, 0xb6, 0xa0, 0x1c, 0xf2, - 0x1c, 0xae, 0x7c, 0xc1, 0x72, 0x94, 0x9e, 0xc5, 0xd1, 0x34, 0x3f, 0x43, 0x27, 0xe6, 0x90, 0x82, 0x04, 0xdf, 0x52, - 0x8b, 0xdb, 0x4c, 0x79, 0x93, 0xc4, 0x26, 0xea, 0xce, 0x77, 0xf1, 0xc0, 0xc0, 0x40, 0x60, 0x30, 0x18, 0x21, 0x1f, - 0xea, 0x48, 0x3b, 0x7d, 0xe9, 0x8c, 0xa6, 0x66, 0xdb, 0x85, 0xc3, 0xdd, 0x34, 0x5b, 0x7a, 0xbb, 0xae, 0x2d, 0xe4, - 0x96, 0xb7, 0x2b, 0x0a, 0x1c, 0xc5, 0xfa, 0x61, 0x40, 0x67, 0x58, 0xde, 0xa2, 0x45, 0x78, 0x2f, 0xaf, 0x40, 0xd9, - 0x08, 0x36, 0x37, 0x7f, 0x92, 0x7b, 0xe9, 0x37, 0xc8, 0xff, 0x91, 0x49, 0x6c, 0x8d, 0x7d, 0xb8, 0x35, 0xfe, 0x57, - 0x57, 0xd6, 0x8c, 0x58, 0x61, 0xaa, 0xa5, 0x6e, 0x94, 0x74, 0x19, 0x86, 0x85, 0xe0, 0x17, 0x4d, 0xbb, 0x96, 0xa4, - 0x9f, 0xb6, 0xc2, 0xc5, 0x7c, 0xea, 0x66, 0xd6, 0xc3, 0xe0, 0x41, 0xd4, 0x76, 0x1e, 0xcf, 0x60, 0x82, 0xae, 0xd0, - 0x75, 0x9e, 0x1f, 0x99, 0xc5, 0x9b, 0x45, 0xde, 0xa3, 0x3a, 0x0a, 0x68, 0x25, 0x02, 0xde, 0x03, 0xec, 0x83, 0x30, - 0xb5, 0x21, 0xc6, 0x14, 0xe4, 0x53, 0x28, 0xe5, 0x79, 0xec, 0xbf, 0x61, 0x5b, 0x15, 0xda, 0x44, 0x8b, 0xd5, 0xf6, - 0xfb, 0xe9, 0x51, 0x1c, 0xbc, 0x80, 0xc0, 0x6d, 0xf6, 0x4b, 0x28, 0x99, 0x48, 0xf4, 0x0b, 0xd6, 0x5f, 0xc1, 0x7f, - 0x80, 0xcd, 0xc8, 0x6e, 0x01, 0x2f, 0x01, 0xd7, 0x53, 0x0d, 0x7e, 0xb3, 0xd6, 0x36, 0x84, 0x24, 0x47, 0x78, 0x0f, - 0x7d, 0x84, 0x98, 0x2e, 0x2d, 0xa3, 0xfd, 0x74, 0x1b, 0x1d, 0x9e, 0xef, 0x00, 0x46, 0x54, 0xe9, 0xc3, 0xc9, 0x92, - 0xbc, 0x8f, 0x3f, 0xbe, 0x59, 0x4a, 0xc1, 0x69, 0x13, 0x0c, 0x2d, 0x48, 0xb2, 0x0c, 0x7b, 0xd3, 0xb6, 0xb9, 0xf0, - 0x69, 0xf0, 0x14, 0x76, 0x17, 0x21, 0x47, 0xc8, 0xa1, 0x0c, 0x3f, 0x6d, 0x8b, 0x80, 0x0a, 0xc0, 0x71, 0xaa, 0xe5, - 0xdd, 0x54, 0x36, 0xfb, 0xbf, 0x01, 0x02, 0x9d, 0x70, 0x74, 0xcd, 0x2a, 0x03, 0x15, 0x00, 0x00, 0x00, 0x00, 0x49, - 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82}; +/* clang-format off */ +unsigned char awslogo_png[] = { // NOLINT + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, // NOLINT + 0x18, 0x00, 0x00, 0x00, 0x0e, 0x08, 0x06, 0x00, 0x00, 0x00, 0x35, 0xf8, 0xdc, 0x7e, 0x00, 0x00, 0x00, 0x04, 0x67, // NOLINT + 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, 0x4d, // NOLINT + 0x00, 0x00, 0x7a, 0x26, 0x00, 0x00, 0x80, 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, 0xe8, 0x00, 0x00, 0x75, // NOLINT + 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, 0x98, 0x00, 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, // NOLINT + 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18, // NOLINT + 0x00, 0x00, 0x01, 0x59, 0x69, 0x54, 0x58, 0x74, 0x58, 0x4d, 0x4c, 0x3a, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x64, 0x6f, // NOLINT + 0x62, 0x65, 0x2e, 0x78, 0x6d, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x78, 0x3a, 0x78, 0x6d, 0x70, 0x6d, 0x65, // NOLINT + 0x74, 0x61, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x78, 0x3d, 0x22, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x3a, 0x6e, // NOLINT + 0x73, 0x3a, 0x6d, 0x65, 0x74, 0x61, 0x2f, 0x22, 0x20, 0x78, 0x3a, 0x78, 0x6d, 0x70, 0x74, 0x6b, 0x3d, 0x22, 0x58, // NOLINT + 0x4d, 0x50, 0x20, 0x43, 0x6f, 0x72, 0x65, 0x20, 0x35, 0x2e, 0x34, 0x2e, 0x30, 0x22, 0x3e, 0x0a, 0x20, 0x20, 0x20, // NOLINT + 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x52, 0x44, 0x46, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x72, 0x64, 0x66, 0x3d, // NOLINT + 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x77, 0x33, 0x2e, 0x6f, 0x72, 0x67, 0x2f, // NOLINT + 0x31, 0x39, 0x39, 0x39, 0x2f, 0x30, 0x32, 0x2f, 0x32, 0x32, 0x2d, 0x72, 0x64, 0x66, 0x2d, 0x73, 0x79, 0x6e, 0x74, // NOLINT + 0x61, 0x78, 0x2d, 0x6e, 0x73, 0x23, 0x22, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x72, 0x64, 0x66, // NOLINT + 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x72, 0x64, 0x66, 0x3a, 0x61, 0x62, // NOLINT + 0x6f, 0x75, 0x74, 0x3d, 0x22, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, // NOLINT + 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x74, 0x69, 0x66, 0x66, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, // NOLINT + 0x6e, 0x73, 0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x69, 0x66, 0x66, 0x2f, 0x31, // NOLINT + 0x2e, 0x30, 0x2f, 0x22, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x74, 0x69, 0x66, // NOLINT + 0x66, 0x3a, 0x4f, 0x72, 0x69, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x31, 0x3c, 0x2f, 0x74, 0x69, // NOLINT + 0x66, 0x66, 0x3a, 0x4f, 0x72, 0x69, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x20, 0x20, 0x20, // NOLINT + 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, // NOLINT + 0x6e, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x52, 0x44, 0x46, 0x3e, 0x0a, 0x3c, 0x2f, // NOLINT + 0x78, 0x3a, 0x78, 0x6d, 0x70, 0x6d, 0x65, 0x74, 0x61, 0x3e, 0x0a, 0x4c, 0xc2, 0x27, 0x59, 0x00, 0x00, 0x03, 0xbc, // NOLINT + 0x49, 0x44, 0x41, 0x54, 0x38, 0x11, 0x65, 0x54, 0x6f, 0x6c, 0x53, 0x55, 0x14, 0x3f, 0xe7, 0xbe, 0xd7, 0x75, 0xf2, // NOLINT + 0x18, 0x1a, 0x24, 0xc4, 0xc1, 0x20, 0x0a, 0x6b, 0x27, 0x1b, 0xa3, 0x85, 0xa4, 0x92, 0x29, 0x5d, 0xbb, 0x25, 0x82, // NOLINT + 0xc6, 0x48, 0x0c, 0x61, 0x43, 0x0d, 0x4a, 0x98, 0x91, 0x19, 0xa3, 0x7e, 0x22, 0x41, 0x09, 0xc9, 0xe0, 0x83, 0x06, // NOLINT + 0x35, 0x31, 0x46, 0x8c, 0xc1, 0x05, 0x25, 0xc1, 0xc8, 0x97, 0xc5, 0xc4, 0x38, 0xd0, 0x84, 0x60, 0x52, 0xba, 0x2d, // NOLINT + 0x68, 0xd0, 0x6c, 0x65, 0x56, 0xb1, 0xab, 0x3a, 0x70, 0x09, 0x68, 0x84, 0x0f, 0xba, 0xd5, 0xba, 0xbe, 0x77, 0x8f, // NOLINT + 0xbf, 0x7b, 0xcb, 0x32, 0xff, 0x9c, 0xe6, 0xdc, 0x73, 0xcf, 0xb9, 0xbf, 0xf3, 0xf7, 0xde, 0x57, 0x26, 0x50, 0x74, // NOLINT + 0x7d, 0x47, 0x4c, 0x74, 0xf0, 0x2a, 0xb6, 0x2b, 0x88, 0x69, 0x21, 0x6b, 0x1a, 0xd5, 0x25, 0x6f, 0x07, 0x79, 0x33, // NOLINT + 0x29, 0x26, 0xea, 0xad, 0xf1, 0xd5, 0xae, 0x7c, 0x3e, 0x33, 0x1d, 0x8d, 0xa7, 0x1f, 0x21, 0x09, 0x7a, 0x1d, 0x97, // NOLINT + 0x7a, 0xbe, 0xfb, 0x7a, 0xe8, 0x6a, 0x34, 0x9e, 0x4a, 0x88, 0x48, 0x9f, 0x2a, 0x07, 0x8f, 0x05, 0x61, 0xa7, 0x43, // NOLINT + 0x31, 0xbd, 0x6e, 0xe2, 0x09, 0xd1, 0x34, 0x2b, 0xb5, 0xaf, 0x30, 0x9a, 0x39, 0xab, 0xac, 0x41, 0xcb, 0x0a, 0x04, // NOLINT + 0x1a, 0x55, 0x4a, 0xed, 0x12, 0x96, 0x27, 0x85, 0x69, 0x33, 0x7b, 0x33, 0x6f, 0x6a, 0xd2, 0x93, 0x8e, 0x1b, 0xda, // NOLINT + 0x56, 0x76, 0x25, 0x61, 0x71, 0xa2, 0x77, 0x86, 0x6a, 0xbd, 0x07, 0xfc, 0x0a, 0xdd, 0x5b, 0x0d, 0xa4, 0x77, 0x43, // NOLINT + 0xc6, 0xb4, 0xe7, 0x34, 0x30, 0xd3, 0xc7, 0x9a, 0xf8, 0xa8, 0x62, 0xb5, 0x85, 0x99, 0xdf, 0xd5, 0x5a, 0xdb, 0xd8, // NOLINT + 0x8a, 0xba, 0xba, 0x9c, 0x89, 0x5c, 0xe6, 0x54, 0x21, 0x97, 0x7d, 0xa9, 0xfe, 0x56, 0x1a, 0x2b, 0x8e, 0x0e, 0x9d, // NOLINT + 0x43, 0x09, 0x6f, 0xa0, 0x8a, 0xce, 0x1f, 0x73, 0xc3, 0x85, 0xc0, 0xaf, 0x14, 0x1d, 0xd2, 0x69, 0x13, 0x10, 0xb4, // NOLINT + 0x74, 0xb6, 0x5c, 0xba, 0x40, 0xc4, 0x49, 0xab, 0x09, 0xa7, 0x44, 0xe8, 0x98, 0x2f, 0x7e, 0xc9, 0x71, 0x5c, 0x56, // NOLINT + 0x22, 0x37, 0x2e, 0x8d, 0x65, 0x26, 0x0b, 0x63, 0xe7, 0xfa, 0x8b, 0xb9, 0xec, 0x19, 0x13, 0x1b, 0x85, 0x63, 0x44, // NOLINT + 0xad, 0x9b, 0x56, 0x91, 0x52, 0xc7, 0x10, 0xb4, 0x01, 0xea, 0x15, 0xc8, 0x16, 0x1c, 0x5c, 0x9d, 0xc8, 0x65, 0x37, // NOLINT + 0x44, 0xe2, 0xc9, 0x77, 0x88, 0x54, 0x84, 0x39, 0xd8, 0x2b, 0x5a, 0x1d, 0x11, 0x92, 0x7e, 0x26, 0xde, 0xa3, 0xc5, // NOLINT + 0xdf, 0xae, 0xd8, 0x2d, 0x90, 0xa6, 0xad, 0x13, 0xe3, 0xd9, 0x6c, 0x34, 0x96, 0x3c, 0x24, 0xc4, 0x07, 0xe0, 0xff, // NOLINT + 0x3b, 0xf8, 0x74, 0xc5, 0x57, 0x7b, 0x27, 0xf3, 0x99, 0x6b, 0xb6, 0x0d, 0xad, 0xd4, 0x09, 0x4d, 0xb4, 0x44, 0x09, // NOLINT + 0x6d, 0x91, 0x19, 0xef, 0x21, 0x62, 0x3e, 0x05, 0x50, 0x18, 0x4c, 0x1c, 0xa8, 0x41, 0x12, 0x69, 0xd0, 0xe2, 0xec, // NOLINT + 0x40, 0xe0, 0xcb, 0x61, 0xdf, 0xff, 0x14, 0x23, 0x58, 0xc0, 0xec, 0xf6, 0xe0, 0xf8, 0x67, 0xf9, 0xd3, 0xfb, 0xd2, // NOLINT + 0xe0, 0x0a, 0xb9, 0xa1, 0x3e, 0xdc, 0xd5, 0x72, 0x8c, 0xf7, 0x39, 0xa8, 0xf7, 0x87, 0x42, 0xf2, 0x81, 0xb1, 0xdb, // NOLINT + 0x04, 0xa8, 0x76, 0x0d, 0x78, 0xe4, 0xfb, 0x8b, 0xd9, 0x9f, 0x8a, 0xc5, 0xcf, 0xfe, 0x82, 0x71, 0x3d, 0xba, 0x58, // NOLINT + 0x6c, 0x00, 0x21, 0xbd, 0xf4, 0x73, 0x88, 0x32, 0x8b, 0xec, 0x43, 0xf5, 0xc3, 0xf9, 0xfc, 0xf9, 0x1b, 0xb8, 0xd8, // NOLINT + 0xeb, 0xc0, 0xbf, 0x0c, 0x3e, 0x6d, 0xf0, 0xd1, 0x58, 0xe7, 0xf2, 0xa6, 0x75, 0xed, 0x77, 0xe1, 0x21, 0x5c, 0x2b, // NOLINT + 0x8e, 0x65, 0x3f, 0x0c, 0x84, 0x4e, 0x6a, 0x2d, 0xeb, 0x8c, 0xbf, 0x6b, 0x16, 0x12, 0x3e, 0x8c, 0x54, 0xaf, 0x45, // NOLINT + 0x62, 0xed, 0x1b, 0xf0, 0x8a, 0xca, 0x98, 0xeb, 0x38, 0x9c, 0x17, 0x47, 0x5b, 0xd3, 0x77, 0xe7, 0xc7, 0x07, 0x2e, // NOLINT + 0xc1, 0x9e, 0x55, 0xca, 0x89, 0xfb, 0x81, 0x8c, 0x54, 0xf1, 0x74, 0xc1, 0x09, 0x85, 0x36, 0x57, 0x82, 0xca, 0x27, // NOLINT + 0x55, 0xf7, 0xa0, 0x19, 0x05, 0x1d, 0x8f, 0xc4, 0x92, 0x53, 0x0b, 0x1c, 0xf6, 0x6a, 0x58, 0x56, 0xdf, 0x1e, 0xa6, // NOLINT + 0x9e, 0x1f, 0x2c, 0xf8, 0xe6, 0x92, 0x48, 0xa4, 0x12, 0x2b, 0xd7, 0x26, 0x77, 0x9a, 0x4a, 0x8c, 0xe9, 0xce, 0x96, // NOLINT + 0xf4, 0x1d, 0x10, 0xb6, 0xc3, 0xa6, 0xa6, 0xfb, 0xea, 0x1a, 0xd7, 0x76, 0xae, 0x9e, 0xd3, 0x1b, 0x1b, 0x37, 0x2e, // NOLINT + 0x5a, 0x15, 0x6f, 0x8f, 0x40, 0x47, 0x1d, 0x55, 0x5a, 0x03, 0xbd, 0xa1, 0xb5, 0xfd, 0x71, 0xa2, 0x8e, 0x6d, 0x44, // NOLINT + 0x4f, 0x78, 0x73, 0x76, 0x46, 0x66, 0xbc, 0x30, 0xf3, 0x74, 0xe7, 0xe9, 0xe0, 0x41, 0x52, 0x60, 0x5c, 0x8b, 0x25, // NOLINT + 0x13, 0xe4, 0x9f, 0xe7, 0xff, 0xd5, 0x6f, 0xc2, 0xaa, 0x42, 0xbe, 0xa2, 0x7a, 0x1a, 0xa7, 0xb6, 0xa0, 0x1c, 0xf2, // NOLINT + 0x1c, 0xae, 0x7c, 0xc1, 0x72, 0x94, 0x9e, 0xc5, 0xd1, 0x34, 0x3f, 0x43, 0x27, 0xe6, 0x90, 0x82, 0x04, 0xdf, 0x52, // NOLINT + 0x8b, 0xdb, 0x4c, 0x79, 0x93, 0xc4, 0x26, 0xea, 0xce, 0x77, 0xf1, 0xc0, 0xc0, 0x40, 0x60, 0x30, 0x18, 0x21, 0x1f, // NOLINT + 0xea, 0x48, 0x3b, 0x7d, 0xe9, 0x8c, 0xa6, 0x66, 0xdb, 0x85, 0xc3, 0xdd, 0x34, 0x5b, 0x7a, 0xbb, 0xae, 0x2d, 0xe4, // NOLINT + 0x96, 0xb7, 0x2b, 0x0a, 0x1c, 0xc5, 0xfa, 0x61, 0x40, 0x67, 0x58, 0xde, 0xa2, 0x45, 0x78, 0x2f, 0xaf, 0x40, 0xd9, // NOLINT + 0x08, 0x36, 0x37, 0x7f, 0x92, 0x7b, 0xe9, 0x37, 0xc8, 0xff, 0x91, 0x49, 0x6c, 0x8d, 0x7d, 0xb8, 0x35, 0xfe, 0x57, // NOLINT + 0x57, 0xd6, 0x8c, 0x58, 0x61, 0xaa, 0xa5, 0x6e, 0x94, 0x74, 0x19, 0x86, 0x85, 0xe0, 0x17, 0x4d, 0xbb, 0x96, 0xa4, // NOLINT + 0x9f, 0xb6, 0xc2, 0xc5, 0x7c, 0xea, 0x66, 0xd6, 0xc3, 0xe0, 0x41, 0xd4, 0x76, 0x1e, 0xcf, 0x60, 0x82, 0xae, 0xd0, // NOLINT + 0x75, 0x9e, 0x1f, 0x99, 0xc5, 0x9b, 0x45, 0xde, 0xa3, 0x3a, 0x0a, 0x68, 0x25, 0x02, 0xde, 0x03, 0xec, 0x83, 0x30, // NOLINT + 0xb5, 0x21, 0xc6, 0x14, 0xe4, 0x53, 0x28, 0xe5, 0x79, 0xec, 0xbf, 0x61, 0x5b, 0x15, 0xda, 0x44, 0x8b, 0xd5, 0xf6, // NOLINT + 0xfb, 0xe9, 0x51, 0x1c, 0xbc, 0x80, 0xc0, 0x6d, 0xf6, 0x4b, 0x28, 0x99, 0x48, 0xf4, 0x0b, 0xd6, 0x5f, 0xc1, 0x7f, // NOLINT + 0x80, 0xcd, 0xc8, 0x6e, 0x01, 0x2f, 0x01, 0xd7, 0x53, 0x0d, 0x7e, 0xb3, 0xd6, 0x36, 0x84, 0x24, 0x47, 0x78, 0x0f, // NOLINT + 0x7d, 0x84, 0x98, 0x2e, 0x2d, 0xa3, 0xfd, 0x74, 0x1b, 0x1d, 0x9e, 0xef, 0x00, 0x46, 0x54, 0xe9, 0xc3, 0xc9, 0x92, // NOLINT + 0xbc, 0x8f, 0x3f, 0xbe, 0x59, 0x4a, 0xc1, 0x69, 0x13, 0x0c, 0x2d, 0x48, 0xb2, 0x0c, 0x7b, 0xd3, 0xb6, 0xb9, 0xf0, // NOLINT + 0x69, 0xf0, 0x14, 0x76, 0x17, 0x21, 0x47, 0xc8, 0xa1, 0x0c, 0x3f, 0x6d, 0x8b, 0x80, 0x0a, 0xc0, 0x71, 0xaa, 0xe5, // NOLINT + 0xdd, 0x54, 0x36, 0xfb, 0xbf, 0x01, 0x02, 0x9d, 0x70, 0x74, 0xcd, 0x2a, 0x03, 0x15, 0x00, 0x00, 0x00, 0x00, 0x49, // NOLINT + 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82}; // NOLINT +/* clang-format on */ diff --git a/tests/runtime_tests.cpp b/tests/runtime_tests.cpp index c5aaa74..0032429 100644 --- a/tests/runtime_tests.cpp +++ b/tests/runtime_tests.cpp @@ -19,8 +19,9 @@ namespace { using namespace Aws::Lambda; -const char S3BUCKET[] = "aws-lambda-cpp-tests"; -const char S3KEY[] = "lambda-test-fun.zip"; +constexpr auto S3BUCKET = "aws-lambda-cpp-tests"; +constexpr auto S3KEY = "lambda-test-fun.zip"; +constexpr auto REQUEST_TIMEOUT = 15 * 1000; struct LambdaRuntimeTest : public ::testing::Test { LambdaClient m_lambda_client; @@ -28,7 +29,7 @@ struct LambdaRuntimeTest : public ::testing::Test { static Aws::Client::ClientConfiguration create_iam_config() { Aws::Client::ClientConfiguration config; - config.requestTimeoutMs = 15 * 1000; + config.requestTimeoutMs = REQUEST_TIMEOUT; config.region = Aws::Region::US_EAST_1; return config; } @@ -36,7 +37,7 @@ struct LambdaRuntimeTest : public ::testing::Test { static Aws::Client::ClientConfiguration create_lambda_config() { Aws::Client::ClientConfiguration config; - config.requestTimeoutMs = 15 * 1000; + config.requestTimeoutMs = REQUEST_TIMEOUT; config.region = Aws::Environment::GetEnv("AWS_REGION"); return config; } @@ -72,25 +73,25 @@ struct LambdaRuntimeTest : public ::testing::Test { void create_function(Aws::String const& function_name, Aws::String const& handler_name) { - Model::CreateFunctionRequest createFunctionRequest; - createFunctionRequest.SetHandler(handler_name); - createFunctionRequest.SetFunctionName(function_name); + Model::CreateFunctionRequest create_function_request; + create_function_request.SetHandler(handler_name); + create_function_request.SetFunctionName(function_name); // I ran into eventual-consistency issues when creating the role dynamically as part of the test. - createFunctionRequest.SetRole(get_role_arn("integration-tests")); + create_function_request.SetRole(get_role_arn("integration-tests")); Model::FunctionCode funcode; funcode.WithS3Bucket(S3BUCKET).WithS3Key(build_resource_name(S3KEY)); - createFunctionRequest.SetCode(funcode); - createFunctionRequest.SetRuntime(Aws::Lambda::Model::Runtime::provided); + create_function_request.SetCode(funcode); + create_function_request.SetRuntime(Aws::Lambda::Model::Runtime::provided); - auto outcome = m_lambda_client.CreateFunction(createFunctionRequest); + auto outcome = m_lambda_client.CreateFunction(create_function_request); ASSERT_TRUE(outcome.IsSuccess()) << "Failed to create function " << function_name; } void delete_function(Aws::String const& function_name, bool assert = true) { - Model::DeleteFunctionRequest deleteFunctionRequest; - deleteFunctionRequest.SetFunctionName(function_name); - auto outcome = m_lambda_client.DeleteFunction(deleteFunctionRequest); + Model::DeleteFunctionRequest delete_function_request; + delete_function_request.SetFunctionName(function_name); + auto outcome = m_lambda_client.DeleteFunction(delete_function_request); if (assert) { ASSERT_TRUE(outcome.IsSuccess()) << "Failed to delete function " << function_name; } @@ -100,62 +101,62 @@ struct LambdaRuntimeTest : public ::testing::Test { TEST_F(LambdaRuntimeTest, echo_success) { Aws::String const funcname = build_resource_name("echo_success"); - char const payloadContent[] = "Hello, Lambda!"; + constexpr auto payload_content = "Hello, Lambda!"; create_function(funcname, "echo_success" /*handler_name*/); - Model::InvokeRequest invokeRequest; - invokeRequest.SetFunctionName(funcname); - invokeRequest.SetInvocationType(Model::InvocationType::RequestResponse); - invokeRequest.SetContentType("application/json"); + Model::InvokeRequest invoke_request; + invoke_request.SetFunctionName(funcname); + invoke_request.SetInvocationType(Model::InvocationType::RequestResponse); + invoke_request.SetContentType("application/json"); std::shared_ptr payload = Aws::MakeShared("FunctionTest"); - Aws::Utils::Json::JsonValue jsonPayload; - jsonPayload.WithString("barbaz", payloadContent); - *payload << jsonPayload.View().WriteCompact(); - invokeRequest.SetBody(payload); + Aws::Utils::Json::JsonValue json_payload; + json_payload.WithString("barbaz", payload_content); + *payload << json_payload.View().WriteCompact(); + invoke_request.SetBody(payload); - Model::InvokeOutcome invokeOutcome = m_lambda_client.Invoke(invokeRequest); - EXPECT_TRUE(invokeOutcome.IsSuccess()); + Model::InvokeOutcome invoke_outcome = m_lambda_client.Invoke(invoke_request); + EXPECT_TRUE(invoke_outcome.IsSuccess()); Aws::StringStream output; - if (!invokeOutcome.IsSuccess()) { + if (!invoke_outcome.IsSuccess()) { delete_function(funcname); return; } - EXPECT_EQ(200, invokeOutcome.GetResult().GetStatusCode()); - EXPECT_TRUE(invokeOutcome.GetResult().GetFunctionError().empty()); - auto const jsonResponse = Aws::Utils::Json::JsonValue(invokeOutcome.GetResult().GetPayload()); - EXPECT_TRUE(jsonResponse.WasParseSuccessful()); - EXPECT_STREQ(payloadContent, jsonResponse.View().GetString("barbaz").c_str()); + EXPECT_EQ(200, invoke_outcome.GetResult().GetStatusCode()); + EXPECT_TRUE(invoke_outcome.GetResult().GetFunctionError().empty()); + auto const json_response = Aws::Utils::Json::JsonValue(invoke_outcome.GetResult().GetPayload()); + EXPECT_TRUE(json_response.WasParseSuccessful()); + EXPECT_STREQ(payload_content, json_response.View().GetString("barbaz").c_str()); delete_function(funcname); } TEST_F(LambdaRuntimeTest, echo_unicode) { Aws::String const funcname = build_resource_name("echo_success"); // re-use the echo method but with Unicode input - char const payloadContent[] = "画像は1000語の価値がある"; + constexpr auto payload_content = "画像は1000語の価値がある"; create_function(funcname, "echo_success" /*handler_name*/); - Model::InvokeRequest invokeRequest; - invokeRequest.SetFunctionName(funcname); - invokeRequest.SetInvocationType(Model::InvocationType::RequestResponse); - invokeRequest.SetContentType("application/json"); + Model::InvokeRequest invoke_request; + invoke_request.SetFunctionName(funcname); + invoke_request.SetInvocationType(Model::InvocationType::RequestResponse); + invoke_request.SetContentType("application/json"); std::shared_ptr payload = Aws::MakeShared("FunctionTest"); - Aws::Utils::Json::JsonValue jsonPayload; - jsonPayload.WithString("UnicodeText", payloadContent); - *payload << jsonPayload.View().WriteCompact(); - invokeRequest.SetBody(payload); + Aws::Utils::Json::JsonValue json_payload; + json_payload.WithString("UnicodeText", payload_content); + *payload << json_payload.View().WriteCompact(); + invoke_request.SetBody(payload); - Model::InvokeOutcome invokeOutcome = m_lambda_client.Invoke(invokeRequest); - EXPECT_TRUE(invokeOutcome.IsSuccess()); + Model::InvokeOutcome invoke_outcome = m_lambda_client.Invoke(invoke_request); + EXPECT_TRUE(invoke_outcome.IsSuccess()); Aws::StringStream output; - if (!invokeOutcome.IsSuccess()) { + if (!invoke_outcome.IsSuccess()) { delete_function(funcname); return; } - EXPECT_EQ(200, invokeOutcome.GetResult().GetStatusCode()); - EXPECT_TRUE(invokeOutcome.GetResult().GetFunctionError().empty()); - auto const jsonResponse = Aws::Utils::Json::JsonValue(invokeOutcome.GetResult().GetPayload()); - EXPECT_TRUE(jsonResponse.WasParseSuccessful()); - EXPECT_STREQ(payloadContent, jsonResponse.View().GetString("UnicodeText").c_str()); + EXPECT_EQ(200, invoke_outcome.GetResult().GetStatusCode()); + EXPECT_TRUE(invoke_outcome.GetResult().GetFunctionError().empty()); + auto const json_response = Aws::Utils::Json::JsonValue(invoke_outcome.GetResult().GetPayload()); + EXPECT_TRUE(json_response.WasParseSuccessful()); + EXPECT_STREQ(payload_content, json_response.View().GetString("UnicodeText").c_str()); delete_function(funcname); } @@ -163,14 +164,14 @@ TEST_F(LambdaRuntimeTest, echo_failure) { Aws::String const funcname = build_resource_name("echo_failure"); create_function(funcname, "echo_failure" /*handler_name*/); - Model::InvokeRequest invokeRequest; - invokeRequest.SetFunctionName(funcname); - invokeRequest.SetInvocationType(Model::InvocationType::RequestResponse); - - Model::InvokeOutcome invokeOutcome = m_lambda_client.Invoke(invokeRequest); - EXPECT_TRUE(invokeOutcome.IsSuccess()); - EXPECT_EQ(200, invokeOutcome.GetResult().GetStatusCode()); - EXPECT_STREQ("Unhandled", invokeOutcome.GetResult().GetFunctionError().c_str()); + Model::InvokeRequest invoke_request; + invoke_request.SetFunctionName(funcname); + invoke_request.SetInvocationType(Model::InvocationType::RequestResponse); + + Model::InvokeOutcome invoke_outcome = m_lambda_client.Invoke(invoke_request); + EXPECT_TRUE(invoke_outcome.IsSuccess()); + EXPECT_EQ(200, invoke_outcome.GetResult().GetStatusCode()); + EXPECT_STREQ("Unhandled", invoke_outcome.GetResult().GetFunctionError().c_str()); delete_function(funcname); } @@ -179,15 +180,15 @@ TEST_F(LambdaRuntimeTest, binary_response) Aws::String const funcname = build_resource_name("binary_response"); unsigned long constexpr expected_length = 1451; create_function(funcname, "binary_response" /*handler_name*/); - Model::InvokeRequest invokeRequest; - invokeRequest.SetFunctionName(funcname); - invokeRequest.SetInvocationType(Model::InvocationType::RequestResponse); - - Model::InvokeOutcome invokeOutcome = m_lambda_client.Invoke(invokeRequest); - EXPECT_TRUE(invokeOutcome.IsSuccess()); - EXPECT_EQ(200, invokeOutcome.GetResult().GetStatusCode()); - EXPECT_TRUE(invokeOutcome.GetResult().GetFunctionError().empty()); - EXPECT_EQ(expected_length, invokeOutcome.GetResult().GetPayload().tellp()); + Model::InvokeRequest invoke_request; + invoke_request.SetFunctionName(funcname); + invoke_request.SetInvocationType(Model::InvocationType::RequestResponse); + + Model::InvokeOutcome invoke_outcome = m_lambda_client.Invoke(invoke_request); + EXPECT_TRUE(invoke_outcome.IsSuccess()); + EXPECT_EQ(200, invoke_outcome.GetResult().GetStatusCode()); + EXPECT_TRUE(invoke_outcome.GetResult().GetFunctionError().empty()); + EXPECT_EQ(expected_length, invoke_outcome.GetResult().GetPayload().tellp()); delete_function(funcname); } } // namespace From 4e4f4cccdabdd5f7ead751b9a6019cfebe545bd1 Mon Sep 17 00:00:00 2001 From: Bryan Moffatt Date: Sat, 4 Apr 2020 04:53:42 +0100 Subject: [PATCH 29/84] use platform auto-detection in backward.h (#89) --- src/backward.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backward.h b/src/backward.h index e065783..940116e 100644 --- a/src/backward.h +++ b/src/backward.h @@ -43,7 +43,7 @@ // You can define one of the following (or leave it to the auto-detection): // -# define BACKWARD_SYSTEM_LINUX +// #define BACKWARD_SYSTEM_LINUX // - specialization for linux // // #define BACKWARD_SYSTEM_DARWIN From fe55d84c808243baf48468369e98e09018e959a3 Mon Sep 17 00:00:00 2001 From: Marco Magdy Date: Thu, 21 May 2020 17:17:37 -0700 Subject: [PATCH 30/84] Update backward lib (#94) binutils 2.34 changed the name of a function and guarded it with a macro. This backward-lib update makes use of that macro to choose the right function name. Fixes #93 --- src/backward.h | 1392 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 981 insertions(+), 411 deletions(-) diff --git a/src/backward.h b/src/backward.h index 940116e..e9e56c7 100644 --- a/src/backward.h +++ b/src/backward.h @@ -1,3 +1,4 @@ +// clang-format off /* * backward.hpp * Copyright 2013 Google Inc. All Rights Reserved. @@ -22,28 +23,28 @@ */ #ifndef H_6B9572DA_A64B_49E6_B234_051480991C89 -# define H_6B9572DA_A64B_49E6_B234_051480991C89 - -# ifndef __cplusplus -# error "It's not going to compile without a C++ compiler..." -# endif - -# if defined(BACKWARD_CXX11) -# elif defined(BACKWARD_CXX98) +#define H_6B9572DA_A64B_49E6_B234_051480991C89 + +#ifndef __cplusplus +# error "It's not going to compile without a C++ compiler..." +#endif + +#if defined(BACKWARD_CXX11) +#elif defined(BACKWARD_CXX98) +#else +# if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1800) +# define BACKWARD_CXX11 +# define BACKWARD_ATLEAST_CXX11 +# define BACKWARD_ATLEAST_CXX98 # else -# if __cplusplus >= 201103L -# define BACKWARD_CXX11 -# define BACKWARD_ATLEAST_CXX11 -# define BACKWARD_ATLEAST_CXX98 -# else -# define BACKWARD_CXX98 -# define BACKWARD_ATLEAST_CXX98 -# endif +# define BACKWARD_CXX98 +# define BACKWARD_ATLEAST_CXX98 # endif +#endif // You can define one of the following (or leave it to the auto-detection): // -// #define BACKWARD_SYSTEM_LINUX +// #define BACKWARD_SYSTEM_LINUX // - specialization for linux // // #define BACKWARD_SYSTEM_DARWIN @@ -52,35 +53,40 @@ // #define BACKWARD_SYSTEM_UNKNOWN // - placebo implementation, does nothing. // -# if defined(BACKWARD_SYSTEM_LINUX) -# elif defined(BACKWARD_SYSTEM_DARWIN) -# elif defined(BACKWARD_SYSTEM_UNKNOWN) +#if defined(BACKWARD_SYSTEM_LINUX) +#elif defined(BACKWARD_SYSTEM_DARWIN) +#elif defined(BACKWARD_SYSTEM_UNKNOWN) +#elif defined(BACKWARD_SYSTEM_WINDOWS) +#else +# if defined(__linux) || defined(__linux__) +# define BACKWARD_SYSTEM_LINUX +# elif defined(__APPLE__) +# define BACKWARD_SYSTEM_DARWIN +# elif defined(_WIN32) +# define BACKWARD_SYSTEM_WINDOWS # else -# if defined(__linux) || defined(__linux__) -# define BACKWARD_SYSTEM_LINUX -# elif defined(__APPLE__) -# define BACKWARD_SYSTEM_DARWIN -# else -# define BACKWARD_SYSTEM_UNKNOWN -# endif +# define BACKWARD_SYSTEM_UNKNOWN # endif - -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include - -# if defined(BACKWARD_SYSTEM_LINUX) +#endif + +#define NOINLINE __attribute__((noinline)) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BACKWARD_SYSTEM_LINUX) // On linux, backtrace can back-trace or "walk" the stack using the following // libraries: @@ -103,14 +109,14 @@ // // Note that only one of the define should be set to 1 at a time. // -# if BACKWARD_HAS_UNWIND == 1 -# elif BACKWARD_HAS_BACKTRACE == 1 -# else -# undef BACKWARD_HAS_UNWIND -# define BACKWARD_HAS_UNWIND 1 -# undef BACKWARD_HAS_BACKTRACE -# define BACKWARD_HAS_BACKTRACE 0 -# endif +# if BACKWARD_HAS_UNWIND == 1 +# elif BACKWARD_HAS_BACKTRACE == 1 +# else +# undef BACKWARD_HAS_UNWIND +# define BACKWARD_HAS_UNWIND 1 +# undef BACKWARD_HAS_BACKTRACE +# define BACKWARD_HAS_BACKTRACE 0 +# endif // On linux, backward can extract detailed information about a stack trace // using one of the following libraries: @@ -161,86 +167,87 @@ // // Note that only one of the define should be set to 1 at a time. // -# if BACKWARD_HAS_DW == 1 -# elif BACKWARD_HAS_BFD == 1 -# elif BACKWARD_HAS_DWARF == 1 -# elif BACKWARD_HAS_BACKTRACE_SYMBOL == 1 -# else -# undef BACKWARD_HAS_DW -# define BACKWARD_HAS_DW 0 -# undef BACKWARD_HAS_BFD -# define BACKWARD_HAS_BFD 0 -# undef BACKWARD_HAS_DWARF -# define BACKWARD_HAS_DWARF 0 -# undef BACKWARD_HAS_BACKTRACE_SYMBOL -# define BACKWARD_HAS_BACKTRACE_SYMBOL 1 -# endif +# if BACKWARD_HAS_DW == 1 +# elif BACKWARD_HAS_BFD == 1 +# elif BACKWARD_HAS_DWARF == 1 +# elif BACKWARD_HAS_BACKTRACE_SYMBOL == 1 +# else +# undef BACKWARD_HAS_DW +# define BACKWARD_HAS_DW 0 +# undef BACKWARD_HAS_BFD +# define BACKWARD_HAS_BFD 0 +# undef BACKWARD_HAS_DWARF +# define BACKWARD_HAS_DWARF 0 +# undef BACKWARD_HAS_BACKTRACE_SYMBOL +# define BACKWARD_HAS_BACKTRACE_SYMBOL 1 +# endif -# include -# include -# ifdef __ANDROID__ -// Old Android API levels define _Unwind_Ptr in both link.h and unwind.h -// Rename the one in link.h as we are not going to be using it -# define _Unwind_Ptr _Unwind_Ptr_Custom -# include -# undef _Unwind_Ptr -# else -# include -# endif -# include -# include -# include -# include +# include +# include +# ifdef __ANDROID__ +// Old Android API levels define _Unwind_Ptr in both link.h and +// unwind.h Rename the one in link.h as we are not going to be using +// it +# define _Unwind_Ptr _Unwind_Ptr_Custom +# include +# undef _Unwind_Ptr +# else +# include +# endif +# include +# include +# include +# include -# if BACKWARD_HAS_BFD == 1 +# if BACKWARD_HAS_BFD == 1 // NOTE: defining PACKAGE{,_VERSION} is required before including // bfd.h on some platforms, see also: // https://sourceware.org/bugzilla/show_bug.cgi?id=14243 -# ifndef PACKAGE -# define PACKAGE -# endif -# ifndef PACKAGE_VERSION -# define PACKAGE_VERSION -# endif -# include -# ifndef _GNU_SOURCE -# define _GNU_SOURCE -# include -# undef _GNU_SOURCE -# else -# include -# endif +# ifndef PACKAGE +# define PACKAGE # endif - -# if BACKWARD_HAS_DW == 1 -# include -# include -# include +# ifndef PACKAGE_VERSION +# define PACKAGE_VERSION +# endif +# include +# ifndef _GNU_SOURCE +# define _GNU_SOURCE +# include +# undef _GNU_SOURCE +# else +# include # endif +# endif + +# if BACKWARD_HAS_DW == 1 +# include +# include +# include +# endif -# if BACKWARD_HAS_DWARF == 1 -# include -# include -# include -# include -# include -# ifndef _GNU_SOURCE -# define _GNU_SOURCE -# include -# undef _GNU_SOURCE -# else -# include -# endif +# if BACKWARD_HAS_DWARF == 1 +# include +# include +# include +# include +# include +# ifndef _GNU_SOURCE +# define _GNU_SOURCE +# include +# undef _GNU_SOURCE +# else +# include # endif +# endif -# if (BACKWARD_HAS_BACKTRACE == 1) || (BACKWARD_HAS_BACKTRACE_SYMBOL == 1) +# if (BACKWARD_HAS_BACKTRACE == 1) || (BACKWARD_HAS_BACKTRACE_SYMBOL == 1) // then we shall rely on backtrace -# include -# endif +# include +# endif -# endif // defined(BACKWARD_SYSTEM_LINUX) +#endif // defined(BACKWARD_SYSTEM_LINUX) -# if defined(BACKWARD_SYSTEM_DARWIN) +#if defined(BACKWARD_SYSTEM_DARWIN) // On Darwin, backtrace can back-trace or "walk" the stack using the following // libraries: // @@ -252,22 +259,22 @@ // - normally libgcc is already linked to your program by default. // // #define BACKWARD_HAS_BACKTRACE == 1 -// - backtrace is available by default, though it does not produce as much information -// as another library might. +// - backtrace is available by default, though it does not produce as much +// information as another library might. // // The default is: // #define BACKWARD_HAS_UNWIND == 1 // // Note that only one of the define should be set to 1 at a time. // -# if BACKWARD_HAS_UNWIND == 1 -# elif BACKWARD_HAS_BACKTRACE == 1 -# else -# undef BACKWARD_HAS_UNWIND -# define BACKWARD_HAS_UNWIND 1 -# undef BACKWARD_HAS_BACKTRACE -# define BACKWARD_HAS_BACKTRACE 0 -# endif +# if BACKWARD_HAS_UNWIND == 1 +# elif BACKWARD_HAS_BACKTRACE == 1 +# else +# undef BACKWARD_HAS_UNWIND +# define BACKWARD_HAS_UNWIND 1 +# undef BACKWARD_HAS_BACKTRACE +# define BACKWARD_HAS_BACKTRACE 0 +# endif // On Darwin, backward can extract detailed information about a stack trace // using one of the following libraries: @@ -280,27 +287,70 @@ // The default is: // #define BACKWARD_HAS_BACKTRACE_SYMBOL == 1 // -# if BACKWARD_HAS_BACKTRACE_SYMBOL == 1 -# else -# undef BACKWARD_HAS_BACKTRACE_SYMBOL -# define BACKWARD_HAS_BACKTRACE_SYMBOL 1 -# endif +# if BACKWARD_HAS_BACKTRACE_SYMBOL == 1 +# else +# undef BACKWARD_HAS_BACKTRACE_SYMBOL +# define BACKWARD_HAS_BACKTRACE_SYMBOL 1 +# endif -# include -# include -# include -# include -# include -# include +# include +# include +# include +# include +# include +# include -# if (BACKWARD_HAS_BACKTRACE == 1) || (BACKWARD_HAS_BACKTRACE_SYMBOL == 1) -# include -# endif -# endif // defined(BACKWARD_SYSTEM_DARWIN) +# if (BACKWARD_HAS_BACKTRACE == 1) || (BACKWARD_HAS_BACKTRACE_SYMBOL == 1) +# include +# endif +#endif // defined(BACKWARD_SYSTEM_DARWIN) -# if BACKWARD_HAS_UNWIND == 1 +#if defined(BACKWARD_SYSTEM_WINDOWS) + +# include +# include +# include + +# include +typedef SSIZE_T ssize_t; + +# define NOMINMAX +# include +# include + +# include +# include + +# ifndef __clang__ +# undef NOINLINE +# define NOINLINE __declspec(noinline) +# endif + +# pragma comment(lib, "psapi.lib") +# pragma comment(lib, "dbghelp.lib") + +// Comment / packing is from stackoverflow: +// https://stackoverflow.com/questions/6205981/windows-c-stack-trace-from-a-running-app/28276227#28276227 +// Some versions of imagehlp.dll lack the proper packing directives themselves +// so we need to do it. +# pragma pack(push, before_imagehlp, 8) +# include +# pragma pack(pop, before_imagehlp) + +// TODO maybe these should be undefined somewhere else? +# undef BACKWARD_HAS_UNWIND +# undef BACKWARD_HAS_BACKTRACE +# if BACKWARD_HAS_PDB_SYMBOL == 1 +# else +# undef BACKWARD_HAS_PDB_SYMBOL +# define BACKWARD_HAS_PDB_SYMBOL 1 +# endif -# include +#endif + +#if BACKWARD_HAS_UNWIND == 1 + +# include // while gcc's unwind.h defines something like that: // extern _Unwind_Ptr _Unwind_GetIP (struct _Unwind_Context *); // extern _Unwind_Ptr _Unwind_GetIPInfo (struct _Unwind_Context *, int *); @@ -313,18 +363,18 @@ // anyway. // // Luckily we can play on the fact that the guard macros have a different name: -# ifdef __CLANG_UNWIND_H +# ifdef __CLANG_UNWIND_H // In fact, this function still comes from libgcc (on my different linux boxes, // clang links against libgcc). -# include +# include extern "C" uintptr_t _Unwind_GetIPInfo(_Unwind_Context*, int*); -# endif +# endif -# endif // BACKWARD_HAS_UNWIND == 1 +#endif // BACKWARD_HAS_UNWIND == 1 -# ifdef BACKWARD_ATLEAST_CXX11 -# include -# include // for std::swap +#ifdef BACKWARD_ATLEAST_CXX11 +# include +# include // for std::swap namespace backward { namespace details { template @@ -334,10 +384,10 @@ struct hashtable { using std::move; } // namespace details } // namespace backward -# else // NOT BACKWARD_ATLEAST_CXX11 -# define nullptr NULL -# define override -# include +#else // NOT BACKWARD_ATLEAST_CXX11 +# define nullptr NULL +# define override +# include namespace backward { namespace details { template @@ -356,7 +406,17 @@ T& move(T& v) } } // namespace details } // namespace backward -# endif // BACKWARD_ATLEAST_CXX11 +#endif // BACKWARD_ATLEAST_CXX11 + +namespace backward { +namespace details { +#if defined(BACKWARD_SYSTEM_WINDOWS) +const char kBackwardPathDelimiter[] = ";"; +#else +const char kBackwardPathDelimiter[] = ":"; +#endif +} // namespace details +} // namespace backward namespace backward { @@ -364,46 +424,56 @@ namespace system_tag { struct linux_tag; // seems that I cannot call that "linux" because the name // is already defined... so I am adding _tag everywhere. struct darwin_tag; +struct windows_tag; struct unknown_tag; -# if defined(BACKWARD_SYSTEM_LINUX) +#if defined(BACKWARD_SYSTEM_LINUX) typedef linux_tag current_tag; -# elif defined(BACKWARD_SYSTEM_DARWIN) +#elif defined(BACKWARD_SYSTEM_DARWIN) typedef darwin_tag current_tag; -# elif defined(BACKWARD_SYSTEM_UNKNOWN) +#elif defined(BACKWARD_SYSTEM_WINDOWS) +typedef windows_tag current_tag; +#elif defined(BACKWARD_SYSTEM_UNKNOWN) typedef unknown_tag current_tag; -# else -# error "May I please get my system defines?" -# endif +#else +# error "May I please get my system defines?" +#endif } // namespace system_tag namespace trace_resolver_tag { -# if defined(BACKWARD_SYSTEM_LINUX) +#if defined(BACKWARD_SYSTEM_LINUX) struct libdw; struct libbfd; struct libdwarf; struct backtrace_symbol; -# if BACKWARD_HAS_DW == 1 +# if BACKWARD_HAS_DW == 1 typedef libdw current; -# elif BACKWARD_HAS_BFD == 1 +# elif BACKWARD_HAS_BFD == 1 typedef libbfd current; -# elif BACKWARD_HAS_DWARF == 1 +# elif BACKWARD_HAS_DWARF == 1 typedef libdwarf current; -# elif BACKWARD_HAS_BACKTRACE_SYMBOL == 1 +# elif BACKWARD_HAS_BACKTRACE_SYMBOL == 1 typedef backtrace_symbol current; -# else -# error "You shall not pass, until you know what you want." -# endif -# elif defined(BACKWARD_SYSTEM_DARWIN) +# else +# error "You shall not pass, until you know what you want." +# endif +#elif defined(BACKWARD_SYSTEM_DARWIN) struct backtrace_symbol; -# if BACKWARD_HAS_BACKTRACE_SYMBOL == 1 +# if BACKWARD_HAS_BACKTRACE_SYMBOL == 1 typedef backtrace_symbol current; -# else -# error "You shall not pass, until you know what you want." -# endif +# else +# error "You shall not pass, until you know what you want." +# endif +#elif defined(BACKWARD_SYSTEM_WINDOWS) +struct pdb_symbol; +# if BACKWARD_HAS_PDB_SYMBOL == 1 +typedef pdb_symbol current; +# else +# error "You shall not pass, until you know what you want." # endif +#endif } // namespace trace_resolver_tag namespace details { @@ -443,10 +513,10 @@ class handle { T _val; bool _empty; -# ifdef BACKWARD_ATLEAST_CXX11 +#ifdef BACKWARD_ATLEAST_CXX11 handle(const handle&) = delete; handle& operator=(const handle&) = delete; -# endif +#endif public: ~handle() @@ -463,14 +533,14 @@ class handle { _empty = true; } -# ifdef BACKWARD_ATLEAST_CXX11 +#ifdef BACKWARD_ATLEAST_CXX11 handle(handle&& from) : _empty(true) { swap(from); } handle& operator=(handle&& from) { swap(from); return *this; } -# else +#else explicit handle(const handle& from) : _empty(true) { // some sort of poor man's move semantic. @@ -482,13 +552,20 @@ class handle { swap(const_cast(from)); return *this; } -# endif +#endif void reset(T new_val) { handle tmp(new_val); swap(tmp); } + + void update(T new_val) + { + _val = new_val; + _empty = static_cast(new_val); + } + operator const dummy*() const { if (_empty) { @@ -510,7 +587,7 @@ class handle { // bools without throwing... It's a lost cause anyway! } - T operator->() { return _val; } + T& operator->() { return _val; } const T& operator->() const { return _val; } typedef typename rm_ptr::type& ref_t; @@ -533,7 +610,7 @@ struct demangler_impl { static std::string demangle(const char* funcname) { return funcname; } }; -# if defined(BACKWARD_SYSTEM_LINUX) || defined(BACKWARD_SYSTEM_DARWIN) +#if defined(BACKWARD_SYSTEM_LINUX) || defined(BACKWARD_SYSTEM_DARWIN) template <> struct demangler_impl { @@ -542,9 +619,9 @@ struct demangler_impl { std::string demangle(const char* funcname) { using namespace details; - char* result = abi::__cxa_demangle(funcname, _demangle_buffer.release(), &_demangle_buffer_length, nullptr); + char* result = abi::__cxa_demangle(funcname, _demangle_buffer.get(), &_demangle_buffer_length, nullptr); if (result) { - _demangle_buffer.reset(result); + _demangle_buffer.update(result); return result; } return funcname; @@ -555,11 +632,35 @@ struct demangler_impl { size_t _demangle_buffer_length; }; -# endif // BACKWARD_SYSTEM_LINUX || BACKWARD_SYSTEM_DARWIN +#endif // BACKWARD_SYSTEM_LINUX || BACKWARD_SYSTEM_DARWIN struct demangler : public demangler_impl { }; +// Split a string on the platform's PATH delimiter. Example: if delimiter +// is ":" then: +// "" --> [] +// ":" --> ["",""] +// "::" --> ["","",""] +// "/a/b/c" --> ["/a/b/c"] +// "/a/b/c:/d/e/f" --> ["/a/b/c","/d/e/f"] +// etc. +inline std::vector split_source_prefixes(const std::string& s) +{ + std::vector out; + size_t last = 0; + size_t next = 0; + size_t delimiter_size = sizeof(kBackwardPathDelimiter) - 1; + while ((next = s.find(kBackwardPathDelimiter, last)) != std::string::npos) { + out.push_back(s.substr(last, next - last)); + last = next + delimiter_size; + } + if (last <= s.length()) { + out.push_back(s.substr(last)); + } + return out; +} + } // namespace details /*************** A TRACE ***************/ @@ -621,7 +722,7 @@ template class StackTraceImpl { public: size_t size() const { return 0; } - Trace operator[](size_t) { return Trace(); } + Trace operator[](size_t) const { return Trace(); } size_t load_here(size_t = 0) { return 0; } size_t load_from(void*, size_t = 0) { return 0; } size_t thread_id() const { return 0; } @@ -639,24 +740,24 @@ class StackTraceImplBase { protected: void load_thread_info() { -# ifdef BACKWARD_SYSTEM_LINUX -# ifndef __ANDROID__ +#ifdef BACKWARD_SYSTEM_LINUX +# ifndef __ANDROID__ _thread_id = static_cast(syscall(SYS_gettid)); -# else +# else _thread_id = static_cast(gettid()); -# endif +# endif if (_thread_id == static_cast(getpid())) { // If the thread is the main one, let's hide that. // I like to keep little secret sometimes. _thread_id = 0; } -# elif defined(BACKWARD_SYSTEM_DARWIN) +#elif defined(BACKWARD_SYSTEM_DARWIN) _thread_id = reinterpret_cast(pthread_self()); if (pthread_main_np() == 1) { // If the thread is the main one, let's hide that. _thread_id = 0; } -# endif +#endif } size_t skip_n_firsts() const { return _skip; } @@ -688,7 +789,7 @@ class StackTraceImplHolder : public StackTraceImplBase { std::vector _stacktrace; }; -# if BACKWARD_HAS_UNWIND == 1 +#if BACKWARD_HAS_UNWIND == 1 namespace details { @@ -723,12 +824,15 @@ class Unwinder { uintptr_t ip = _Unwind_GetIPInfo(ctx, &ip_before_instruction); if (!ip_before_instruction) { - // calculating 0-1 for unsigned, looks like a possible bug to sanitiziers, so let's do it explicitly: + // calculating 0-1 for unsigned, looks like a possible bug to sanitiziers, + // so let's do it explicitly: if (ip == 0) { - ip = std::numeric_limits::max(); // set it to 0xffff... (as from casting 0-1) + ip = std::numeric_limits::max(); // set it to 0xffff... (as + // from casting 0-1) } else { - ip -= 1; // else just normally decrement it (no overflow/underflow will happen) + ip -= 1; // else just normally decrement it (no overflow/underflow will + // happen) } } @@ -752,9 +856,8 @@ size_t unwind(F f, size_t depth) template <> class StackTraceImpl : public StackTraceImplHolder { public: - __attribute__((noinline)) // TODO use some macro - size_t - load_here(size_t depth = 32) + NOINLINE + size_t load_here(size_t depth = 32) { load_thread_info(); if (depth == 0) { @@ -790,14 +893,13 @@ class StackTraceImpl : public StackTraceImplHolder { }; }; -# else // BACKWARD_HAS_UNWIND == 0 +#elif defined(BACKWARD_HAS_BACKTRACE) template <> class StackTraceImpl : public StackTraceImplHolder { public: - __attribute__((noinline)) // TODO use some macro - size_t - load_here(size_t depth = 32) + NOINLINE + size_t load_here(size_t depth = 32) { load_thread_info(); if (depth == 0) { @@ -827,7 +929,104 @@ class StackTraceImpl : public StackTraceImplHolder { } }; -# endif // BACKWARD_HAS_UNWIND +#elif defined(BACKWARD_SYSTEM_WINDOWS) + +template <> +class StackTraceImpl : public StackTraceImplHolder { +public: + // We have to load the machine type from the image info + // So we first initialize the resolver, and it tells us this info + void set_machine_type(DWORD machine_type) { machine_type_ = machine_type; } + void set_context(CONTEXT* ctx) { ctx_ = ctx; } + void set_thread_handle(HANDLE handle) { thd_ = handle; } + + NOINLINE + size_t load_here(size_t depth = 32) + { + + CONTEXT localCtx; // used when no context is provided + + if (depth == 0) { + return 0; + } + + if (!ctx_) { + ctx_ = &localCtx; + RtlCaptureContext(ctx_); + } + + if (!thd_) { + thd_ = GetCurrentThread(); + } + + HANDLE process = GetCurrentProcess(); + + STACKFRAME64 s; + memset(&s, 0, sizeof(STACKFRAME64)); + + // TODO: 32 bit context capture + s.AddrStack.Mode = AddrModeFlat; + s.AddrFrame.Mode = AddrModeFlat; + s.AddrPC.Mode = AddrModeFlat; +# ifdef _M_X64 + s.AddrPC.Offset = ctx_->Rip; + s.AddrStack.Offset = ctx_->Rsp; + s.AddrFrame.Offset = ctx_->Rbp; +# else + s.AddrPC.Offset = ctx_->Eip; + s.AddrStack.Offset = ctx_->Esp; + s.AddrFrame.Offset = ctx_->Ebp; +# endif + + if (!machine_type_) { +# ifdef _M_X64 + machine_type_ = IMAGE_FILE_MACHINE_AMD64; +# else + machine_type_ = IMAGE_FILE_MACHINE_I386; +# endif + } + + for (;;) { + // NOTE: this only works if PDBs are already loaded! + SetLastError(0); + if (!StackWalk64( + machine_type_, process, thd_, &s, ctx_, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL)) + break; + + if (s.AddrReturn.Offset == 0) + break; + + _stacktrace.push_back(reinterpret_cast(s.AddrPC.Offset)); + + if (size() >= depth) + break; + } + + return size(); + } + + size_t load_from(void* addr, size_t depth = 32) + { + load_here(depth + 8); + + for (size_t i = 0; i < _stacktrace.size(); ++i) { + if (_stacktrace[i] == addr) { + skip_n_firsts(i); + break; + } + } + + _stacktrace.resize(std::min(_stacktrace.size(), skip_n_firsts() + depth)); + return size(); + } + +private: + DWORD machine_type_ = 0; + HANDLE thd_ = 0; + CONTEXT* ctx_ = nullptr; +}; + +#endif class StackTrace : public StackTraceImpl { }; @@ -837,7 +1036,7 @@ class StackTrace : public StackTraceImpl { template class TraceResolverImpl; -# ifdef BACKWARD_SYSTEM_UNKNOWN +#ifdef BACKWARD_SYSTEM_UNKNOWN template <> class TraceResolverImpl { @@ -849,7 +1048,7 @@ class TraceResolverImpl { ResolvedTrace resolve(ResolvedTrace t) { return t; } }; -# endif +#endif class TraceResolverImplBase { protected: @@ -859,15 +1058,72 @@ class TraceResolverImplBase { details::demangler _demangler; }; -# ifdef BACKWARD_SYSTEM_LINUX +#ifdef BACKWARD_SYSTEM_LINUX + +class TraceResolverLinuxBase : public TraceResolverImplBase { +public: + TraceResolverLinuxBase() : argv0_(get_argv0()), exec_path_(read_symlink("/proc/self/exe")) {} + std::string resolve_exec_path(Dl_info& symbol_info) const + { + // mutates symbol_info.dli_fname to be filename to open and returns filename + // to display + if (symbol_info.dli_fname == argv0_) { + // dladdr returns argv[0] in dli_fname for symbols contained in + // the main executable, which is not a valid path if the + // executable was found by a search of the PATH environment + // variable; In that case, we actually open /proc/self/exe, which + // is always the actual executable (even if it was deleted/replaced!) + // but display the path that /proc/self/exe links to. + symbol_info.dli_fname = "/proc/self/exe"; + return exec_path_; + } + else { + return symbol_info.dli_fname; + } + } + +private: + std::string argv0_; + std::string exec_path_; + + static std::string get_argv0() + { + std::string argv0; + std::ifstream ifs("/proc/self/cmdline"); + std::getline(ifs, argv0, '\0'); + return argv0; + } + + static std::string read_symlink(std::string const& symlink_path) + { + std::string path; + path.resize(100); + + while (true) { + ssize_t len = ::readlink(symlink_path.c_str(), &*path.begin(), path.size()); + if (len < 0) { + return ""; + } + if (static_cast(len) == path.size()) { + path.resize(path.size() * 2); + } + else { + path.resize(static_cast(len)); + break; + } + } + + return path; + } +}; template class TraceResolverLinuxImpl; -# if BACKWARD_HAS_BACKTRACE_SYMBOL == 1 +# if BACKWARD_HAS_BACKTRACE_SYMBOL == 1 template <> -class TraceResolverLinuxImpl : public TraceResolverImplBase { +class TraceResolverLinuxImpl : public TraceResolverLinuxBase { public: template void load_stacktrace(ST& st) @@ -886,8 +1142,10 @@ class TraceResolverLinuxImpl : public Trac while (*funcname && *funcname != '(') { funcname += 1; } - trace.object_filename.assign(filename, funcname); // ok even if funcname is the ending \0 (then we assign entire - // string) + trace.object_filename.assign( + filename, + funcname); // ok even if funcname is the ending + // \0 (then we assign entire string) if (*funcname) { // if it's not end of string (e.g. from last frame ip==0) funcname += 1; @@ -906,34 +1164,12 @@ class TraceResolverLinuxImpl : public Trac details::handle _symbols; }; -# endif // BACKWARD_HAS_BACKTRACE_SYMBOL == 1 +# endif // BACKWARD_HAS_BACKTRACE_SYMBOL == 1 -# if BACKWARD_HAS_BFD == 1 +# if BACKWARD_HAS_BFD == 1 template <> -class TraceResolverLinuxImpl : public TraceResolverImplBase { - static std::string read_symlink(std::string const& symlink_path) - { - std::string path; - path.resize(100); - - while (true) { - ssize_t len = ::readlink(symlink_path.c_str(), &*path.begin(), path.size()); - if (len < 0) { - return ""; - } - if (static_cast(len) == path.size()) { - path.resize(path.size() * 2); - } - else { - path.resize(static_cast(len)); - break; - } - } - - return path; - } - +class TraceResolverLinuxImpl : public TraceResolverLinuxBase { public: TraceResolverLinuxImpl() : _bfd_loaded(false) {} @@ -953,17 +1189,6 @@ class TraceResolverLinuxImpl : public TraceResolverI return trace; // dat broken trace... } - std::string argv0; - { - std::ifstream ifs("/proc/self/cmdline"); - std::getline(ifs, argv0, '\0'); - } - std::string tmp; - if (symbol_info.dli_fname == argv0) { - tmp = read_symlink("/proc/self/exe"); - symbol_info.dli_fname = tmp.c_str(); - } - // Now we get in symbol_info: // .dli_fname: // pathname of the shared object that contains the address. @@ -983,7 +1208,7 @@ class TraceResolverLinuxImpl : public TraceResolverI return trace; } - trace.object_filename = symbol_info.dli_fname; + trace.object_filename = resolve_exec_path(symbol_info); bfd_fileobject& fobj = load_object_with_bfd(symbol_info.dli_fname); if (!fobj.handle) { return trace; // sad, we couldn't load the object :( @@ -999,7 +1224,7 @@ class TraceResolverLinuxImpl : public TraceResolverI find_sym_result details_call_site = find_symbol_details(fobj, trace.addr, symbol_info.dli_fbase); details_selected = &details_call_site; -# if BACKWARD_HAS_UNWIND == 0 +# if BACKWARD_HAS_UNWIND == 0 // ...this is why we also try to resolve the symbol that is right // before the return address. If we are lucky enough, we will get the // line of the function that was called. But if the code is optimized, @@ -1023,7 +1248,7 @@ class TraceResolverLinuxImpl : public TraceResolverI // thereafter... details_call_site = find_symbol_details(fobj, trace.addr, symbol_info.dli_fbase); } -# endif // BACKWARD_HAS_UNWIND +# endif // BACKWARD_HAS_UNWIND if (details_selected->found) { if (details_selected->filename) { @@ -1052,7 +1277,7 @@ class TraceResolverLinuxImpl : public TraceResolverI // calls along the way up to the initial call site. trace.inliners = backtrace_inliners(fobj, *details_selected); -# if 0 +# if 0 if (trace.inliners.size() == 0) { // Maybe the trace was not inlined... or maybe it was and we // are lacking the debug information. Let's try to make the @@ -1094,7 +1319,7 @@ class TraceResolverLinuxImpl : public TraceResolverI } } } -# endif +# endif } return trace; @@ -1232,11 +1457,23 @@ class TraceResolverLinuxImpl : public TraceResolverI if (result.found) return; +# ifdef bfd_get_section_flags if ((bfd_get_section_flags(fobj.handle.get(), section) & SEC_ALLOC) == 0) +# else + if ((bfd_section_flags(section) & SEC_ALLOC) == 0) +# endif return; // a debug section is never loaded automatically. +# ifdef bfd_get_section_vma bfd_vma sec_addr = bfd_get_section_vma(fobj.handle.get(), section); +# else + bfd_vma sec_addr = bfd_section_vma(section); +# endif +# ifdef bfd_get_section_size bfd_size_type size = bfd_get_section_size(section); +# else + bfd_size_type size = bfd_section_size(section); +# endif // are we in the boundaries of the section? if (addr < sec_addr || addr >= sec_addr + size) { @@ -1246,10 +1483,10 @@ class TraceResolverLinuxImpl : public TraceResolverI } } -# if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" -# endif +# if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" +# endif if (!result.found && fobj.symtab) { result.found = bfd_find_nearest_line( fobj.handle.get(), @@ -1271,9 +1508,9 @@ class TraceResolverLinuxImpl : public TraceResolverI &result.funcname, &result.line); } -# if defined(__clang__) -# pragma clang diagnostic pop -# endif +# if defined(__clang__) +# pragma clang diagnostic pop +# endif } ResolvedTrace::source_locs_t backtrace_inliners(bfd_fileobject& fobj, find_sym_result previous_result) @@ -1286,10 +1523,11 @@ class TraceResolverLinuxImpl : public TraceResolverI result.found = bfd_find_inliner_info(fobj.handle.get(), &result.filename, &result.funcname, &result.line); if (result.found) /* and not ( - cstrings_eq(previous_result.filename, result.filename) - and cstrings_eq(previous_result.funcname, result.funcname) - and result.line == previous_result.line - )) */ + cstrings_eq(previous_result.filename, + result.filename) and + cstrings_eq(previous_result.funcname, result.funcname) + and result.line == previous_result.line + )) */ { ResolvedTrace::SourceLoc src_loc; src_loc.line = result.line; @@ -1314,12 +1552,12 @@ class TraceResolverLinuxImpl : public TraceResolverI return strcmp(a, b) == 0; } }; -# endif // BACKWARD_HAS_BFD == 1 +# endif // BACKWARD_HAS_BFD == 1 -# if BACKWARD_HAS_DW == 1 +# if BACKWARD_HAS_DW == 1 template <> -class TraceResolverLinuxImpl : public TraceResolverImplBase { +class TraceResolverLinuxImpl : public TraceResolverLinuxBase { public: TraceResolverLinuxImpl() : _dwfl_handle_initialized(false) {} @@ -1392,7 +1630,7 @@ class TraceResolverLinuxImpl : public TraceResolverIm Dwarf_Addr mod_bias = 0; Dwarf_Die* cudie = dwfl_module_addrdie(mod, trace_addr, &mod_bias); -# if 1 +# if 1 if (!cudie) { // Sadly clang does not generate the section .debug_aranges, thus // dwfl_module_addrdie will fail early. Clang doesn't either set @@ -1412,10 +1650,10 @@ class TraceResolverLinuxImpl : public TraceResolverIm } } } -# endif +# endif //#define BACKWARD_I_DO_NOT_RECOMMEND_TO_ENABLE_THIS_HORRIBLE_PIECE_OF_CODE -# ifdef BACKWARD_I_DO_NOT_RECOMMEND_TO_ENABLE_THIS_HORRIBLE_PIECE_OF_CODE +# ifdef BACKWARD_I_DO_NOT_RECOMMEND_TO_ENABLE_THIS_HORRIBLE_PIECE_OF_CODE if (!cudie) { // If it's still not enough, lets dive deeper in the shit, and try // to save the world again: for every compilation unit, we will @@ -1443,7 +1681,7 @@ class TraceResolverLinuxImpl : public TraceResolverIm } } } -# endif +# endif if (!cudie) { return trace; // this time we lost the game :/ @@ -1643,34 +1881,12 @@ class TraceResolverLinuxImpl : public TraceResolverIm return dwarf_filesrc(files, file_idx, 0, 0); } }; -# endif // BACKWARD_HAS_DW == 1 +# endif // BACKWARD_HAS_DW == 1 -# if BACKWARD_HAS_DWARF == 1 +# if BACKWARD_HAS_DWARF == 1 template <> -class TraceResolverLinuxImpl : public TraceResolverImplBase { - static std::string read_symlink(std::string const& symlink_path) - { - std::string path; - path.resize(100); - - while (true) { - ssize_t len = ::readlink(symlink_path.c_str(), &*path.begin(), path.size()); - if (len < 0) { - return ""; - } - if ((size_t)len == path.size()) { - path.resize(path.size() * 2); - } - else { - path.resize(len); - break; - } - } - - return path; - } - +class TraceResolverLinuxImpl : public TraceResolverLinuxBase { public: TraceResolverLinuxImpl() : _dwarf_loaded(false) {} @@ -1687,29 +1903,18 @@ class TraceResolverLinuxImpl : public TraceResolve Dl_info symbol_info; int dladdr_result = 0; -# ifndef __ANDROID__ +# if defined(__GLIBC__) link_map* link_map; // We request the link map so we can get information about offsets dladdr_result = dladdr1(trace.addr, &symbol_info, reinterpret_cast(&link_map), RTLD_DL_LINKMAP); -# else +# else // Android doesn't have dladdr1. Don't use the linker map. dladdr_result = dladdr(trace.addr, &symbol_info); -# endif +# endif if (!dladdr_result) { return trace; // dat broken trace... } - std::string argv0; - { - std::ifstream ifs("/proc/self/cmdline"); - std::getline(ifs, argv0, '\0'); - } - std::string tmp; - if (symbol_info.dli_fname == argv0) { - tmp = read_symlink("/proc/self/exe"); - symbol_info.dli_fname = tmp.c_str(); - } - // Now we get in symbol_info: // .dli_fname: // pathname of the shared object that contains the address. @@ -1736,19 +1941,19 @@ class TraceResolverLinuxImpl : public TraceResolve return trace; } - trace.object_filename = symbol_info.dli_fname; + trace.object_filename = resolve_exec_path(symbol_info); dwarf_fileobject& fobj = load_object_with_dwarf(symbol_info.dli_fname); if (!fobj.dwarf_handle) { return trace; // sad, we couldn't load the object :( } -# ifndef __ANDROID__ +# if defined(__GLIBC__) // Convert the address to a module relative one by looking at // the module's loading address in the link map Dwarf_Addr address = reinterpret_cast(trace.addr) - reinterpret_cast(link_map->l_addr); -# else +# else Dwarf_Addr address = reinterpret_cast(trace.addr); -# endif +# endif if (trace.object_function.empty()) { symbol_cache_t::iterator it = fobj.symbol_cache.lower_bound(address); @@ -1913,7 +2118,7 @@ class TraceResolverLinuxImpl : public TraceResolve dwarf_file_t file_handle; file_handle.reset(open(filename_object.c_str(), O_RDONLY)); - if (file_handle < 0) { + if (file_handle.get() < 0) { return r; } @@ -1950,72 +2155,72 @@ class TraceResolverLinuxImpl : public TraceResolve // We go the preprocessor way to avoid having to create templated // classes or using gelf (which might throw a compiler error if 64 bit // is not supported -# define ELF_GET_DATA(ARCH) \ - Elf_Scn* elf_section = 0; \ - Elf_Data* elf_data = 0; \ - Elf##ARCH##_Shdr* section_header = 0; \ - Elf_Scn* symbol_section = 0; \ - size_t symbol_count = 0; \ - size_t symbol_strings = 0; \ - Elf##ARCH##_Sym* symbol = 0; \ - const char* section_name = 0; \ +# define ELF_GET_DATA(ARCH) \ + Elf_Scn* elf_section = 0; \ + Elf_Data* elf_data = 0; \ + Elf##ARCH##_Shdr* section_header = 0; \ + Elf_Scn* symbol_section = 0; \ + size_t symbol_count = 0; \ + size_t symbol_strings = 0; \ + Elf##ARCH##_Sym* symbol = 0; \ + const char* section_name = 0; \ \ - while ((elf_section = elf_nextscn(elf_handle.get(), elf_section)) != NULL) { \ - section_header = elf##ARCH##_getshdr(elf_section); \ - if (section_header == NULL) { \ - return r; \ - } \ + while ((elf_section = elf_nextscn(elf_handle.get(), elf_section)) != NULL) { \ + section_header = elf##ARCH##_getshdr(elf_section); \ + if (section_header == NULL) { \ + return r; \ + } \ \ - if ((section_name = elf_strptr(elf_handle.get(), shdrstrndx, section_header->sh_name)) == NULL) { \ - return r; \ - } \ + if ((section_name = elf_strptr(elf_handle.get(), shdrstrndx, section_header->sh_name)) == NULL) { \ + return r; \ + } \ \ - if (cstrings_eq(section_name, ".gnu_debuglink")) { \ - elf_data = elf_getdata(elf_section, NULL); \ - if (elf_data && elf_data->d_size > 0) { \ - debuglink = std::string(reinterpret_cast(elf_data->d_buf)); \ - } \ + if (cstrings_eq(section_name, ".gnu_debuglink")) { \ + elf_data = elf_getdata(elf_section, NULL); \ + if (elf_data && elf_data->d_size > 0) { \ + debuglink = std::string(reinterpret_cast(elf_data->d_buf)); \ } \ + } \ + \ + switch (section_header->sh_type) { \ + case SHT_SYMTAB: \ + symbol_section = elf_section; \ + symbol_count = section_header->sh_size / section_header->sh_entsize; \ + symbol_strings = section_header->sh_link; \ + break; \ \ - switch (section_header->sh_type) { \ - case SHT_SYMTAB: \ + /* We use .dynsyms as a last resort, we prefer .symtab */ \ + case SHT_DYNSYM: \ + if (!symbol_section) { \ symbol_section = elf_section; \ symbol_count = section_header->sh_size / section_header->sh_entsize; \ symbol_strings = section_header->sh_link; \ - break; \ - \ - /* We use .dynsyms as a last resort, we prefer .symtab */ \ - case SHT_DYNSYM: \ - if (!symbol_section) { \ - symbol_section = elf_section; \ - symbol_count = section_header->sh_size / section_header->sh_entsize; \ - symbol_strings = section_header->sh_link; \ - } \ - break; \ - } \ + } \ + break; \ } \ + } \ \ - if (symbol_section && symbol_count && symbol_strings) { \ - elf_data = elf_getdata(symbol_section, NULL); \ - symbol = reinterpret_cast(elf_data->d_buf); \ - for (size_t i = 0; i < symbol_count; ++i) { \ - int type = ELF##ARCH##_ST_TYPE(symbol->st_info); \ - if (type == STT_FUNC && symbol->st_value > 0) { \ - r.symbol_cache[symbol->st_value] = \ - std::string(elf_strptr(elf_handle.get(), symbol_strings, symbol->st_name)); \ - } \ - ++symbol; \ + if (symbol_section && symbol_count && symbol_strings) { \ + elf_data = elf_getdata(symbol_section, NULL); \ + symbol = reinterpret_cast(elf_data->d_buf); \ + for (size_t i = 0; i < symbol_count; ++i) { \ + int type = ELF##ARCH##_ST_TYPE(symbol->st_info); \ + if (type == STT_FUNC && symbol->st_value > 0) { \ + r.symbol_cache[symbol->st_value] = \ + std::string(elf_strptr(elf_handle.get(), symbol_strings, symbol->st_name)); \ } \ - } + ++symbol; \ + } \ + } if (e_ident[EI_CLASS] == ELFCLASS32) { ELF_GET_DATA(32) } else if (e_ident[EI_CLASS] == ELFCLASS64) { // libelf might have been built without 64 bit support -# if __LIBELF64 +# if __LIBELF64 ELF_GET_DATA(64) -# endif +# endif } if (!debuglink.empty()) { @@ -3034,15 +3239,15 @@ class TraceResolverLinuxImpl : public TraceResolve return NULL; } }; -# endif // BACKWARD_HAS_DWARF == 1 +# endif // BACKWARD_HAS_DWARF == 1 template <> class TraceResolverImpl : public TraceResolverLinuxImpl { }; -# endif // BACKWARD_SYSTEM_LINUX +#endif // BACKWARD_SYSTEM_LINUX -# ifdef BACKWARD_SYSTEM_DARWIN +#ifdef BACKWARD_SYSTEM_DARWIN template class TraceResolverDarwinImpl; @@ -3105,8 +3310,8 @@ class TraceResolverDarwinImpl : public Tra filename_end = filename + strlen(filename); funcname = filename_end; } - trace.object_filename.assign(filename, filename_end); // ok even if filename_end is the ending \0 (then we - // assign entire string) + trace.object_filename.assign(filename, filename_end); // ok even if filename_end is the ending \0 + // (then we assign entire string) if (*funcname) { // if it's not end of string *funcname_end = '\0'; @@ -3127,7 +3332,140 @@ template <> class TraceResolverImpl : public TraceResolverDarwinImpl { }; -# endif // BACKWARD_SYSTEM_DARWIN +#endif // BACKWARD_SYSTEM_DARWIN + +#ifdef BACKWARD_SYSTEM_WINDOWS + +// Load all symbol info +// Based on: +// https://stackoverflow.com/questions/6205981/windows-c-stack-trace-from-a-running-app/28276227#28276227 + +struct module_data { + std::string image_name; + std::string module_name; + void* base_address; + DWORD load_size; +}; + +class get_mod_info { + HANDLE process; + static const int buffer_length = 4096; + +public: + get_mod_info(HANDLE h) : process(h) {} + + module_data operator()(HMODULE module) + { + module_data ret; + char temp[buffer_length]; + MODULEINFO mi; + + GetModuleInformation(process, module, &mi, sizeof(mi)); + ret.base_address = mi.lpBaseOfDll; + ret.load_size = mi.SizeOfImage; + + GetModuleFileNameEx(process, module, temp, sizeof(temp)); + ret.image_name = temp; + GetModuleBaseName(process, module, temp, sizeof(temp)); + ret.module_name = temp; + std::vector img(ret.image_name.begin(), ret.image_name.end()); + std::vector mod(ret.module_name.begin(), ret.module_name.end()); + SymLoadModule64(process, 0, &img[0], &mod[0], (DWORD64)ret.base_address, ret.load_size); + return ret; + } +}; + +template <> +class TraceResolverImpl { +public: + TraceResolverImpl() + { + + HANDLE process = GetCurrentProcess(); + + std::vector modules; + DWORD cbNeeded; + std::vector module_handles(1); + SymInitialize(process, NULL, false); + DWORD symOptions = SymGetOptions(); + symOptions |= SYMOPT_LOAD_LINES | SYMOPT_UNDNAME; + SymSetOptions(symOptions); + EnumProcessModules(process, &module_handles[0], module_handles.size() * sizeof(HMODULE), &cbNeeded); + module_handles.resize(cbNeeded / sizeof(HMODULE)); + EnumProcessModules(process, &module_handles[0], module_handles.size() * sizeof(HMODULE), &cbNeeded); + std::transform( + module_handles.begin(), module_handles.end(), std::back_inserter(modules), get_mod_info(process)); + void* base = modules[0].base_address; + IMAGE_NT_HEADERS* h = ImageNtHeader(base); + image_type = h->FileHeader.Machine; + } + + template + void load_stacktrace(ST&) + { + } + + static const int max_sym_len = 255; + struct symbol_t { + SYMBOL_INFO sym; + char buffer[max_sym_len]; + } sym; + + DWORD64 displacement; + + ResolvedTrace resolve(ResolvedTrace t) + { + HANDLE process = GetCurrentProcess(); + + char name[256]; + + memset(&sym, 0, sizeof sym); + sym.sym.SizeOfStruct = sizeof(SYMBOL_INFO); + sym.sym.MaxNameLen = max_sym_len; + + if (!SymFromAddr(process, (ULONG64)t.addr, &displacement, &sym.sym)) { + // TODO: error handling everywhere + LPTSTR lpMsgBuf; + DWORD dw = GetLastError(); + + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + dw, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR)&lpMsgBuf, + 0, + NULL); + + printf(lpMsgBuf); + + // abort(); + } + UnDecorateSymbolName(sym.sym.Name, (PSTR)name, 256, UNDNAME_COMPLETE); + + DWORD offset = 0; + IMAGEHLP_LINE line; + if (SymGetLineFromAddr(process, (ULONG64)t.addr, &offset, &line)) { + t.object_filename = line.FileName; + t.source.filename = line.FileName; + t.source.line = line.LineNumber; + t.source.col = offset; + } + + t.source.function = name; + t.object_filename = ""; + t.object_function = name; + + return t; + } + + DWORD machine_type() const { return image_type; } + +private: + DWORD image_type; +}; + +#endif class TraceResolver : public TraceResolverImpl { }; @@ -3139,7 +3477,24 @@ class SourceFile { typedef std::vector> lines_t; SourceFile() {} - SourceFile(const std::string& path) : _file(new std::ifstream(path.c_str())) {} + SourceFile(const std::string& path) + { + // 1. If BACKWARD_CXX_SOURCE_PREFIXES is set then assume it contains + // a colon-separated list of path prefixes. Try prepending each + // to the given path until a valid file is found. + const std::vector& prefixes = get_paths_from_env_variable(); + for (size_t i = 0; i < prefixes.size(); ++i) { + // Double slashes (//) should not be a problem. + std::string new_path = prefixes[i] + '/' + path; + _file.reset(new std::ifstream(new_path.c_str())); + if (is_open()) + break; + } + // 2. If no valid file found then fallback to opening the path as-is. + if (!_file || !is_open()) { + _file.reset(new std::ifstream(path.c_str())); + } + } bool is_open() const { return _file->is_open(); } lines_t& get_lines(unsigned line_start, unsigned line_count, lines_t& lines) @@ -3213,14 +3568,14 @@ class SourceFile { void swap(SourceFile& b) { _file.swap(b._file); } -# ifdef BACKWARD_ATLEAST_CXX11 +#ifdef BACKWARD_ATLEAST_CXX11 SourceFile(SourceFile&& from) : _file(nullptr) { swap(from); } SourceFile& operator=(SourceFile&& from) { swap(from); return *this; } -# else +#else explicit SourceFile(const SourceFile& from) { // some sort of poor man's move semantic. @@ -3232,15 +3587,31 @@ class SourceFile { swap(const_cast(from)); return *this; } -# endif +#endif private: details::handle> _file; -# ifdef BACKWARD_ATLEAST_CXX11 + std::vector get_paths_from_env_variable_impl() + { + std::vector paths; + const char* prefixes_str = std::getenv("BACKWARD_CXX_SOURCE_PREFIXES"); + if (prefixes_str && prefixes_str[0]) { + paths = details::split_source_prefixes(prefixes_str); + } + return paths; + } + + const std::vector& get_paths_from_env_variable() + { + static std::vector paths = get_paths_from_env_variable_impl(); + return paths; + } + +#ifdef BACKWARD_ATLEAST_CXX11 SourceFile(const SourceFile&) = delete; SourceFile& operator=(const SourceFile&) = delete; -# endif +#endif }; class SnippetFactory { @@ -3327,22 +3698,22 @@ class cfile_streambuf : public std::streambuf { return static_cast(fwrite(s, sizeof *s, static_cast(count), sink)); } -# ifdef BACKWARD_ATLEAST_CXX11 +#ifdef BACKWARD_ATLEAST_CXX11 public: cfile_streambuf(const cfile_streambuf&) = delete; cfile_streambuf& operator=(const cfile_streambuf&) = delete; -# else +#else private: cfile_streambuf(const cfile_streambuf&); cfile_streambuf& operator=(const cfile_streambuf&); -# endif +#endif private: FILE* sink; std::vector buffer; }; -# ifdef BACKWARD_SYSTEM_LINUX +#ifdef BACKWARD_SYSTEM_LINUX namespace Color { enum type { yellow = 33, purple = 35, reset = 39 }; @@ -3385,7 +3756,7 @@ class Colorize { bool _enabled; }; -# else // ndef BACKWARD_SYSTEM_LINUX +#else // ndef BACKWARD_SYSTEM_LINUX namespace Color { enum type { yellow = 0, purple = 0, reset = 0 }; @@ -3399,7 +3770,7 @@ class Colorize { void set_color(Color::type) {} }; -# endif // BACKWARD_SYSTEM_LINUX +#endif // BACKWARD_SYSTEM_LINUX class Printer { public: @@ -3456,6 +3827,8 @@ class Printer { return os; } + TraceResolver const& resolver() const { return _resolver; } + private: TraceResolver _resolver; SnippetFactory _snippets; @@ -3569,7 +3942,7 @@ class Printer { /*************** SIGNALS HANDLING ***************/ -# if defined(BACKWARD_SYSTEM_LINUX) || defined(BACKWARD_SYSTEM_DARWIN) +#if defined(BACKWARD_SYSTEM_LINUX) || defined(BACKWARD_SYSTEM_DARWIN) class SignalHandling { public: @@ -3588,9 +3961,9 @@ class SignalHandling { SIGTRAP, // Trace/breakpoint trap SIGXCPU, // CPU time limit exceeded (4.2BSD) SIGXFSZ, // File size limit exceeded (4.2BSD) -# if defined(BACKWARD_SYSTEM_DARWIN) +# if defined(BACKWARD_SYSTEM_DARWIN) SIGEMT, // emulation instruction executed -# endif +# endif }; return std::vector(posix_signals, posix_signals + sizeof posix_signals / sizeof posix_signals[0]); } @@ -3620,14 +3993,14 @@ class SignalHandling { action.sa_flags = static_cast(SA_SIGINFO | SA_ONSTACK | SA_NODEFER | SA_RESETHAND); sigfillset(&action.sa_mask); sigdelset(&action.sa_mask, posix_signals[i]); -# if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wdisabled-macro-expansion" -# endif +# if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wdisabled-macro-expansion" +# endif action.sa_sigaction = &sig_handler; -# if defined(__clang__) -# pragma clang diagnostic pop -# endif +# if defined(__clang__) +# pragma clang diagnostic pop +# endif int r = sigaction(posix_signals[i], &action, nullptr); if (r < 0) @@ -3645,25 +4018,27 @@ class SignalHandling { StackTrace st; void* error_addr = nullptr; -# ifdef REG_RIP // x86_64 +# ifdef REG_RIP // x86_64 error_addr = reinterpret_cast(uctx->uc_mcontext.gregs[REG_RIP]); -# elif defined(REG_EIP) // x86_32 +# elif defined(REG_EIP) // x86_32 error_addr = reinterpret_cast(uctx->uc_mcontext.gregs[REG_EIP]); -# elif defined(__arm__) +# elif defined(__arm__) error_addr = reinterpret_cast(uctx->uc_mcontext.arm_pc); -# elif defined(__aarch64__) +# elif defined(__aarch64__) error_addr = reinterpret_cast(uctx->uc_mcontext.pc); -# elif defined(__ppc__) || defined(__powerpc) || defined(__powerpc__) || defined(__POWERPC__) +# elif defined(__mips__) + error_addr = reinterpret_cast(reinterpret_cast(&uctx->uc_mcontext)->sc_pc); +# elif defined(__ppc__) || defined(__powerpc) || defined(__powerpc__) || defined(__POWERPC__) error_addr = reinterpret_cast(uctx->uc_mcontext.regs->nip); -# elif defined(__s390x__) +# elif defined(__s390x__) error_addr = reinterpret_cast(uctx->uc_mcontext.psw.addr); -# elif defined(__APPLE__) && defined(__x86_64__) +# elif defined(__APPLE__) && defined(__x86_64__) error_addr = reinterpret_cast(uctx->uc_mcontext->__ss.__rip); -# elif defined(__APPLE__) +# elif defined(__APPLE__) error_addr = reinterpret_cast(uctx->uc_mcontext->__ss.__eip); -# else -# warning ":/ sorry, ain't know no nothing none not of your architecture!" -# endif +# else +# warning ":/ sorry, ain't know no nothing none not of your architecture!" +# endif if (error_addr) { st.load_from(error_addr, 32); } @@ -3675,20 +4050,20 @@ class SignalHandling { printer.address = true; printer.print(st, stderr); -# if _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L +# if _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L psiginfo(info, nullptr); -# else +# else (void)info; -# endif +# endif } private: details::handle _stack_content; bool _loaded; -# ifdef __GNUC__ +# ifdef __GNUC__ __attribute__((noreturn)) -# endif +# endif static void sig_handler(int signo, siginfo_t* info, void* _ctx) { @@ -3703,9 +4078,203 @@ class SignalHandling { } }; -# endif // BACKWARD_SYSTEM_LINUX || BACKWARD_SYSTEM_DARWIN +#endif // BACKWARD_SYSTEM_LINUX || BACKWARD_SYSTEM_DARWIN + +#ifdef BACKWARD_SYSTEM_WINDOWS + +class SignalHandling { +public: + SignalHandling(const std::vector& = std::vector()) + : reporter_thread_([]() { + /* We handle crashes in a utility thread: + backward structures and some Windows functions called here + need stack space, which we do not have when we encounter a + stack overflow. + To support reporting stack traces during a stack overflow, + we create a utility thread at startup, which waits until a + crash happens or the program exits normally. */ + + { + std::unique_lock lk(mtx()); + cv().wait(lk, [] { return crashed() != crash_status::running; }); + } + if (crashed() == crash_status::crashed) { + handle_stacktrace(skip_recs()); + } + { + std::unique_lock lk(mtx()); + crashed() = crash_status::ending; + } + cv().notify_one(); + }) + { + SetUnhandledExceptionFilter(crash_handler); + + signal(SIGABRT, signal_handler); + _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT); + + set_terminate(&terminator); + set_unexpected(&terminator); + _set_purecall_handler(&terminator); + _set_invalid_parameter_handler(&invalid_parameter_handler); + } + bool loaded() const { return true; } + + ~SignalHandling() + { + { + std::unique_lock lk(mtx()); + crashed() = crash_status::normal_exit; + } + + cv().notify_one(); + + reporter_thread_.join(); + } + +private: + static CONTEXT* ctx() + { + static CONTEXT data; + return &data; + } + + enum class crash_status { running, crashed, normal_exit, ending }; + + static crash_status& crashed() + { + static crash_status data; + return data; + } + + static std::mutex& mtx() + { + static std::mutex data; + return data; + } + + static std::condition_variable& cv() + { + static std::condition_variable data; + return data; + } + + static HANDLE& thread_handle() + { + static HANDLE handle; + return handle; + } + + std::thread reporter_thread_; + + // TODO: how not to hardcode these? + static const constexpr int signal_skip_recs = +# ifdef __clang__ + // With clang, RtlCaptureContext also captures the stack frame of the + // current function Below that, there ar 3 internal Windows functions + 4 +# else + // With MSVC cl, RtlCaptureContext misses the stack frame of the current + // function The first entries during StackWalk are the 3 internal Windows + // functions + 3 +# endif + ; + + static int& skip_recs() + { + static int data; + return data; + } + + static inline void terminator() + { + crash_handler(signal_skip_recs); + abort(); + } + + static inline void signal_handler(int) + { + crash_handler(signal_skip_recs); + abort(); + } + + static inline void __cdecl invalid_parameter_handler( + const wchar_t*, + const wchar_t*, + const wchar_t*, + unsigned int, + uintptr_t) + { + crash_handler(signal_skip_recs); + abort(); + } + + NOINLINE static LONG WINAPI crash_handler(EXCEPTION_POINTERS* info) + { + // The exception info supplies a trace from exactly where the issue was, + // no need to skip records + crash_handler(0, info->ContextRecord); + return EXCEPTION_CONTINUE_SEARCH; + } + + NOINLINE static void crash_handler(int skip, CONTEXT* ct = nullptr) + { + + if (ct == nullptr) { + RtlCaptureContext(ctx()); + } + else { + memcpy(ctx(), ct, sizeof(CONTEXT)); + } + DuplicateHandle( + GetCurrentProcess(), + GetCurrentThread(), + GetCurrentProcess(), + &thread_handle(), + 0, + FALSE, + DUPLICATE_SAME_ACCESS); + + skip_recs() = skip; + + { + std::unique_lock lk(mtx()); + crashed() = crash_status::crashed; + } + + cv().notify_one(); + + { + std::unique_lock lk(mtx()); + cv().wait(lk, [] { return crashed() != crash_status::crashed; }); + } + } + + static void handle_stacktrace(int skip_frames = 0) + { + // printer creates the TraceResolver, which can supply us a machine type + // for stack walking. Without this, StackTrace can only guess using some + // macros. + // StackTrace also requires that the PDBs are already loaded, which is done + // in the constructor of TraceResolver + Printer printer; + + StackTrace st; + st.set_machine_type(printer.resolver().machine_type()); + st.set_context(ctx()); + st.set_thread_handle(thread_handle()); + st.load_here(32 + skip_frames); + st.skip_n_firsts(skip_frames); + + printer.address = true; + printer.print(st, std::cerr); + } +}; + +#endif // BACKWARD_SYSTEM_WINDOWS -# ifdef BACKWARD_SYSTEM_UNKNOWN +#ifdef BACKWARD_SYSTEM_UNKNOWN class SignalHandling { public: @@ -3714,8 +4283,9 @@ class SignalHandling { bool loaded() { return false; } }; -# endif // BACKWARD_SYSTEM_UNKNOWN +#endif // BACKWARD_SYSTEM_UNKNOWN } // namespace backward #endif /* H_GUARD */ +// clang-format on From 2beedaac40889c099563add5b7e5f460de4423f2 Mon Sep 17 00:00:00 2001 From: Bradley Bottomlee Date: Thu, 18 Jun 2020 14:47:12 -0500 Subject: [PATCH 31/84] Add simple Hello World lambda example using API Gateway (#97) --- examples/api-gateway/CMakeLists.txt | 12 +++++ examples/api-gateway/README.md | 81 +++++++++++++++++++++++++++++ examples/api-gateway/main.cpp | 61 ++++++++++++++++++++++ 3 files changed, 154 insertions(+) create mode 100644 examples/api-gateway/CMakeLists.txt create mode 100644 examples/api-gateway/README.md create mode 100644 examples/api-gateway/main.cpp diff --git a/examples/api-gateway/CMakeLists.txt b/examples/api-gateway/CMakeLists.txt new file mode 100644 index 0000000..02da6cc --- /dev/null +++ b/examples/api-gateway/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 3.5) +set(CMAKE_CXX_STANDARD 11) + +project(api LANGUAGES CXX) + +find_package(aws-lambda-runtime REQUIRED) +find_package(AWSSDK COMPONENTS core) + +add_executable(${PROJECT_NAME} "main.cpp") +target_link_libraries(${PROJECT_NAME} PUBLIC AWS::aws-lambda-runtime ${AWSSDK_LINK_LIBRARIES}) + +aws_lambda_package_target(${PROJECT_NAME}) diff --git a/examples/api-gateway/README.md b/examples/api-gateway/README.md new file mode 100644 index 0000000..d184165 --- /dev/null +++ b/examples/api-gateway/README.md @@ -0,0 +1,81 @@ +# Example using the AWS C++ Lambda runtime and Amazon API Gateway + +In this example, we'll build a simple "Hello, World" lambda function that can be invoked using an api endpoint created using Amazon API gateway. This example can be viewed as the C++ counterpart to the NodeJS "Hello, World" API example as viewed [here](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-create-api-as-simple-proxy-for-lambda.html). At the end of this example, you should be able to invoke your lambda via an api endpoint and receive a raw JSON response. This example employs the use of the AWS C++ SDK to parse the request and write the necessary response. + +## Build the AWS C++ SDK +Start by building the SDK from source. + +```bash +$ mkdir ~/install +$ git clone https://github.com/aws/aws-sdk-cpp.git +$ cd aws-sdk-cpp +$ mkdir build +$ cd build +$ cmake .. -DBUILD_ONLY="core" \ + -DCMAKE_BUILD_TYPE=Release \ + -DBUILD_SHARED_LIBS=OFF \ + -DENABLE_UNITY_BUILD=ON \ + -DCUSTOM_MEMORY_MANAGEMENT=OFF \ + -DCMAKE_INSTALL_PREFIX=~/install \ + -DENABLE_UNITY_BUILD=ON +$ make +$ make install +``` + +## Build the Runtime +We need to build the C++ Lambda runtime as outlined in the other examples. + +```bash +$ git clone https://github.com/awslabs/aws-lambda-cpp-runtime.git +$ cd aws-lambda-cpp-runtime +$ mkdir build +$ cd build +$ cmake .. -DCMAKE_BUILD_TYPE=Release \ + -DBUILD_SHARED_LIBS=OFF \ + -DCMAKE_INSTALL_PREFIX=~/install \ +$ make +$ make install +``` + +## Build the application +The next step is to build the Lambda function in `main.cpp` and run the packaging command as follows: + +```bash +$ mkdir build +$ cd build +$ cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH=~/install +$ make +$ make aws-lambda-package-api +``` + +You should now have a zip file called `api.zip`. Follow the instructions in the main README to upload it and return here once complete. + +## Using Amazon API Gateway +For the rest of this example, we will use the AWS Management Console to create the API endpoint using Amazon API Gateway. + +1. Navigate to AWS Lambda within the console [here](https://console.aws.amazon.com/lambda/home) +1. Select the newly created function. Within the specific function, the "Designer" window should appear. +1. Simply click "Add trigger" -> "API Gateway" -> "Create an API". Please view the settings below. + * API Type: HTTP API + * Security: Open + * API name: Hello-World-API (or desired name) + * Deployment stage: default +1. Once you have added the API gateway, locate the newly created endpoint. View how to test the endpoint below. + +## Test the endpoint +Feel free to test the endpoint any way you desire. Below is a way to test using cURL: + +``` +curl -v -X POST \ + '?name=Bradley&city=Chicago' \ + -H 'content-type: application/json' \ + -H 'day: Sunday' \ + -d '{ "time": "evening" }' +``` + +With the expected response being: +``` +{ + "message": "Good evening, Bradley of Chicago. Happy Sunday!" +} +``` diff --git a/examples/api-gateway/main.cpp b/examples/api-gateway/main.cpp new file mode 100644 index 0000000..90f1035 --- /dev/null +++ b/examples/api-gateway/main.cpp @@ -0,0 +1,61 @@ +#include +#include +#include + +using namespace aws::lambda_runtime; + +invocation_response my_handler(invocation_request const& request) +{ + + using namespace Aws::Utils::Json; + + JsonValue json(request.payload); + if (!json.WasParseSuccessful()) { + return invocation_response::failure("Failed to parse input JSON", "InvalidJSON"); + } + + auto v = json.View(); + Aws::SimpleStringStream ss; + ss << "Good "; + + if (v.ValueExists("body") && v.GetObject("body").IsString()) { + auto body = v.GetString("body"); + JsonValue body_json(body); + + if (body_json.WasParseSuccessful()) { + auto body_v = body_json.View(); + ss << (body_v.ValueExists("time") && body_v.GetObject("time").IsString() ? body_v.GetString("time") : ""); + } + } + ss << ", "; + + if (v.ValueExists("queryStringParameters")) { + auto query_params = v.GetObject("queryStringParameters"); + ss << (query_params.ValueExists("name") && query_params.GetObject("name").IsString() + ? query_params.GetString("name") + : "") + << " of "; + ss << (query_params.ValueExists("city") && query_params.GetObject("city").IsString() + ? query_params.GetString("city") + : "") + << ". "; + } + + if (v.ValueExists("headers")) { + auto headers = v.GetObject("headers"); + ss << "Happy " + << (headers.ValueExists("day") && headers.GetObject("day").IsString() ? headers.GetString("day") : "") + << "!"; + } + + JsonValue resp; + resp.WithString("message", ss.str()); + + return invocation_response::success(resp.View().WriteCompact(), "application/json"); +} + +int main() +{ + run_handler(my_handler); + return 0; +} From 17473f8c12895a964900c63454f470a7de700fd3 Mon Sep 17 00:00:00 2001 From: Ovidijus Okinskas Date: Wed, 29 Jul 2020 20:21:04 +0100 Subject: [PATCH 32/84] feat: Manjaro support (#99) - added Manjaro as an OS supporting pacman --- packaging/packager | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/packager b/packaging/packager index 3d689c0..d333891 100755 --- a/packaging/packager +++ b/packaging/packager @@ -56,7 +56,7 @@ if ! type zip > /dev/null 2>&1; then exit 1 fi function package_libc_via_pacman { - if grep "Arch Linux" < /etc/os-release > /dev/null 2>&1; then + if grep --extended-regexp "Arch Linux|Manjaro Linux" < /etc/os-release > /dev/null 2>&1; then if type pacman > /dev/null 2>&1; then pacman --query --list --quiet glibc | sed -E '/\.so$|\.so\.[0-9]+$/!d' fi From 57d9f29f876d4edea4fc4166542e44eab2a9198d Mon Sep 17 00:00:00 2001 From: Marco Magdy Date: Sat, 1 Aug 2020 14:11:21 -0700 Subject: [PATCH 33/84] Avoid copying the result of a successful outcome (#100) Adding rvalue ref-qualifiers to the 'outcome' class getters enables moving out the result instead of copying it. In this case, we can avoid copying the request payload. * Remove static modifier from inline header functions static inline makes no sense in a header file. --- include/aws/lambda-runtime/outcome.h | 48 +++++++++++++++++++++------- include/aws/logging/logging.h | 6 ++-- src/runtime.cpp | 4 +-- 3 files changed, 41 insertions(+), 17 deletions(-) diff --git a/include/aws/lambda-runtime/outcome.h b/include/aws/lambda-runtime/outcome.h index e587e39..b5d0b8b 100644 --- a/include/aws/lambda-runtime/outcome.h +++ b/include/aws/lambda-runtime/outcome.h @@ -23,48 +23,72 @@ namespace lambda_runtime { template class outcome { public: - outcome(TResult const& s) : s(s), m_success(true) {} + outcome(TResult const& s) : m_s(s), m_success(true) {} + outcome(TResult&& s) : m_s(std::move(s)), m_success(true) {} - outcome(TFailure const& f) : f(f), m_success(false) {} + outcome(TFailure const& f) : m_f(f), m_success(false) {} + outcome(TFailure&& f) : m_f(std::move(f)), m_success(false) {} + + outcome(outcome const& other) : m_success(other.m_success) + { + if (m_success) { + new (&m_s) TResult(other.m_s); + } + else { + new (&m_f) TFailure(other.m_f); + } + } outcome(outcome&& other) noexcept : m_success(other.m_success) { if (m_success) { - s = std::move(other.s); + new (&m_s) TResult(std::move(other.m_s)); } else { - f = std::move(other.f); + new (&m_f) TFailure(std::move(other.m_f)); } } ~outcome() { if (m_success) { - s.~TResult(); + m_s.~TResult(); } else { - f.~TFailure(); + m_f.~TFailure(); } } - TResult const& get_result() const + TResult const& get_result() const& { assert(m_success); - return s; + return m_s; + } + + TResult&& get_result() && + { + assert(m_success); + return std::move(m_s); + } + + TFailure const& get_failure() const& + { + assert(!m_success); + return m_f; } - TFailure const& get_failure() const + TFailure&& get_failure() && { assert(!m_success); - return f; + return std::move(m_f); } bool is_success() const { return m_success; } private: union { - TResult s; - TFailure f; + TResult m_s; + TFailure m_f; }; bool m_success; }; diff --git a/include/aws/logging/logging.h b/include/aws/logging/logging.h index a3d9f50..0b5d0ef 100644 --- a/include/aws/logging/logging.h +++ b/include/aws/logging/logging.h @@ -27,7 +27,7 @@ enum class verbosity { void log(verbosity v, char const* tag, char const* msg, va_list args); -[[gnu::format(printf, 2, 3)]] static inline void log_error(char const* tag, char const* msg, ...) +[[gnu::format(printf, 2, 3)]] inline void log_error(char const* tag, char const* msg, ...) { va_list args; va_start(args, msg); @@ -37,7 +37,7 @@ void log(verbosity v, char const* tag, char const* msg, va_list args); (void)msg; } -[[gnu::format(printf, 2, 3)]] static inline void log_info(char const* tag, char const* msg, ...) +[[gnu::format(printf, 2, 3)]] inline void log_info(char const* tag, char const* msg, ...) { #if AWS_LAMBDA_LOG >= 1 va_list args; @@ -50,7 +50,7 @@ void log(verbosity v, char const* tag, char const* msg, va_list args); #endif } -[[gnu::format(printf, 2, 3)]] static inline void log_debug(char const* tag, char const* msg, ...) +[[gnu::format(printf, 2, 3)]] inline void log_debug(char const* tag, char const* msg, ...) { #if AWS_LAMBDA_LOG >= 2 va_list args; diff --git a/src/runtime.cpp b/src/runtime.cpp index 2c12542..36fe22b 100644 --- a/src/runtime.cpp +++ b/src/runtime.cpp @@ -412,7 +412,7 @@ void run_handler(std::function c size_t const max_retries = 3; while (retries < max_retries) { - const auto next_outcome = rt.get_next(); + auto next_outcome = rt.get_next(); if (!next_outcome.is_success()) { if (next_outcome.get_failure() == aws::http::response_code::REQUEST_NOT_MADE) { ++retries; @@ -429,7 +429,7 @@ void run_handler(std::function c retries = 0; - auto const& req = next_outcome.get_result(); + auto const req = std::move(next_outcome).get_result(); logging::log_info(LOG_TAG, "Invoking user handler"); invocation_response res = handler(req); logging::log_info(LOG_TAG, "Invoking user handler completed."); From 3b90c853decc420c658cf730d68e4f26b9303d2c Mon Sep 17 00:00:00 2001 From: Michael Hart Date: Wed, 21 Oct 2020 14:35:48 -0400 Subject: [PATCH 34/84] Update LICENSE badge to correct repo (#105) Copy pasta mistake --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3407b45..0812476 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![GitHub](https://img.shields.io/github/license/awslabs/aws-c-common.svg)](https://github.com/awslabs/aws-c-common/blob/master/LICENSE) +[![GitHub](https://img.shields.io/github/license/awslabs/aws-lambda-cpp.svg)](https://github.com/awslabs/aws-lambda-cpp/blob/master/LICENSE) ![CodeBuild](https://codebuild.us-west-2.amazonaws.com/badges?uuid=eyJlbmNyeXB0ZWREYXRhIjoiQkN1b0srbWtnUjNibFVyL2psNmdaM0l4RnVQNzVBeG84QnQvUjRmOEJVdXdHUXMxZ25iWnFZQUtGTkUxVGJhcGZaVEhXY2JOSTFHTlkvaGF2RDRIZlpVPSIsIml2UGFyYW1ldGVyU3BlYyI6IjRiS3hlRjFxVFZHSWViQmQiLCJtYXRlcmlhbFNldFNlcmlhbCI6MX0%3D&branch=master) [![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/awslabs/aws-lambda-cpp.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/awslabs/aws-lambda-cpp/context:cpp) ## AWS Lambda C++ Runtime From aa351a6b037840f9edd7d90ef9e971317b7886e9 Mon Sep 17 00:00:00 2001 From: Bryan Moffatt Date: Wed, 21 Oct 2020 12:42:37 -0700 Subject: [PATCH 35/84] make the runtime client's user agent overrideable (#106) * make the runtime client's user agent overrideable * remove extra empty string * clang-format -i src/* --- include/aws/lambda-runtime/runtime.h | 2 ++ src/runtime.cpp | 20 ++++++++------------ 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/include/aws/lambda-runtime/runtime.h b/include/aws/lambda-runtime/runtime.h index 0dc292c..94e1e22 100644 --- a/include/aws/lambda-runtime/runtime.h +++ b/include/aws/lambda-runtime/runtime.h @@ -137,6 +137,7 @@ class runtime { using next_outcome = aws::lambda_runtime::outcome; using post_outcome = aws::lambda_runtime::outcome; + runtime(std::string const& endpoint, std::string const& user_agent); runtime(std::string const& endpoint); ~runtime(); @@ -164,6 +165,7 @@ class runtime { invocation_response const& handler_response); private: + std::string const m_user_agent_header; std::array const m_endpoints; CURL* const m_curl_handle; }; diff --git a/src/runtime.cpp b/src/runtime.cpp index 36fe22b..9175084 100644 --- a/src/runtime.cpp +++ b/src/runtime.cpp @@ -124,12 +124,6 @@ static size_t write_header(char* ptr, size_t size, size_t nmemb, void* userdata) return size * nmemb; } -static std::string const& get_user_agent_header() -{ - static std::string user_agent = std::string("User-Agent: AWS_Lambda_Cpp/") + get_version(); - return user_agent; -} - static size_t read_data(char* buffer, size_t size, size_t nitems, void* userdata) { auto const limit = size * nitems; @@ -163,10 +157,12 @@ static int rt_curl_debug_callback(CURL* handle, curl_infotype type, char* data, } #endif -runtime::runtime(std::string const& endpoint) - : m_endpoints{{endpoint + "/2018-06-01/runtime/init/error", - endpoint + "/2018-06-01/runtime/invocation/next", - endpoint + "/2018-06-01/runtime/invocation/"}}, +runtime::runtime(std::string const& endpoint) : runtime(endpoint, "AWS_Lambda_Cpp/" + std::string(get_version())) {} + +runtime::runtime(std::string const& endpoint, std::string const& user_agent) + : m_user_agent_header("User-Agent: " + user_agent), m_endpoints{{endpoint + "/2018-06-01/runtime/init/error", + endpoint + "/2018-06-01/runtime/invocation/next", + endpoint + "/2018-06-01/runtime/invocation/"}}, m_curl_handle(curl_easy_init()) { if (!m_curl_handle) { @@ -234,7 +230,7 @@ runtime::next_outcome runtime::get_next() curl_easy_setopt(m_curl_handle, CURLOPT_HEADERDATA, &resp); curl_slist* headers = nullptr; - headers = curl_slist_append(headers, get_user_agent_header().c_str()); + headers = curl_slist_append(headers, m_user_agent_header.c_str()); curl_easy_setopt(m_curl_handle, CURLOPT_HTTPHEADER, headers); logging::log_debug(LOG_TAG, "Making request to %s", m_endpoints[Endpoints::NEXT].c_str()); @@ -339,7 +335,7 @@ runtime::post_outcome runtime::do_post( headers = curl_slist_append(headers, "Expect:"); headers = curl_slist_append(headers, "transfer-encoding:"); - headers = curl_slist_append(headers, get_user_agent_header().c_str()); + headers = curl_slist_append(headers, m_user_agent_header.c_str()); auto const& payload = handler_response.get_payload(); logging::log_debug( LOG_TAG, "calculating content length... %s", ("content-length: " + std::to_string(payload.length())).c_str()); From 5959e2fac63ece49720597979856d3f68ab943a7 Mon Sep 17 00:00:00 2001 From: Keshav Yadav <73339349+keshayad@users.noreply.github.com> Date: Tue, 11 May 2021 18:04:21 +0100 Subject: [PATCH 36/84] packager: fetch glibc corresponding to the architecture (#120) --- packaging/packager | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packaging/packager b/packaging/packager index d333891..ab27526 100755 --- a/packaging/packager +++ b/packaging/packager @@ -45,6 +45,7 @@ done set -- "${POSITIONAL[@]}" # restore positional parameters PKG_BIN_PATH=$1 +architecture=$(arch) if [ ! -f "$PKG_BIN_PATH" ]; then echo "$PKG_BIN_PATH" - No such file.; @@ -73,8 +74,8 @@ function package_libc_via_dpkg() { function package_libc_via_rpm() { if type rpm > /dev/null 2>&1; then - if [[ $(rpm --query --list glibc.x86_64 | wc -l) -gt 1 ]]; then - rpm --query --list glibc.x86_64 | sed -E '/\.so$|\.so\.[0-9]+$/!d' + if [[ $(rpm --query --list glibc.$architecture | wc -l) -gt 1 ]]; then + rpm --query --list glibc.$architecture | sed -E '/\.so$|\.so\.[0-9]+$/!d' fi fi } From 8c4506997fc56e3d2656d2096c6db05aa33ae58e Mon Sep 17 00:00:00 2001 From: Ildar Sagdejev Date: Mon, 15 Nov 2021 06:39:22 +0000 Subject: [PATCH 37/84] Fixes build on Alpine Linux (#129) --- examples/Dockerfile | 2 +- src/backward.h | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/examples/Dockerfile b/examples/Dockerfile index aabb4dd..c7af1ec 100644 --- a/examples/Dockerfile +++ b/examples/Dockerfile @@ -1,3 +1,3 @@ FROM alpine:latest -RUN apk update && apk add cmake make git g++ bash curl-dev zlib-dev +RUN apk add --no-cache cmake make g++ git bash curl-dev zlib-dev libexecinfo-dev diff --git a/src/backward.h b/src/backward.h index e9e56c7..5128410 100644 --- a/src/backward.h +++ b/src/backward.h @@ -240,6 +240,10 @@ # endif # endif +# if BACKWARD_HAS_BACKTRACE_SYMBOL == 1 +# include +# endif + # if (BACKWARD_HAS_BACKTRACE == 1) || (BACKWARD_HAS_BACKTRACE_SYMBOL == 1) // then we shall rely on backtrace # include @@ -254,7 +258,7 @@ // #define BACKWARD_HAS_UNWIND 1 // - unwind comes from libgcc, but I saw an equivalent inside clang itself. // - with unwind, the stacktrace is as accurate as it can possibly be, since -// this is used by the C++ runtine in gcc/clang for stack unwinding on +// this is used by the C++ runtime in gcc/clang for stack unwinding on // exception. // - normally libgcc is already linked to your program by default. // From f0f427f9b96a96439299487b22f5313a9d8fc1c4 Mon Sep 17 00:00:00 2001 From: Ildar Sagdejev Date: Tue, 23 Nov 2021 20:06:38 +0000 Subject: [PATCH 38/84] Packaging support on Alpine Linux (#131) * Packaging support on Alpine Linux * Check system architecture using a standard utility and only where needed Fixes #122 * Use long-form flags in packager script --- packaging/packager | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/packaging/packager b/packaging/packager index ab27526..795d330 100755 --- a/packaging/packager +++ b/packaging/packager @@ -45,7 +45,6 @@ done set -- "${POSITIONAL[@]}" # restore positional parameters PKG_BIN_PATH=$1 -architecture=$(arch) if [ ! -f "$PKG_BIN_PATH" ]; then echo "$PKG_BIN_PATH" - No such file.; @@ -56,26 +55,41 @@ if ! type zip > /dev/null 2>&1; then echo "zip utility is not found. Please install it and re-run this script" exit 1 fi -function package_libc_via_pacman { + +function pluck_so_files() { + sed -E '/\.so$|\.so\.[0-9]+$/!d' +} + +function package_libc_alpine() { + if grep --fixed-strings "Alpine Linux" < /etc/os-release > /dev/null; then + if type apk > /dev/null 2>&1; then + apk info --contents musl 2>/dev/null | pluck_so_files | sed 's/^/\//' + fi + fi +} + +function package_libc_pacman() { if grep --extended-regexp "Arch Linux|Manjaro Linux" < /etc/os-release > /dev/null 2>&1; then if type pacman > /dev/null 2>&1; then - pacman --query --list --quiet glibc | sed -E '/\.so$|\.so\.[0-9]+$/!d' + pacman --query --list --quiet glibc | pluck_so_files fi fi } -function package_libc_via_dpkg() { +function package_libc_dpkg() { if type dpkg-query > /dev/null 2>&1; then if [[ $(dpkg-query --listfiles libc6 | wc -l) -gt 0 ]]; then - dpkg-query --listfiles libc6 | sed -E '/\.so$|\.so\.[0-9]+$/!d' + dpkg-query --listfiles libc6 | pluck_so_files fi fi } -function package_libc_via_rpm() { +function package_libc_rpm() { + arch=$(uname -m) + if type rpm > /dev/null 2>&1; then - if [[ $(rpm --query --list glibc.$architecture | wc -l) -gt 1 ]]; then - rpm --query --list glibc.$architecture | sed -E '/\.so$|\.so\.[0-9]+$/!d' + if [[ $(rpm --query --list glibc.$arch | wc -l) -gt 1 ]]; then + rpm --query --list glibc.$arch | pluck_so_files fi fi } @@ -99,9 +113,10 @@ PKG_LD="" list=$(ldd "$PKG_BIN_PATH" | awk '{print $(NF-1)}') libc_libs=() -libc_libs+=($(package_libc_via_dpkg)) -libc_libs+=($(package_libc_via_rpm)) -libc_libs+=($(package_libc_via_pacman)) +libc_libs+=($(package_libc_dpkg)) +libc_libs+=($(package_libc_rpm)) +libc_libs+=($(package_libc_pacman)) +libc_libs+=($(package_libc_alpine)) mkdir -p "$PKG_DIR/bin" "$PKG_DIR/lib" From 087eccba3a7d47ccd3a32435d2c49d7907f3f5c3 Mon Sep 17 00:00:00 2001 From: Ildar Sagdejev Date: Tue, 23 Nov 2021 20:10:43 +0000 Subject: [PATCH 39/84] Alpine Linux needs zip to package the build artifact (#130) Co-authored-by: Bryan Moffatt --- examples/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/Dockerfile b/examples/Dockerfile index c7af1ec..1aabd59 100644 --- a/examples/Dockerfile +++ b/examples/Dockerfile @@ -1,3 +1,3 @@ FROM alpine:latest -RUN apk add --no-cache cmake make g++ git bash curl-dev zlib-dev libexecinfo-dev +RUN apk add --no-cache cmake make g++ git bash zip curl-dev zlib-dev libexecinfo-dev From 6328d70f560d9b63e52862310551f91b4f5eba2b Mon Sep 17 00:00:00 2001 From: Bryan Moffatt Date: Tue, 23 Nov 2021 13:14:51 -0800 Subject: [PATCH 40/84] remove git pull from ci/codebuild/build-cpp-sdk.sh (#132) --- ci/codebuild/build-cpp-sdk.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/ci/codebuild/build-cpp-sdk.sh b/ci/codebuild/build-cpp-sdk.sh index 93ae7eb..59a8748 100755 --- a/ci/codebuild/build-cpp-sdk.sh +++ b/ci/codebuild/build-cpp-sdk.sh @@ -4,7 +4,6 @@ set -euo pipefail # build the AWS C++ SDK cd /aws-sdk-cpp -git pull mkdir build cd build cmake .. -GNinja -DBUILD_ONLY="lambda" \ From b254a62714f1b5e7dc573819a4cfd32898b284f8 Mon Sep 17 00:00:00 2001 From: Marco Magdy Date: Tue, 23 Nov 2021 13:15:41 -0800 Subject: [PATCH 41/84] Change the version on master branch to have -dev suffix (#107) Releases will have that suffix removed. Co-authored-by: Bryan Moffatt --- CMakeLists.txt | 4 ++-- tests/version_tests.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b3869a6..ce7296e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.9) set(CMAKE_CXX_STANDARD 11) project(aws-lambda-runtime - VERSION 0.2.6 + VERSION 0.0.0 LANGUAGES CXX) option(ENABLE_LTO "Enables link-time optimization, requires compiler support." ON) @@ -16,7 +16,7 @@ add_library(${PROJECT_NAME} set_target_properties(${PROJECT_NAME} PROPERTIES SOVERSION 0 - VERSION ${PROJECT_VERSION}) + VERSION ${PROJECT_VERSION}-dev) target_include_directories(${PROJECT_NAME} PUBLIC $ diff --git a/tests/version_tests.cpp b/tests/version_tests.cpp index 862c680..070b6dd 100644 --- a/tests/version_tests.cpp +++ b/tests/version_tests.cpp @@ -12,7 +12,7 @@ TEST(VersionTests, get_version_major) TEST(VersionTests, get_version_minor) { auto version = get_version_minor(); - ASSERT_GE(version, 1); + ASSERT_GE(version, 0); } TEST(VersionTests, get_version_patch) From 6be624de1b2a92e9cb77a57ac8895dde20ca0c37 Mon Sep 17 00:00:00 2001 From: Bryan Moffatt Date: Tue, 23 Nov 2021 16:30:22 -0800 Subject: [PATCH 42/84] reduce things done in ubuntu-18.04.yml --- ci/codebuild/ubuntu-18.04.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ci/codebuild/ubuntu-18.04.yml b/ci/codebuild/ubuntu-18.04.yml index 5313f91..5a39a8f 100644 --- a/ci/codebuild/ubuntu-18.04.yml +++ b/ci/codebuild/ubuntu-18.04.yml @@ -8,8 +8,7 @@ phases: build: commands: - echo Build started on `date` - - ci/codebuild/build.sh -DCMAKE_CXX_CLANG_TIDY=clang-tidy -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DENABLE_TESTS=ON -DTEST_RESOURCE_PREFIX=ubuntu1804 - - ci/codebuild/format-check.sh + - ci/codebuild/build.sh -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DENABLE_TESTS=ON -DTEST_RESOURCE_PREFIX=ubuntu1804 - ci/codebuild/run-tests.sh aws-lambda-package-lambda-test-fun ubuntu1804 post_build: commands: From 1f619721c3da13d637eddde23405d76529110649 Mon Sep 17 00:00:00 2001 From: Bryan Moffatt Date: Tue, 23 Nov 2021 16:41:01 -0800 Subject: [PATCH 43/84] Revert "reduce things done in ubuntu-18.04.yml" This reverts commit 6be624de1b2a92e9cb77a57ac8895dde20ca0c37. --- ci/codebuild/ubuntu-18.04.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ci/codebuild/ubuntu-18.04.yml b/ci/codebuild/ubuntu-18.04.yml index 5a39a8f..5313f91 100644 --- a/ci/codebuild/ubuntu-18.04.yml +++ b/ci/codebuild/ubuntu-18.04.yml @@ -8,7 +8,8 @@ phases: build: commands: - echo Build started on `date` - - ci/codebuild/build.sh -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DENABLE_TESTS=ON -DTEST_RESOURCE_PREFIX=ubuntu1804 + - ci/codebuild/build.sh -DCMAKE_CXX_CLANG_TIDY=clang-tidy -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DENABLE_TESTS=ON -DTEST_RESOURCE_PREFIX=ubuntu1804 + - ci/codebuild/format-check.sh - ci/codebuild/run-tests.sh aws-lambda-package-lambda-test-fun ubuntu1804 post_build: commands: From 0ee61ee96b2629d3890a6bca8d6ff0eaeff6ed24 Mon Sep 17 00:00:00 2001 From: Bryan Moffatt Date: Wed, 24 Nov 2021 11:01:54 -0800 Subject: [PATCH 44/84] Update and fix CI workflows (#133) * Create github workflow.yml * satisfy the format check * satisfy clang-tidy warning readability-qualified-auto * satisfy clang-tidy warning readability-redundant-access-specifiers * Update codebuild ubuntu-18.04.yml * sleep a bit after creating function resource in tests * reflect fixes made to codebuild environment for amazon linux --- .github/workflows/workflow.yml | 44 ++++++++++++++++++++++++++++ ci/codebuild/ubuntu-18.04.yml | 3 +- ci/docker/amazon-linux-2017.03 | 4 +-- include/aws/lambda-runtime/runtime.h | 2 -- src/runtime.cpp | 16 +++++----- tests/gtest/gtest.h | 1 + tests/runtime_tests.cpp | 4 +++ 7 files changed, 60 insertions(+), 14 deletions(-) create mode 100644 .github/workflows/workflow.yml diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml new file mode 100644 index 0000000..7abad42 --- /dev/null +++ b/.github/workflows/workflow.yml @@ -0,0 +1,44 @@ +name: Validate Project + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +env: + # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) + BUILD_TYPE: Debug + +jobs: + build: + # The CMake configure and build commands are platform agnostic and should work equally + # well on Windows or Mac. You can convert this to a matrix build if you need + # cross-platform coverage. + # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Install Dependencies + run: sudo apt-get install -y clang-tidy libcurl4-openssl-dev + + - name: Configure CMake + # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. + # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type + run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_CXX_CLANG_TIDY=clang-tidy + + - name: Build It + # Build your program with the given configuration + run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} + + format: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Check Formatting + run: ./ci/codebuild/format-check.sh + diff --git a/ci/codebuild/ubuntu-18.04.yml b/ci/codebuild/ubuntu-18.04.yml index 5313f91..5a39a8f 100644 --- a/ci/codebuild/ubuntu-18.04.yml +++ b/ci/codebuild/ubuntu-18.04.yml @@ -8,8 +8,7 @@ phases: build: commands: - echo Build started on `date` - - ci/codebuild/build.sh -DCMAKE_CXX_CLANG_TIDY=clang-tidy -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DENABLE_TESTS=ON -DTEST_RESOURCE_PREFIX=ubuntu1804 - - ci/codebuild/format-check.sh + - ci/codebuild/build.sh -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DENABLE_TESTS=ON -DTEST_RESOURCE_PREFIX=ubuntu1804 - ci/codebuild/run-tests.sh aws-lambda-package-lambda-test-fun ubuntu1804 post_build: commands: diff --git a/ci/docker/amazon-linux-2017.03 b/ci/docker/amazon-linux-2017.03 index f66919a..0ad4621 100644 --- a/ci/docker/amazon-linux-2017.03 +++ b/ci/docker/amazon-linux-2017.03 @@ -1,12 +1,10 @@ FROM amazonlinux:2017.03 RUN yum install gcc64-c++ git ninja-build curl-devel openssl-devel zlib-devel gtest-devel python36-pip zip -y -RUN git clone https://github.com/aws/aws-sdk-cpp.git +RUN git clone --recurse-submodules https://github.com/aws/aws-sdk-cpp RUN curl -fLo cmake-install https://github.com/Kitware/CMake/releases/download/v3.13.0/cmake-3.13.0-Linux-x86_64.sh; \ sh cmake-install --skip-license --prefix=/usr --exclude-subdirectory; RUN pip-3.6 install --upgrade pip -RUN git clone https://github.com/aws/aws-sdk-cpp.git - diff --git a/include/aws/lambda-runtime/runtime.h b/include/aws/lambda-runtime/runtime.h index 94e1e22..9602369 100644 --- a/include/aws/lambda-runtime/runtime.h +++ b/include/aws/lambda-runtime/runtime.h @@ -163,8 +163,6 @@ class runtime { std::string const& url, std::string const& request_id, invocation_response const& handler_response); - -private: std::string const m_user_agent_header; std::array const m_endpoints; CURL* const m_curl_handle; diff --git a/src/runtime.cpp b/src/runtime.cpp index 9175084..6d2a1fb 100644 --- a/src/runtime.cpp +++ b/src/runtime.cpp @@ -61,7 +61,7 @@ static size_t write_data(char* ptr, size_t size, size_t nmemb, void* userdata) return 0; } - auto const resp = static_cast(userdata); + auto* const resp = static_cast(userdata); assert(size == 1); (void)size; // avoid warning in release builds assert(resp); @@ -110,7 +110,7 @@ static size_t write_header(char* ptr, size_t size, size_t nmemb, void* userdata) logging::log_debug(LOG_TAG, "received header: %s", std::string(ptr, nmemb).c_str()); - auto const resp = static_cast(userdata); + auto* const resp = static_cast(userdata); assert(resp); for (size_t i = 0; i < nmemb; i++) { if (ptr[i] != ':') { @@ -127,7 +127,7 @@ static size_t write_header(char* ptr, size_t size, size_t nmemb, void* userdata) static size_t read_data(char* buffer, size_t size, size_t nitems, void* userdata) { auto const limit = size * nitems; - auto ctx = static_cast*>(userdata); + auto* ctx = static_cast*>(userdata); assert(ctx); auto const unread = ctx->first.length() - ctx->second; if (0 == unread) { @@ -160,9 +160,11 @@ static int rt_curl_debug_callback(CURL* handle, curl_infotype type, char* data, runtime::runtime(std::string const& endpoint) : runtime(endpoint, "AWS_Lambda_Cpp/" + std::string(get_version())) {} runtime::runtime(std::string const& endpoint, std::string const& user_agent) - : m_user_agent_header("User-Agent: " + user_agent), m_endpoints{{endpoint + "/2018-06-01/runtime/init/error", - endpoint + "/2018-06-01/runtime/invocation/next", - endpoint + "/2018-06-01/runtime/invocation/"}}, + : m_user_agent_header("User-Agent: " + user_agent), + m_endpoints{ + {endpoint + "/2018-06-01/runtime/init/error", + endpoint + "/2018-06-01/runtime/invocation/next", + endpoint + "/2018-06-01/runtime/invocation/"}}, m_curl_handle(curl_easy_init()) { if (!m_curl_handle) { @@ -396,7 +398,7 @@ void run_handler(std::function c { logging::log_info(LOG_TAG, "Initializing the C++ Lambda Runtime version %s", aws::lambda_runtime::get_version()); std::string endpoint("http://"); - if (auto ep = std::getenv("AWS_LAMBDA_RUNTIME_API")) { + if (auto* ep = std::getenv("AWS_LAMBDA_RUNTIME_API")) { assert(ep); logging::log_debug(LOG_TAG, "LAMBDA_SERVER_ADDRESS defined in environment as: %s", ep); endpoint += ep; diff --git a/tests/gtest/gtest.h b/tests/gtest/gtest.h index 844c9b7..deeb98d 100644 --- a/tests/gtest/gtest.h +++ b/tests/gtest/gtest.h @@ -1,3 +1,4 @@ +// clang-format off // Copyright 2005, Google Inc. // All rights reserved. // diff --git a/tests/runtime_tests.cpp b/tests/runtime_tests.cpp index 0032429..989b844 100644 --- a/tests/runtime_tests.cpp +++ b/tests/runtime_tests.cpp @@ -12,6 +12,7 @@ #include #include #include "gtest/gtest.h" +#include extern std::string aws_prefix; @@ -85,6 +86,9 @@ struct LambdaRuntimeTest : public ::testing::Test { auto outcome = m_lambda_client.CreateFunction(create_function_request); ASSERT_TRUE(outcome.IsSuccess()) << "Failed to create function " << function_name; + + // work around Lambda function pending creation state + sleep(5); } void delete_function(Aws::String const& function_name, bool assert = true) From 1f2ed6e46b6133e3013a1d4d9a49d96fc09c8bf1 Mon Sep 17 00:00:00 2001 From: Jaehyun Lyu Date: Thu, 25 Nov 2021 04:29:12 +0900 Subject: [PATCH 45/84] Cast type explicitly for fix build error (#111) Co-authored-by: Bryan Moffatt --- src/backward.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backward.h b/src/backward.h index 5128410..29beb81 100644 --- a/src/backward.h +++ b/src/backward.h @@ -3266,7 +3266,7 @@ class TraceResolverDarwinImpl : public Tra if (st.size() == 0) { return; } - _symbols.reset(backtrace_symbols(st.begin(), st.size())); + _symbols.reset(backtrace_symbols(st.begin(), (int)st.size())); } ResolvedTrace resolve(ResolvedTrace trace) From 4aa6639808fe03b5664edc95963e289d7444820d Mon Sep 17 00:00:00 2001 From: Marco Magdy Date: Mon, 29 Nov 2021 14:21:36 -0800 Subject: [PATCH 46/84] Reduce string copying. (#135) * Reduce string copying. Optimized a few unnecessary string copies that should have been moves to begin with. Additionally, I noticed that we're scanning the headers twice once to test if a given header exists and another to get its value, that is a perfect use case for std::optional, but since we need to stay compatible with C++11 and C++14, we can use the 'outcome' class instead. * Fixup: Move state boolean in move assignment Co-authored-by: Marco Magdy --- include/aws/http/response.h | 13 ++++++---- include/aws/lambda-runtime/outcome.h | 24 +++++++++++++++---- src/runtime.cpp | 36 +++++++++++++++------------- 3 files changed, 49 insertions(+), 24 deletions(-) diff --git a/include/aws/http/response.h b/include/aws/http/response.h index 9b8cbda..81f5071 100644 --- a/include/aws/http/response.h +++ b/include/aws/http/response.h @@ -14,6 +14,8 @@ * permissions and limitations under the License. */ +#include "aws/lambda-runtime/outcome.h" + #include #include #include @@ -31,7 +33,7 @@ class response { inline void add_header(std::string name, std::string const& value); inline void append_body(const char* p, size_t sz); inline bool has_header(char const* header) const; - inline std::string const& get_header(char const* header) const; + inline lambda_runtime::outcome get_header(char const* header) const; inline response_code get_response_code() const { return m_response_code; } inline void set_response_code(aws::http::response_code c); inline void set_content_type(char const* ct); @@ -140,7 +142,7 @@ inline std::string const& response::get_body() const inline void response::add_header(std::string name, std::string const& value) { std::transform(name.begin(), name.end(), name.begin(), ::tolower); - m_headers.emplace_back(name, value); + m_headers.emplace_back(std::move(name), value); } inline void response::append_body(const char* p, size_t sz) @@ -161,12 +163,15 @@ inline bool response::has_header(char const* header) const }); } -inline std::string const& response::get_header(char const* header) const +inline lambda_runtime::outcome response::get_header(char const* header) const { auto it = std::find_if(m_headers.begin(), m_headers.end(), [header](std::pair const& p) { return p.first == header; }); - assert(it != m_headers.end()); + + if (it == m_headers.end()) { + return false; + } return it->second; } diff --git a/include/aws/lambda-runtime/outcome.h b/include/aws/lambda-runtime/outcome.h index b5d0b8b..9982f5d 100644 --- a/include/aws/lambda-runtime/outcome.h +++ b/include/aws/lambda-runtime/outcome.h @@ -49,14 +49,20 @@ class outcome { } } - ~outcome() + ~outcome() { destroy(); } + + outcome& operator=(outcome&& other) noexcept { - if (m_success) { - m_s.~TResult(); + assert(this != &other); + destroy(); + if (other.m_success) { + new (&m_s) TResult(std::move(other.m_s)); } else { - m_f.~TFailure(); + new (&m_f) TFailure(std::move(other.m_f)); } + m_success = other.m_success; + return *this; } TResult const& get_result() const& @@ -86,6 +92,16 @@ class outcome { bool is_success() const { return m_success; } private: + void destroy() + { + if (m_success) { + m_s.~TResult(); + } + else { + m_f.~TFailure(); + } + } + union { TResult m_s; TFailure m_f; diff --git a/src/runtime.cpp b/src/runtime.cpp index 6d2a1fb..1232471 100644 --- a/src/runtime.cpp +++ b/src/runtime.cpp @@ -116,9 +116,7 @@ static size_t write_header(char* ptr, size_t size, size_t nmemb, void* userdata) if (ptr[i] != ':') { continue; } - std::string key{ptr, i}; - std::string value{ptr + i + 1, nmemb - i - 1}; - resp->add_header(trim(key), trim(value)); + resp->add_header(trim({ptr, i}), trim({ptr + i + 1, nmemb - i - 1})); break; } return size * nmemb; @@ -266,32 +264,38 @@ runtime::next_outcome runtime::get_next() return resp.get_response_code(); } - if (!resp.has_header(REQUEST_ID_HEADER)) { + auto out = resp.get_header(REQUEST_ID_HEADER); + if (!out.is_success()) { logging::log_error(LOG_TAG, "Failed to find header %s in response", REQUEST_ID_HEADER); return aws::http::response_code::REQUEST_NOT_MADE; } invocation_request req; req.payload = resp.get_body(); - req.request_id = resp.get_header(REQUEST_ID_HEADER); + req.request_id = std::move(out).get_result(); - if (resp.has_header(TRACE_ID_HEADER)) { - req.xray_trace_id = resp.get_header(TRACE_ID_HEADER); + out = resp.get_header(TRACE_ID_HEADER); + if (out.is_success()) { + req.xray_trace_id = std::move(out).get_result(); } - if (resp.has_header(CLIENT_CONTEXT_HEADER)) { - req.client_context = resp.get_header(CLIENT_CONTEXT_HEADER); + out = resp.get_header(CLIENT_CONTEXT_HEADER); + if (out.is_success()) { + req.client_context = std::move(out).get_result(); } - if (resp.has_header(COGNITO_IDENTITY_HEADER)) { - req.cognito_identity = resp.get_header(COGNITO_IDENTITY_HEADER); + out = resp.get_header(COGNITO_IDENTITY_HEADER); + if (out.is_success()) { + req.cognito_identity = std::move(out).get_result(); } - if (resp.has_header(FUNCTION_ARN_HEADER)) { - req.function_arn = resp.get_header(FUNCTION_ARN_HEADER); + out = resp.get_header(FUNCTION_ARN_HEADER); + if (out.is_success()) { + req.function_arn = std::move(out).get_result(); } - if (resp.has_header(DEADLINE_MS_HEADER)) { - auto const& deadline_string = resp.get_header(DEADLINE_MS_HEADER); + out = resp.get_header(DEADLINE_MS_HEADER); + if (out.is_success()) { + auto const& deadline_string = std::move(out).get_result(); constexpr int base = 10; unsigned long ms = strtoul(deadline_string.c_str(), nullptr, base); assert(ms > 0); @@ -303,7 +307,7 @@ runtime::next_outcome runtime::get_next() req.payload.c_str(), static_cast(req.get_time_remaining().count())); } - return next_outcome(req); + return {req}; } runtime::post_outcome runtime::post_success(std::string const& request_id, invocation_response const& handler_response) From b3cc2614b9d751eaac8e37972f59fae8f35a4735 Mon Sep 17 00:00:00 2001 From: nlewycky Date: Mon, 29 Nov 2021 16:40:42 -0800 Subject: [PATCH 47/84] packager: fetch glibc corresponding to the host architecture on debian multiarch (#126) Co-authored-by: Bryan Moffatt --- packaging/packager | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packaging/packager b/packaging/packager index 795d330..f5a3c8b 100755 --- a/packaging/packager +++ b/packaging/packager @@ -78,8 +78,9 @@ function package_libc_pacman() { function package_libc_dpkg() { if type dpkg-query > /dev/null 2>&1; then - if [[ $(dpkg-query --listfiles libc6 | wc -l) -gt 0 ]]; then - dpkg-query --listfiles libc6 | pluck_so_files + architecture=$(dpkg --print-architecture) + if [[ $(dpkg-query --listfiles libc6:$architecture | wc -l) -gt 0 ]]; then + dpkg-query --listfiles libc6:$architecture | pluck_so_files fi fi } From 57ce6869ca5b8638606f426b7423203f46b20f26 Mon Sep 17 00:00:00 2001 From: Bryan Moffatt Date: Thu, 2 Dec 2021 17:29:22 -0500 Subject: [PATCH 48/84] Enable alpine ci (#137) * add files for running the CI tests on alpine linux * ensure that libexecinfo is linked in builds not using glibc * busybox grep doesn't know -F as --fixed-strings (cherry picked from commit 935f4f59efe170c75e4e7ab5543bdff245a77d5b) * Added comment that explains -F flag (cherry picked from commit c1480f79b139ee3f427f12e25dfd09f24e89236c) * update dockerfile Co-authored-by: Ildar Sagdejev --- CMakeLists.txt | 3 +++ ci/codebuild/alpine-3.15.yml | 16 ++++++++++++++++ ci/docker/alpine-linux-3.15 | 5 +++++ ci/docker/alpine-linux-3.8 | 5 ----- packaging/packager | 3 ++- 5 files changed, 26 insertions(+), 6 deletions(-) create mode 100644 ci/codebuild/alpine-3.15.yml create mode 100644 ci/docker/alpine-linux-3.15 delete mode 100644 ci/docker/alpine-linux-3.8 diff --git a/CMakeLists.txt b/CMakeLists.txt index ce7296e..01e6313 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,6 +41,9 @@ endif() target_include_directories(${PROJECT_NAME} PRIVATE ${CURL_INCLUDE_DIRS}) +find_package(Backtrace REQUIRED) +target_link_libraries(${PROJECT_NAME} PRIVATE ${Backtrace_LIBRARIES}) + target_compile_options(${PROJECT_NAME} PRIVATE "-fno-exceptions" "-fno-rtti" diff --git a/ci/codebuild/alpine-3.15.yml b/ci/codebuild/alpine-3.15.yml new file mode 100644 index 0000000..6954b97 --- /dev/null +++ b/ci/codebuild/alpine-3.15.yml @@ -0,0 +1,16 @@ +version: 0.2 +# This uses the docker image specified in ci/docker/alpine-linux-3.15 +phases: + pre_build: + commands: + - pip install awscli + - ci/codebuild/build-cpp-sdk.sh + build: + commands: + - echo Build started on `date` + - ci/codebuild/build.sh -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DENABLE_TESTS=ON -DTEST_RESOURCE_PREFIX=alpine315 + - ci/codebuild/run-tests.sh aws-lambda-package-lambda-test-fun alpine315 + post_build: + commands: + - echo Build completed on `date` + diff --git a/ci/docker/alpine-linux-3.15 b/ci/docker/alpine-linux-3.15 new file mode 100644 index 0000000..8b0837e --- /dev/null +++ b/ci/docker/alpine-linux-3.15 @@ -0,0 +1,5 @@ +FROM alpine:3.15 + +RUN apk add --no-cache g++ cmake git bash py3-pip libexecinfo-dev ninja curl-dev zlib-dev zip + +RUN git clone --recurse-submodules https://github.com/aws/aws-sdk-cpp.git diff --git a/ci/docker/alpine-linux-3.8 b/ci/docker/alpine-linux-3.8 deleted file mode 100644 index a042e4c..0000000 --- a/ci/docker/alpine-linux-3.8 +++ /dev/null @@ -1,5 +0,0 @@ -FROM alpine:latest - -RUN apk update; apk add g++ cmake git ninja curl-dev zlib-dev - -RUN git clone https://github.com/aws/aws-sdk-cpp.git diff --git a/packaging/packager b/packaging/packager index f5a3c8b..0c4e749 100755 --- a/packaging/packager +++ b/packaging/packager @@ -61,7 +61,8 @@ function pluck_so_files() { } function package_libc_alpine() { - if grep --fixed-strings "Alpine Linux" < /etc/os-release > /dev/null; then + # -F matches a fixed string rather than a regex (grep that comes with busybox doesn't know --fixed-strings) + if grep -F "Alpine Linux" < /etc/os-release > /dev/null; then if type apk > /dev/null 2>&1; then apk info --contents musl 2>/dev/null | pluck_so_files | sed 's/^/\//' fi From dae6eb46a4498ce3f26d3243c6cb73aa3e4ffd18 Mon Sep 17 00:00:00 2001 From: Bryan Moffatt Date: Thu, 2 Dec 2021 18:48:09 -0500 Subject: [PATCH 49/84] Remove the need to have an S3 bucket to run the tests (#138) * Remove the need to have an S3 bucket to run the tests * clang-format * i like to std::move it --- ci/codebuild/amazonlinux-2017.03.yml | 1 - ci/codebuild/run-tests.sh | 1 - ci/codebuild/ubuntu-18.04.yml | 1 - tests/runtime_tests.cpp | 19 +++++++++++++++---- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/ci/codebuild/amazonlinux-2017.03.yml b/ci/codebuild/amazonlinux-2017.03.yml index eab1baf..b5cbcad 100644 --- a/ci/codebuild/amazonlinux-2017.03.yml +++ b/ci/codebuild/amazonlinux-2017.03.yml @@ -4,7 +4,6 @@ phases: pre_build: commands: - alias cmake=cmake3 - - pip install awscli - ci/codebuild/build-cpp-sdk.sh build: commands: diff --git a/ci/codebuild/run-tests.sh b/ci/codebuild/run-tests.sh index b25d0e3..1d25c78 100755 --- a/ci/codebuild/run-tests.sh +++ b/ci/codebuild/run-tests.sh @@ -6,6 +6,5 @@ cd $CODEBUILD_SRC_DIR cd build rm -rf *.zip ninja $1 -aws s3 cp tests/resources/lambda-test-fun.zip s3://aws-lambda-cpp-tests/$2lambda-test-fun.zip ctest --output-on-failure diff --git a/ci/codebuild/ubuntu-18.04.yml b/ci/codebuild/ubuntu-18.04.yml index 5a39a8f..eee4d57 100644 --- a/ci/codebuild/ubuntu-18.04.yml +++ b/ci/codebuild/ubuntu-18.04.yml @@ -3,7 +3,6 @@ version: 0.1 phases: pre_build: commands: - - pip install awscli - ci/codebuild/build-cpp-sdk.sh build: commands: diff --git a/tests/runtime_tests.cpp b/tests/runtime_tests.cpp index 989b844..9547d6b 100644 --- a/tests/runtime_tests.cpp +++ b/tests/runtime_tests.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -12,6 +13,8 @@ #include #include #include "gtest/gtest.h" +#include +#include #include extern std::string aws_prefix; @@ -20,8 +23,7 @@ namespace { using namespace Aws::Lambda; -constexpr auto S3BUCKET = "aws-lambda-cpp-tests"; -constexpr auto S3KEY = "lambda-test-fun.zip"; +constexpr auto ZIP_FILE_PATH = "resources/lambda-test-fun.zip"; constexpr auto REQUEST_TIMEOUT = 15 * 1000; struct LambdaRuntimeTest : public ::testing::Test { @@ -79,9 +81,18 @@ struct LambdaRuntimeTest : public ::testing::Test { create_function_request.SetFunctionName(function_name); // I ran into eventual-consistency issues when creating the role dynamically as part of the test. create_function_request.SetRole(get_role_arn("integration-tests")); + + struct stat s; + auto rc = stat(ZIP_FILE_PATH, &s); + ASSERT_EQ(rc, 0) << std::string("file does not exist: ") + ZIP_FILE_PATH; + Aws::Utils::CryptoBuffer zip_file_bytes(s.st_size); + auto* zip_file = fopen(ZIP_FILE_PATH, "r"); + fread(zip_file_bytes.GetUnderlyingData(), sizeof(unsigned char), s.st_size, zip_file); + fclose(zip_file); + Model::FunctionCode funcode; - funcode.WithS3Bucket(S3BUCKET).WithS3Key(build_resource_name(S3KEY)); - create_function_request.SetCode(funcode); + funcode.SetZipFile(std::move(zip_file_bytes)); + create_function_request.SetCode(std::move(funcode)); create_function_request.SetRuntime(Aws::Lambda::Model::Runtime::provided); auto outcome = m_lambda_client.CreateFunction(create_function_request); From 2ebbf8e5759841b68709e7bd1c9d90808854a204 Mon Sep 17 00:00:00 2001 From: Rawiri Blundell Date: Wed, 16 Feb 2022 12:36:22 +1300 Subject: [PATCH 50/84] Fix issue raised in #140 (#141) --- ci/codebuild/format-check.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/codebuild/format-check.sh b/ci/codebuild/format-check.sh index 3afb802..222b784 100755 --- a/ci/codebuild/format-check.sh +++ b/ci/codebuild/format-check.sh @@ -4,7 +4,7 @@ set -euo pipefail CLANG_FORMAT=clang-format -if NOT type $CLANG_FORMAT > /dev/null 2>&1; then +if ! type $CLANG_FORMAT > /dev/null 2>&1; then echo "No appropriate clang-format found." exit 1 fi From 132ca8758eeb223f3ce89beb9e510f22ed72ff3f Mon Sep 17 00:00:00 2001 From: Bryan Moffatt Date: Wed, 29 Jun 2022 20:49:06 -0700 Subject: [PATCH 51/84] add apt-get update to workflow.yml (#149) * Update workflow.yml * Update workflow.yml * Update workflow.yml * Update workflow.yml --- .github/workflows/workflow.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 7abad42..334e2f8 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -22,7 +22,7 @@ jobs: - uses: actions/checkout@v2 - name: Install Dependencies - run: sudo apt-get install -y clang-tidy libcurl4-openssl-dev + run: sudo apt-get update && sudo apt-get install -y clang-tidy libcurl4-openssl-dev - name: Configure CMake # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. From d56f24312610ff78b37eced195f5e6c0f7b32034 Mon Sep 17 00:00:00 2001 From: Krzysiek Karbowiak Date: Thu, 30 Jun 2022 05:59:41 +0200 Subject: [PATCH 52/84] Remove duplicated settings (#147) Co-authored-by: Bryan Moffatt --- examples/api-gateway/README.md | 1 - examples/dynamodb/README.md | 1 - 2 files changed, 2 deletions(-) diff --git a/examples/api-gateway/README.md b/examples/api-gateway/README.md index d184165..d1245fb 100644 --- a/examples/api-gateway/README.md +++ b/examples/api-gateway/README.md @@ -14,7 +14,6 @@ $ cd build $ cmake .. -DBUILD_ONLY="core" \ -DCMAKE_BUILD_TYPE=Release \ -DBUILD_SHARED_LIBS=OFF \ - -DENABLE_UNITY_BUILD=ON \ -DCUSTOM_MEMORY_MANAGEMENT=OFF \ -DCMAKE_INSTALL_PREFIX=~/install \ -DENABLE_UNITY_BUILD=ON diff --git a/examples/dynamodb/README.md b/examples/dynamodb/README.md index db84fd8..044877f 100644 --- a/examples/dynamodb/README.md +++ b/examples/dynamodb/README.md @@ -16,7 +16,6 @@ $ cd build $ cmake .. -DBUILD_ONLY="dynamodb" \ -DCMAKE_BUILD_TYPE=Release \ -DBUILD_SHARED_LIBS=OFF \ - -DENABLE_UNITY_BUILD=ON \ -DCUSTOM_MEMORY_MANAGEMENT=OFF \ -DCMAKE_INSTALL_PREFIX=~/install \ -DENABLE_UNITY_BUILD=ON From 7b9d56af2a2d02894917c50206bf7cce51cf7c84 Mon Sep 17 00:00:00 2001 From: Krzysiek Karbowiak Date: Thu, 30 Jun 2022 06:29:02 +0200 Subject: [PATCH 53/84] Fix response code value (#148) Co-authored-by: Bryan Moffatt --- include/aws/http/response.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/aws/http/response.h b/include/aws/http/response.h index 81f5071..6ef0c20 100644 --- a/include/aws/http/response.h +++ b/include/aws/http/response.h @@ -116,7 +116,7 @@ enum class response_code { GATEWAY_TIMEOUT = 504, HTTP_VERSION_NOT_SUPPORTED = 505, VARIANT_ALSO_NEGOTIATES = 506, - INSUFFICIENT_STORAGE = 506, + INSUFFICIENT_STORAGE = 507, LOOP_DETECTED = 508, BANDWIDTH_LIMIT_EXCEEDED = 509, NOT_EXTENDED = 510, From c3d92f700a9003e637964682e819045b1f398bba Mon Sep 17 00:00:00 2001 From: Bryan Moffatt Date: Sat, 23 Jul 2022 22:47:17 -0700 Subject: [PATCH 54/84] try arm build action on qemu (#152) --- .github/workflows/workflow.yml | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 334e2f8..14bb1da 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -32,7 +32,22 @@ jobs: - name: Build It # Build your program with the given configuration run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} - + + build-on-arm-too: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: uraimo/run-on-arch-action@v2 + with: + arch: aarch64 + distro: ubuntu20.04 + run: | + apt-get update && apt-get install -y cmake g++ clang-tidy libcurl4-openssl-dev + cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_CXX_CLANG_TIDY=clang-tidy + cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} + + + format: runs-on: ubuntu-latest @@ -41,4 +56,5 @@ jobs: - name: Check Formatting run: ./ci/codebuild/format-check.sh - + + From 095ff84911d0f3dcd0f428c4a5b49124ee66ee6b Mon Sep 17 00:00:00 2001 From: Bryan Moffatt Date: Tue, 26 Jul 2022 21:03:03 -0700 Subject: [PATCH 55/84] Update runtime tests to set the architecture for the function (#153) set test function architecture --- ci/codebuild/amazonlinux-2.yml | 12 ++++++++++++ ci/docker/amazon-linux-2 | 6 ++++++ ci/docker/ubuntu-linux-18.04 | 2 +- tests/runtime_tests.cpp | 10 +++++++++- 4 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 ci/codebuild/amazonlinux-2.yml create mode 100644 ci/docker/amazon-linux-2 diff --git a/ci/codebuild/amazonlinux-2.yml b/ci/codebuild/amazonlinux-2.yml new file mode 100644 index 0000000..71c0b59 --- /dev/null +++ b/ci/codebuild/amazonlinux-2.yml @@ -0,0 +1,12 @@ +version: 0.2 +phases: + pre_build: + commands: + - yum install -y zip + build: + commands: + - cmake3 -S . -B build -DENABLE_TESTS=ON -DTEST_RESOURCE_PREFIX=al2arm -GNinja + - cd build + - ninja-build + - ninja-build aws-lambda-package-lambda-test-fun + - ctest3 --output-on-failure diff --git a/ci/docker/amazon-linux-2 b/ci/docker/amazon-linux-2 new file mode 100644 index 0000000..787af12 --- /dev/null +++ b/ci/docker/amazon-linux-2 @@ -0,0 +1,6 @@ +FROM public.ecr.aws/amazonlinux/amazonlinux:2 +RUN yum install -y cmake3 ninja-build git gcc-c++ openssl-devel curl-devel +RUN git clone https://github.com/aws/aws-sdk-cpp --recurse-submodules +RUN cmake3 -Saws-sdk-cpp -Baws-sdk-cpp/build -DBUILD_ONLY=lambda -DENABLE_TESTING=OFF -GNinja +RUN cd aws-sdk-cpp/build && ninja-build && ninja-build install +RUN yum install -y openssl-static diff --git a/ci/docker/ubuntu-linux-18.04 b/ci/docker/ubuntu-linux-18.04 index 175ea82..0c43c97 100644 --- a/ci/docker/ubuntu-linux-18.04 +++ b/ci/docker/ubuntu-linux-18.04 @@ -9,7 +9,7 @@ sh cmake-install --skip-license --prefix=/usr --exclude-subdirectory; RUN pip3 install --upgrade pip -RUN git clone https://github.com/aws/aws-sdk-cpp.git +RUN git clone https://github.com/aws/aws-sdk-cpp.git --recurse-submodules RUN update-alternatives --set cc /usr/bin/clang RUN update-alternatives --set c++ /usr/bin/clang++ diff --git a/tests/runtime_tests.cpp b/tests/runtime_tests.cpp index 9547d6b..64ad79f 100644 --- a/tests/runtime_tests.cpp +++ b/tests/runtime_tests.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -16,6 +17,7 @@ #include #include #include +#include extern std::string aws_prefix; @@ -93,7 +95,13 @@ struct LambdaRuntimeTest : public ::testing::Test { Model::FunctionCode funcode; funcode.SetZipFile(std::move(zip_file_bytes)); create_function_request.SetCode(std::move(funcode)); - create_function_request.SetRuntime(Aws::Lambda::Model::Runtime::provided); + create_function_request.SetRuntime(Aws::Lambda::Model::Runtime::provided_al2); + + std::vector lambda_architectures = {Aws::Lambda::Model::Architecture::x86_64}; +#ifdef __aarch64__ + lambda_architectures[0] = Aws::Lambda::Model::Architecture::arm64; +#endif + create_function_request.SetArchitectures(lambda_architectures); auto outcome = m_lambda_client.CreateFunction(create_function_request); ASSERT_TRUE(outcome.IsSuccess()) << "Failed to create function " << function_name; From fab4a6eef7b2a4af864ad31406bb8eec72a20fcc Mon Sep 17 00:00:00 2001 From: Bryan Moffatt Date: Mon, 22 Aug 2022 10:09:33 -0700 Subject: [PATCH 56/84] throw if AWS_REGION environment variable is missing (#158) --- tests/runtime_tests.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/runtime_tests.cpp b/tests/runtime_tests.cpp index 64ad79f..9d0ee72 100644 --- a/tests/runtime_tests.cpp +++ b/tests/runtime_tests.cpp @@ -44,6 +44,9 @@ struct LambdaRuntimeTest : public ::testing::Test { Aws::Client::ClientConfiguration config; config.requestTimeoutMs = REQUEST_TIMEOUT; config.region = Aws::Environment::GetEnv("AWS_REGION"); + if (config.region.empty()) { + throw std::invalid_argument("environment variable AWS_REGION not set"); + } return config; } From 9b8daab14fb8e2751fb9cb8eae995e080eb91620 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Ben=C3=ADcio?= Date: Mon, 22 Aug 2022 21:53:14 -0300 Subject: [PATCH 57/84] improving error log for runtime::get_next() curl failure (#157) --- src/runtime.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/runtime.cpp b/src/runtime.cpp index 1232471..47ead0e 100644 --- a/src/runtime.cpp +++ b/src/runtime.cpp @@ -240,7 +240,10 @@ runtime::next_outcome runtime::get_next() if (curl_code != CURLE_OK) { logging::log_debug(LOG_TAG, "CURL returned error code %d - %s", curl_code, curl_easy_strerror(curl_code)); - logging::log_error(LOG_TAG, "Failed to get next invocation. No Response from endpoint"); + logging::log_error( + LOG_TAG, + "Failed to get next invocation. No Response from endpoint \"%s\"", + m_endpoints[Endpoints::NEXT].c_str()); return aws::http::response_code::REQUEST_NOT_MADE; } From 939c2e0dd90a937b3086860b99fa2b4b9b0b1350 Mon Sep 17 00:00:00 2001 From: Bryan Moffatt Date: Mon, 22 Aug 2022 19:16:26 -0700 Subject: [PATCH 58/84] Add instructions for executing the AWS CodeBuild workflows locally (#160) --- CONTRIBUTING.md | 18 ++++ ci/codebuild_build.sh | 205 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 223 insertions(+) create mode 100755 ci/codebuild_build.sh diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e8c3aa5..d6b300a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -43,6 +43,24 @@ GitHub provides additional document on [forking a repository](https://help.githu ## Finding contributions to work on Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any ['help wanted'](https://github.com/awslabs/aws-lambda-cpp-runtime/labels/help%20wanted) issues is a great place to start. +## Running the Integration Tests Locally + +The integration testing for the project creates, invokes, and deletes, Lambda functions. +These tests typically run AWS CodeBuild, but may also be executed locally + +Prerequisites: +* install Docker +* configure AWS credentials, need at least permissions to Create, Delete, and Invoke Lambda functions +* an IAM role, named exactly `integration-tests`, must exist in the account. + * The role must also be assumable by Lambda. + * (optional) attach AWSLambdaBasicExecutionRole managed policy to the role, so that the test function logs are saved to CloudWatch + +Then, to iterate on a single workflow: +``` +docker build -t lambda-cpp-amazon-linux-2 -f ./ci/docker/amazon-linux-2 . +./ci/codebuild_build.sh -c -a /tmp -i lambda-cpp-amazon-linux-2 -b ./ci/codebuild/amazon-linux-2.yml +``` + ## Code of Conduct This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). diff --git a/ci/codebuild_build.sh b/ci/codebuild_build.sh new file mode 100755 index 0000000..b2f75bc --- /dev/null +++ b/ci/codebuild_build.sh @@ -0,0 +1,205 @@ +#!/bin/bash + +function allOSRealPath() { + if isOSWindows + then + path="" + case $1 in + .* ) path="$PWD/${1#./}" ;; + /* ) path="$1" ;; + * ) path="/$1" ;; + esac + + echo "/$path" | sed -e 's/\\/\//g' -e 's/://' -e 's/./\U&/3' + else + case $1 in + /* ) echo "$1"; exit;; + * ) echo "$PWD/${1#./}"; exit;; + esac + fi +} + +function isOSWindows() { + if [ $OSTYPE == "msys" ] + then + return 0 + else + return 1 + fi +} + +function usage { + echo "usage: codebuild_build.sh [-i image_name] [-a artifact_output_directory] [options]" + echo "Required:" + echo " -i Used to specify the customer build container image." + echo " -a Used to specify an artifact output directory." + echo "Options:" + echo " -l IMAGE Used to override the default local agent image." + echo " -r Used to specify a report output directory." + echo " -s Used to specify source information. Defaults to the current working directory for primary source." + echo " * First (-s) is for primary source" + echo " * Use additional (-s) in : format for secondary source" + echo " * For sourceIdentifier, use a value that is fewer than 128 characters and contains only alphanumeric characters and underscores" + echo " -c Use the AWS configuration and credentials from your local host. This includes ~/.aws and any AWS_* environment variables." + echo " -p Used to specify the AWS CLI Profile." + echo " -b FILE Used to specify a buildspec override file. Defaults to buildspec.yml in the source directory." + echo " -m Used to mount the source directory to the customer build container directly." + echo " -d Used to run the build container in docker privileged mode." + echo " -e FILE Used to specify a file containing environment variables." + echo " (-e) File format expectations:" + echo " * Each line is in VAR=VAL format" + echo " * Lines beginning with # are processed as comments and ignored" + echo " * Blank lines are ignored" + echo " * File can be of type .env or .txt" + echo " * There is no special handling of quotation marks, meaning they will be part of the VAL" + exit 1 +} + +image_flag=false +artifact_flag=false +awsconfig_flag=false +mount_src_dir_flag=false +docker_privileged_mode_flag=false + +while getopts "cmdi:a:r:s:b:e:l:p:h" opt; do + case $opt in + i ) image_flag=true; image_name=$OPTARG;; + a ) artifact_flag=true; artifact_dir=$OPTARG;; + r ) report_dir=$OPTARG;; + b ) buildspec=$OPTARG;; + c ) awsconfig_flag=true;; + m ) mount_src_dir_flag=true;; + d ) docker_privileged_mode_flag=true;; + s ) source_dirs+=("$OPTARG");; + e ) environment_variable_file=$OPTARG;; + l ) local_agent_image=$OPTARG;; + p ) aws_profile=$OPTARG;; + h ) usage; exit;; + \? ) echo "Unknown option: -$OPTARG" >&2; exit 1;; + : ) echo "Missing option argument for -$OPTARG" >&2; exit 1;; + * ) echo "Invalid option: -$OPTARG" >&2; exit 1;; + esac +done + +if ! $image_flag +then + echo "The image name flag (-i) must be included for a build to run" >&2 +fi + +if ! $artifact_flag +then + echo "The artifact directory (-a) must be included for a build to run" >&2 +fi + +if ! $image_flag || ! $artifact_flag +then + exit 1 +fi + +docker_command="docker run -it " +if isOSWindows +then + docker_command+="-v //var/run/docker.sock:/var/run/docker.sock -e " +else + docker_command+="-v /var/run/docker.sock:/var/run/docker.sock -e " +fi + +docker_command+="\"IMAGE_NAME=$image_name\" -e \ + \"ARTIFACTS=$(allOSRealPath "$artifact_dir")\"" + +if [ -n "$report_dir" ] +then + docker_command+=" -e \"REPORTS=$(allOSRealPath "$report_dir")\"" +fi + +if [ -z "$source_dirs" ] +then + docker_command+=" -e \"SOURCE=$(allOSRealPath "$PWD")\"" +else + for index in "${!source_dirs[@]}"; do + if [ $index -eq 0 ] + then + docker_command+=" -e \"SOURCE=$(allOSRealPath "${source_dirs[$index]}")\"" + else + identifier=${source_dirs[$index]%%:*} + src_dir=$(allOSRealPath "${source_dirs[$index]#*:}") + + docker_command+=" -e \"SECONDARY_SOURCE_$index=$identifier:$src_dir\"" + fi + done +fi + +if [ -n "$buildspec" ] +then + docker_command+=" -e \"BUILDSPEC=$(allOSRealPath "$buildspec")\"" +fi + +if [ -n "$environment_variable_file" ] +then + environment_variable_file_path=$(allOSRealPath "$environment_variable_file") + environment_variable_file_dir=$(dirname "$environment_variable_file_path") + environment_variable_file_basename=$(basename "$environment_variable_file") + docker_command+=" -v \"$environment_variable_file_dir:/LocalBuild/envFile/\" -e \"ENV_VAR_FILE=$environment_variable_file_basename\"" +fi + +if [ -n "$local_agent_image" ] +then + docker_command+=" -e \"LOCAL_AGENT_IMAGE_NAME=$local_agent_image\"" +fi + +if $awsconfig_flag +then + if [ -d "$HOME/.aws" ] + then + configuration_file_path=$(allOSRealPath "$HOME/.aws") + docker_command+=" -e \"AWS_CONFIGURATION=$configuration_file_path\"" + else + docker_command+=" -e \"AWS_CONFIGURATION=NONE\"" + fi + + if [ -n "$aws_profile" ] + then + docker_command+=" -e \"AWS_PROFILE=$aws_profile\"" + fi + + docker_command+="$(env | grep ^AWS_ | while read -r line; do echo " -e \"$line\""; done )" +fi + +if $mount_src_dir_flag +then + docker_command+=" -e \"MOUNT_SOURCE_DIRECTORY=TRUE\"" +fi + +if $docker_privileged_mode_flag +then + docker_command+=" -e \"DOCKER_PRIVILEGED_MODE=TRUE\"" +fi + +if isOSWindows +then + docker_command+=" -e \"INITIATOR=$USERNAME\"" +else + docker_command+=" -e \"INITIATOR=$USER\"" +fi + +if [ -n "$local_agent_image" ] +then + docker_command+=" $local_agent_image" +else + docker_command+=" public.ecr.aws/codebuild/local-builds:latest" +fi + +# Note we do not expose the AWS_SECRET_ACCESS_KEY or the AWS_SESSION_TOKEN +exposed_command=$docker_command +secure_variables=( "AWS_SECRET_ACCESS_KEY=" "AWS_SESSION_TOKEN=") +for variable in "${secure_variables[@]}" +do + exposed_command="$(echo $exposed_command | sed "s/\($variable\)[^ ]*/\1********\"/")" +done + +echo "Build Command:" +echo "" +echo $exposed_command +echo "" + +eval $docker_command From 4668e1a8939d34992fe4e8b49e60e646246adb69 Mon Sep 17 00:00:00 2001 From: Bryan Moffatt Date: Tue, 23 Aug 2022 00:40:32 -0700 Subject: [PATCH 59/84] update backward.h to v1.6 upstream release (#154) --- ci/codebuild/amazonlinux-2.yml | 2 +- src/backward.h | 513 ++++++++++++++++++++-------- tests/CMakeLists.txt | 1 + tests/resources/lambda_function.cpp | 8 + tests/runtime_tests.cpp | 27 +- 5 files changed, 416 insertions(+), 135 deletions(-) diff --git a/ci/codebuild/amazonlinux-2.yml b/ci/codebuild/amazonlinux-2.yml index 71c0b59..7a5441c 100644 --- a/ci/codebuild/amazonlinux-2.yml +++ b/ci/codebuild/amazonlinux-2.yml @@ -5,7 +5,7 @@ phases: - yum install -y zip build: commands: - - cmake3 -S . -B build -DENABLE_TESTS=ON -DTEST_RESOURCE_PREFIX=al2arm -GNinja + - cmake3 -S . -B build -DBUILD_SHARED_LIBS=ON -DENABLE_TESTS=ON -DTEST_RESOURCE_PREFIX=al2arm -GNinja - cd build - ninja-build - ninja-build aws-lambda-package-lambda-test-fun diff --git a/src/backward.h b/src/backward.h index 29beb81..c421378 100644 --- a/src/backward.h +++ b/src/backward.h @@ -1,4 +1,3 @@ -// clang-format off /* * backward.hpp * Copyright 2013 Google Inc. All Rights Reserved. @@ -36,6 +35,9 @@ # define BACKWARD_CXX11 # define BACKWARD_ATLEAST_CXX11 # define BACKWARD_ATLEAST_CXX98 +# if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) +# define BACKWARD_ATLEAST_CXX17 +# endif # else # define BACKWARD_CXX98 # define BACKWARD_ATLEAST_CXX98 @@ -50,6 +52,9 @@ // #define BACKWARD_SYSTEM_DARWIN // - specialization for Mac OS X 10.5 and later. // +// #define BACKWARD_SYSTEM_WINDOWS +// - specialization for Windows (Clang 9 and MSVC2017) +// // #define BACKWARD_SYSTEM_UNKNOWN // - placebo implementation, does nothing. // @@ -85,6 +90,8 @@ #include #include #include +#include +#include #if defined(BACKWARD_SYSTEM_LINUX) @@ -98,6 +105,11 @@ // exception. // - normally libgcc is already linked to your program by default. // +// #define BACKWARD_HAS_LIBUNWIND 1 +// - libunwind provides, in some cases, a more accurate stacktrace as it knows +// to decode signal handler frames and lets us edit the context registers when +// unwinding, allowing stack traces over bad function references. +// // #define BACKWARD_HAS_BACKTRACE == 1 // - backtrace seems to be a little bit more portable than libunwind, but on // linux, it uses unwind anyway, but abstract away a tiny information that is @@ -110,10 +122,13 @@ // Note that only one of the define should be set to 1 at a time. // # if BACKWARD_HAS_UNWIND == 1 +# elif BACKWARD_HAS_LIBUNWIND == 1 # elif BACKWARD_HAS_BACKTRACE == 1 # else # undef BACKWARD_HAS_UNWIND # define BACKWARD_HAS_UNWIND 1 +# undef BACKWARD_HAS_LIBUNWIND +# define BACKWARD_HAS_LIBUNWIND 0 # undef BACKWARD_HAS_BACKTRACE # define BACKWARD_HAS_BACKTRACE 0 # endif @@ -126,9 +141,10 @@ // - object filename // - function name // - source filename -// - line and column numbers -// - source code snippet (assuming the file is accessible) -// - variables name and values (if not optimized out) +// - line and column numbers +// - source code snippet (assuming the file is accessible) +// - variable names (if not optimized out) +// - variable values (not supported by backward-cpp) // - You need to link with the lib "dw": // - apt-get install libdw-dev // - g++/clang++ -ldw ... @@ -138,8 +154,8 @@ // - object filename // - function name // - source filename -// - line numbers -// - source code snippet (assuming the file is accessible) +// - line numbers +// - source code snippet (assuming the file is accessible) // - You need to link with the lib "bfd": // - apt-get install binutils-dev // - g++/clang++ -lbfd ... @@ -151,7 +167,8 @@ // - source filename // - line and column numbers // - source code snippet (assuming the file is accessible) -// - variables name and values (if not optimized out) +// - variable names (if not optimized out) +// - variable values (not supported by backward-cpp) // - You need to link with the lib "dwarf": // - apt-get install libdwarf-dev // - g++/clang++ -ldwarf ... @@ -240,13 +257,10 @@ # endif # endif -# if BACKWARD_HAS_BACKTRACE_SYMBOL == 1 -# include -# endif - # if (BACKWARD_HAS_BACKTRACE == 1) || (BACKWARD_HAS_BACKTRACE_SYMBOL == 1) // then we shall rely on backtrace # include +# include # endif #endif // defined(BACKWARD_SYSTEM_LINUX) @@ -258,10 +272,16 @@ // #define BACKWARD_HAS_UNWIND 1 // - unwind comes from libgcc, but I saw an equivalent inside clang itself. // - with unwind, the stacktrace is as accurate as it can possibly be, since -// this is used by the C++ runtime in gcc/clang for stack unwinding on +// this is used by the C++ runtine in gcc/clang for stack unwinding on // exception. // - normally libgcc is already linked to your program by default. // +// #define BACKWARD_HAS_LIBUNWIND 1 +// - libunwind comes from clang, which implements an API compatible version. +// - libunwind provides, in some cases, a more accurate stacktrace as it knows +// to decode signal handler frames and lets us edit the context registers when +// unwinding, allowing stack traces over bad function references. +// // #define BACKWARD_HAS_BACKTRACE == 1 // - backtrace is available by default, though it does not produce as much // information as another library might. @@ -273,11 +293,14 @@ // # if BACKWARD_HAS_UNWIND == 1 # elif BACKWARD_HAS_BACKTRACE == 1 +# elif BACKWARD_HAS_LIBUNWIND == 1 # else # undef BACKWARD_HAS_UNWIND # define BACKWARD_HAS_UNWIND 1 # undef BACKWARD_HAS_BACKTRACE # define BACKWARD_HAS_BACKTRACE 0 +# undef BACKWARD_HAS_LIBUNWIND +# define BACKWARD_HAS_LIBUNWIND 0 # endif // On Darwin, backward can extract detailed information about a stack trace @@ -296,7 +319,6 @@ # undef BACKWARD_HAS_BACKTRACE_SYMBOL # define BACKWARD_HAS_BACKTRACE_SYMBOL 1 # endif - # include # include # include @@ -315,14 +337,16 @@ # include # include -# include +# include typedef SSIZE_T ssize_t; -# define NOMINMAX -# include +# ifndef NOMINMAX +# define NOMINMAX +# endif +# include # include -# include +# include # include # ifndef __clang__ @@ -330,8 +354,10 @@ typedef SSIZE_T ssize_t; # define NOINLINE __declspec(noinline) # endif -# pragma comment(lib, "psapi.lib") -# pragma comment(lib, "dbghelp.lib") +# ifdef _MSC_VER +# pragma comment(lib, "psapi.lib") +# pragma comment(lib, "dbghelp.lib") +# endif // Comment / packing is from stackoverflow: // https://stackoverflow.com/questions/6205981/windows-c-stack-trace-from-a-running-app/28276227#28276227 @@ -376,6 +402,11 @@ extern "C" uintptr_t _Unwind_GetIPInfo(_Unwind_Context*, int*); #endif // BACKWARD_HAS_UNWIND == 1 +#if BACKWARD_HAS_LIBUNWIND == 1 +# define UNW_LOCAL_ONLY +# include +#endif // BACKWARD_HAS_LIBUNWIND == 1 + #ifdef BACKWARD_ATLEAST_CXX11 # include # include // for std::swap @@ -567,7 +598,7 @@ class handle { void update(T new_val) { _val = new_val; - _empty = static_cast(new_val); + _empty = !static_cast(new_val); } operator const dummy*() const @@ -728,14 +759,14 @@ class StackTraceImpl { size_t size() const { return 0; } Trace operator[](size_t) const { return Trace(); } size_t load_here(size_t = 0) { return 0; } - size_t load_from(void*, size_t = 0) { return 0; } + size_t load_from(void*, size_t = 0, void* = nullptr, void* = nullptr) { return 0; } size_t thread_id() const { return 0; } void skip_n_firsts(size_t) {} }; class StackTraceImplBase { public: - StackTraceImplBase() : _thread_id(0), _skip(0) {} + StackTraceImplBase() : _thread_id(0), _skip(0), _context(nullptr), _error_addr(nullptr) {} size_t thread_id() const { return _thread_id; } @@ -764,16 +795,24 @@ class StackTraceImplBase { #endif } + void set_context(void* context) { _context = context; } + void* context() const { return _context; } + + void set_error_addr(void* error_addr) { _error_addr = error_addr; } + void* error_addr() const { return _error_addr; } + size_t skip_n_firsts() const { return _skip; } private: size_t _thread_id; size_t _skip; + void* _context; + void* _error_addr; }; class StackTraceImplHolder : public StackTraceImplBase { public: - size_t size() const { return _stacktrace.size() ? _stacktrace.size() - skip_n_firsts() : 0; } + size_t size() const { return (_stacktrace.size() >= skip_n_firsts()) ? _stacktrace.size() - skip_n_firsts() : 0; } Trace operator[](size_t idx) const { if (idx >= size()) { @@ -861,9 +900,11 @@ template <> class StackTraceImpl : public StackTraceImplHolder { public: NOINLINE - size_t load_here(size_t depth = 32) + size_t load_here(size_t depth = 32, void* context = nullptr, void* error_addr = nullptr) { load_thread_info(); + set_context(context); + set_error_addr(error_addr); if (depth == 0) { return 0; } @@ -873,9 +914,9 @@ class StackTraceImpl : public StackTraceImplHolder { skip_n_firsts(0); return size(); } - size_t load_from(void* addr, size_t depth = 32) + size_t load_from(void* addr, size_t depth = 32, void* context = nullptr, void* error_addr = nullptr) { - load_here(depth + 8); + load_here(depth + 8, context, error_addr); for (size_t i = 0; i < _stacktrace.size(); ++i) { if (_stacktrace[i] == addr) { @@ -897,14 +938,182 @@ class StackTraceImpl : public StackTraceImplHolder { }; }; +#elif BACKWARD_HAS_LIBUNWIND == 1 + +template <> +class StackTraceImpl : public StackTraceImplHolder { +public: + __attribute__((noinline)) size_t load_here(size_t depth = 32, void* _context = nullptr, void* _error_addr = nullptr) + { + set_context(_context); + set_error_addr(_error_addr); + load_thread_info(); + if (depth == 0) { + return 0; + } + _stacktrace.resize(depth + 1); + + int result = 0; + + unw_context_t ctx; + size_t index = 0; + + // Add the tail call. If the Instruction Pointer is the crash address it + // means we got a bad function pointer dereference, so we "unwind" the + // bad pointer manually by using the return address pointed to by the + // Stack Pointer as the Instruction Pointer and letting libunwind do + // the rest + + if (context()) { + ucontext_t* uctx = reinterpret_cast(context()); +# ifdef REG_RIP // x86_64 + if (uctx->uc_mcontext.gregs[REG_RIP] == reinterpret_cast(error_addr())) { + uctx->uc_mcontext.gregs[REG_RIP] = *reinterpret_cast(uctx->uc_mcontext.gregs[REG_RSP]); + } + _stacktrace[index] = reinterpret_cast(uctx->uc_mcontext.gregs[REG_RIP]); + ++index; + ctx = *reinterpret_cast(uctx); +# elif defined(REG_EIP) // x86_32 + if (uctx->uc_mcontext.gregs[REG_EIP] == reinterpret_cast(error_addr())) { + uctx->uc_mcontext.gregs[REG_EIP] = *reinterpret_cast(uctx->uc_mcontext.gregs[REG_ESP]); + } + _stacktrace[index] = reinterpret_cast(uctx->uc_mcontext.gregs[REG_EIP]); + ++index; + ctx = *reinterpret_cast(uctx); +# elif defined(__arm__) + // libunwind uses its own context type for ARM unwinding. + // Copy the registers from the signal handler's context so we can + // unwind + unw_getcontext(&ctx); + ctx.regs[UNW_ARM_R0] = uctx->uc_mcontext.arm_r0; + ctx.regs[UNW_ARM_R1] = uctx->uc_mcontext.arm_r1; + ctx.regs[UNW_ARM_R2] = uctx->uc_mcontext.arm_r2; + ctx.regs[UNW_ARM_R3] = uctx->uc_mcontext.arm_r3; + ctx.regs[UNW_ARM_R4] = uctx->uc_mcontext.arm_r4; + ctx.regs[UNW_ARM_R5] = uctx->uc_mcontext.arm_r5; + ctx.regs[UNW_ARM_R6] = uctx->uc_mcontext.arm_r6; + ctx.regs[UNW_ARM_R7] = uctx->uc_mcontext.arm_r7; + ctx.regs[UNW_ARM_R8] = uctx->uc_mcontext.arm_r8; + ctx.regs[UNW_ARM_R9] = uctx->uc_mcontext.arm_r9; + ctx.regs[UNW_ARM_R10] = uctx->uc_mcontext.arm_r10; + ctx.regs[UNW_ARM_R11] = uctx->uc_mcontext.arm_fp; + ctx.regs[UNW_ARM_R12] = uctx->uc_mcontext.arm_ip; + ctx.regs[UNW_ARM_R13] = uctx->uc_mcontext.arm_sp; + ctx.regs[UNW_ARM_R14] = uctx->uc_mcontext.arm_lr; + ctx.regs[UNW_ARM_R15] = uctx->uc_mcontext.arm_pc; + + // If we have crashed in the PC use the LR instead, as this was + // a bad function dereference + if (reinterpret_cast(error_addr()) == uctx->uc_mcontext.arm_pc) { + ctx.regs[UNW_ARM_R15] = uctx->uc_mcontext.arm_lr - sizeof(unsigned long); + } + _stacktrace[index] = reinterpret_cast(ctx.regs[UNW_ARM_R15]); + ++index; +# elif defined(__APPLE__) && defined(__x86_64__) + unw_getcontext(&ctx); + // OS X's implementation of libunwind uses its own context object + // so we need to convert the passed context to libunwind's format + // (information about the data layout taken from unw_getcontext.s + // in Apple's libunwind source + ctx.data[0] = uctx->uc_mcontext->__ss.__rax; + ctx.data[1] = uctx->uc_mcontext->__ss.__rbx; + ctx.data[2] = uctx->uc_mcontext->__ss.__rcx; + ctx.data[3] = uctx->uc_mcontext->__ss.__rdx; + ctx.data[4] = uctx->uc_mcontext->__ss.__rdi; + ctx.data[5] = uctx->uc_mcontext->__ss.__rsi; + ctx.data[6] = uctx->uc_mcontext->__ss.__rbp; + ctx.data[7] = uctx->uc_mcontext->__ss.__rsp; + ctx.data[8] = uctx->uc_mcontext->__ss.__r8; + ctx.data[9] = uctx->uc_mcontext->__ss.__r9; + ctx.data[10] = uctx->uc_mcontext->__ss.__r10; + ctx.data[11] = uctx->uc_mcontext->__ss.__r11; + ctx.data[12] = uctx->uc_mcontext->__ss.__r12; + ctx.data[13] = uctx->uc_mcontext->__ss.__r13; + ctx.data[14] = uctx->uc_mcontext->__ss.__r14; + ctx.data[15] = uctx->uc_mcontext->__ss.__r15; + ctx.data[16] = uctx->uc_mcontext->__ss.__rip; + + // If the IP is the same as the crash address we have a bad function + // dereference The caller's address is pointed to by %rsp, so we + // dereference that value and set it to be the next frame's IP. + if (uctx->uc_mcontext->__ss.__rip == reinterpret_cast<__uint64_t>(error_addr())) { + ctx.data[16] = *reinterpret_cast<__uint64_t*>(uctx->uc_mcontext->__ss.__rsp); + } + _stacktrace[index] = reinterpret_cast(ctx.data[16]); + ++index; +# elif defined(__APPLE__) + unw_getcontext(&ctx) + // TODO: Convert the ucontext_t to libunwind's unw_context_t like + // we do in 64 bits + if (ctx.uc_mcontext->__ss.__eip == reinterpret_cast(error_addr())) + { + ctx.uc_mcontext->__ss.__eip = ctx.uc_mcontext->__ss.__esp; + } + _stacktrace[index] = reinterpret_cast(ctx.uc_mcontext->__ss.__eip); + ++index; +# endif + } + + unw_cursor_t cursor; + if (context()) { +# if defined(UNW_INIT_SIGNAL_FRAME) + result = unw_init_local2(&cursor, &ctx, UNW_INIT_SIGNAL_FRAME); +# else + result = unw_init_local(&cursor, &ctx); +# endif + } + else { + unw_getcontext(&ctx); + ; + result = unw_init_local(&cursor, &ctx); + } + + if (result != 0) + return 1; + + unw_word_t ip = 0; + + while (index <= depth && unw_step(&cursor) > 0) { + result = unw_get_reg(&cursor, UNW_REG_IP, &ip); + if (result == 0) { + _stacktrace[index] = reinterpret_cast(--ip); + ++index; + } + } + --index; + + _stacktrace.resize(index + 1); + skip_n_firsts(0); + return size(); + } + + size_t load_from(void* addr, size_t depth = 32, void* context = nullptr, void* error_addr = nullptr) + { + load_here(depth + 8, context, error_addr); + + for (size_t i = 0; i < _stacktrace.size(); ++i) { + if (_stacktrace[i] == addr) { + skip_n_firsts(i); + _stacktrace[i] = (void*)((uintptr_t)_stacktrace[i]); + break; + } + } + + _stacktrace.resize(std::min(_stacktrace.size(), skip_n_firsts() + depth)); + return size(); + } +}; + #elif defined(BACKWARD_HAS_BACKTRACE) template <> class StackTraceImpl : public StackTraceImplHolder { public: NOINLINE - size_t load_here(size_t depth = 32) + size_t load_here(size_t depth = 32, void* context = nullptr, void* error_addr = nullptr) { + set_context(context); + set_error_addr(error_addr); load_thread_info(); if (depth == 0) { return 0; @@ -916,9 +1125,9 @@ class StackTraceImpl : public StackTraceImplHolder { return size(); } - size_t load_from(void* addr, size_t depth = 32) + size_t load_from(void* addr, size_t depth = 32, void* context = nullptr, void* error_addr = nullptr) { - load_here(depth + 8); + load_here(depth + 8, context, error_addr); for (size_t i = 0; i < _stacktrace.size(); ++i) { if (_stacktrace[i] == addr) { @@ -945,9 +1154,10 @@ class StackTraceImpl : public StackTraceImplHolder { void set_thread_handle(HANDLE handle) { thd_ = handle; } NOINLINE - size_t load_here(size_t depth = 32) + size_t load_here(size_t depth = 32, void* context = nullptr, void* error_addr = nullptr) { - + set_context(static_cast(context)); + set_error_addr(error_addr); CONTEXT localCtx; // used when no context is provided if (depth == 0) { @@ -1009,9 +1219,9 @@ class StackTraceImpl : public StackTraceImplHolder { return size(); } - size_t load_from(void* addr, size_t depth = 32) + size_t load_from(void* addr, size_t depth = 32, void* context = nullptr, void* error_addr = nullptr) { - load_here(depth + 8); + load_here(depth + 8, context, error_addr); for (size_t i = 0; i < _stacktrace.size(); ++i) { if (_stacktrace[i] == addr) { @@ -1037,24 +1247,24 @@ class StackTrace : public StackTraceImpl { /*************** TRACE RESOLVER ***************/ -template -class TraceResolverImpl; +class TraceResolverImplBase { +public: + virtual ~TraceResolverImplBase() {} -#ifdef BACKWARD_SYSTEM_UNKNOWN + virtual void load_addresses(void* const* addresses, int address_count) + { + (void)addresses; + (void)address_count; + } -template <> -class TraceResolverImpl { -public: template - void load_stacktrace(ST&) + void load_stacktrace(ST& st) { + load_addresses(st.begin(), (int)st.size()); } - ResolvedTrace resolve(ResolvedTrace t) { return t; } -}; -#endif + virtual ResolvedTrace resolve(ResolvedTrace t) { return t; } -class TraceResolverImplBase { protected: std::string demangle(const char* funcname) { return _demangler.demangle(funcname); } @@ -1062,6 +1272,17 @@ class TraceResolverImplBase { details::demangler _demangler; }; +template +class TraceResolverImpl; + +#ifdef BACKWARD_SYSTEM_UNKNOWN + +template <> +class TraceResolverImpl : public TraceResolverImplBase { +}; + +#endif + #ifdef BACKWARD_SYSTEM_LINUX class TraceResolverLinuxBase : public TraceResolverImplBase { @@ -1078,6 +1299,12 @@ class TraceResolverLinuxBase : public TraceResolverImplBase { // variable; In that case, we actually open /proc/self/exe, which // is always the actual executable (even if it was deleted/replaced!) // but display the path that /proc/self/exe links to. + // However, this right away reduces probability of successful symbol + // resolution, because libbfd may try to find *.debug files in the + // same dir, in case symbols are stripped. As a result, it may try + // to find a file /proc/self/.debug, which obviously does + // not exist. /proc/self/exe is a last resort. First load attempt + // should go for the original executable file path. symbol_info.dli_fname = "/proc/self/exe"; return exec_path_; } @@ -1129,17 +1356,15 @@ class TraceResolverLinuxImpl; template <> class TraceResolverLinuxImpl : public TraceResolverLinuxBase { public: - template - void load_stacktrace(ST& st) + void load_addresses(void* const* addresses, int address_count) override { - using namespace details; - if (st.size() == 0) { + if (address_count == 0) { return; } - _symbols.reset(backtrace_symbols(st.begin(), (int)st.size())); + _symbols.reset(backtrace_symbols(addresses, address_count)); } - ResolvedTrace resolve(ResolvedTrace trace) + ResolvedTrace resolve(ResolvedTrace trace) override { char* filename = _symbols[trace.idx]; char* funcname = filename; @@ -1177,12 +1402,7 @@ class TraceResolverLinuxImpl : public TraceResolverL public: TraceResolverLinuxImpl() : _bfd_loaded(false) {} - template - void load_stacktrace(ST&) - { - } - - ResolvedTrace resolve(ResolvedTrace trace) + ResolvedTrace resolve(ResolvedTrace trace) override { Dl_info symbol_info; @@ -1213,9 +1433,45 @@ class TraceResolverLinuxImpl : public TraceResolverL } trace.object_filename = resolve_exec_path(symbol_info); - bfd_fileobject& fobj = load_object_with_bfd(symbol_info.dli_fname); - if (!fobj.handle) { - return trace; // sad, we couldn't load the object :( + bfd_fileobject* fobj; + // Before rushing to resolution need to ensure the executable + // file still can be used. For that compare inode numbers of + // what is stored by the executable's file path, and in the + // dli_fname, which not necessarily equals to the executable. + // It can be a shared library, or /proc/self/exe, and in the + // latter case has drawbacks. See the exec path resolution for + // details. In short - the dli object should be used only as + // the last resort. + // If inode numbers are equal, it is known dli_fname and the + // executable file are the same. This is guaranteed by Linux, + // because if the executable file is changed/deleted, it will + // be done in a new inode. The old file will be preserved in + // /proc/self/exe, and may even have inode 0. The latter can + // happen if the inode was actually reused, and the file was + // kept only in the main memory. + // + struct stat obj_stat; + struct stat dli_stat; + if (stat(trace.object_filename.c_str(), &obj_stat) == 0 && stat(symbol_info.dli_fname, &dli_stat) == 0 && + obj_stat.st_ino == dli_stat.st_ino) { + // The executable file, and the shared object containing the + // address are the same file. Safe to use the original path. + // this is preferable. Libbfd will search for stripped debug + // symbols in the same directory. + fobj = load_object_with_bfd(trace.object_filename); + } + else { + // The original object file was *deleted*! The only hope is + // that the debug symbols are either inside the shared + // object file, or are in the same directory, and this is + // not /proc/self/exe. + fobj = nullptr; + } + if (fobj == nullptr || !fobj->handle) { + fobj = load_object_with_bfd(symbol_info.dli_fname); + if (!fobj->handle) { + return trace; + } } find_sym_result* details_selected; // to be filled. @@ -1346,7 +1602,7 @@ class TraceResolverLinuxImpl : public TraceResolverL typedef details::hashtable::type fobj_bfd_map_t; fobj_bfd_map_t _fobj_bfd_map; - bfd_fileobject& load_object_with_bfd(const std::string& filename_object) + bfd_fileobject* load_object_with_bfd(const std::string& filename_object) { using namespace details; @@ -1358,11 +1614,11 @@ class TraceResolverLinuxImpl : public TraceResolverL fobj_bfd_map_t::iterator it = _fobj_bfd_map.find(filename_object); if (it != _fobj_bfd_map.end()) { - return it->second; + return &it->second; } // this new object is empty for now. - bfd_fileobject& r = _fobj_bfd_map[filename_object]; + bfd_fileobject* r = &_fobj_bfd_map[filename_object]; // we do the work temporary in this one; bfd_handle_t bfd_handle; @@ -1407,9 +1663,9 @@ class TraceResolverLinuxImpl : public TraceResolverL return r; // damned, that's a stripped file that you got there! } - r.handle = move(bfd_handle); - r.symtab = move(symtab); - r.dynamic_symtab = move(dynamic_symtab); + r->handle = move(bfd_handle); + r->symtab = move(symtab); + r->dynamic_symtab = move(dynamic_symtab); return r; } @@ -1428,15 +1684,15 @@ class TraceResolverLinuxImpl : public TraceResolverL find_sym_result result; }; - find_sym_result find_symbol_details(bfd_fileobject& fobj, void* addr, void* base_addr) + find_sym_result find_symbol_details(bfd_fileobject* fobj, void* addr, void* base_addr) { find_sym_context context; context.self = this; - context.fobj = &fobj; + context.fobj = fobj; context.addr = addr; context.base_addr = base_addr; context.result.found = false; - bfd_map_over_sections(fobj.handle.get(), &find_in_section_trampoline, static_cast(&context)); + bfd_map_over_sections(fobj->handle.get(), &find_in_section_trampoline, static_cast(&context)); return context.result; } @@ -1446,7 +1702,7 @@ class TraceResolverLinuxImpl : public TraceResolverL context->self->find_in_section( reinterpret_cast(context->addr), reinterpret_cast(context->base_addr), - *context->fobj, + context->fobj, section, context->result); } @@ -1454,7 +1710,7 @@ class TraceResolverLinuxImpl : public TraceResolverL void find_in_section( bfd_vma addr, bfd_vma base_addr, - bfd_fileobject& fobj, + bfd_fileobject* fobj, asection* section, find_sym_result& result) { @@ -1462,14 +1718,14 @@ class TraceResolverLinuxImpl : public TraceResolverL return; # ifdef bfd_get_section_flags - if ((bfd_get_section_flags(fobj.handle.get(), section) & SEC_ALLOC) == 0) + if ((bfd_get_section_flags(fobj->handle.get(), section) & SEC_ALLOC) == 0) # else if ((bfd_section_flags(section) & SEC_ALLOC) == 0) # endif return; // a debug section is never loaded automatically. # ifdef bfd_get_section_vma - bfd_vma sec_addr = bfd_get_section_vma(fobj.handle.get(), section); + bfd_vma sec_addr = bfd_get_section_vma(fobj->handle.get(), section); # else bfd_vma sec_addr = bfd_section_vma(section); # endif @@ -1491,22 +1747,22 @@ class TraceResolverLinuxImpl : public TraceResolverL # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" # endif - if (!result.found && fobj.symtab) { + if (!result.found && fobj->symtab) { result.found = bfd_find_nearest_line( - fobj.handle.get(), + fobj->handle.get(), section, - fobj.symtab.get(), + fobj->symtab.get(), addr - sec_addr, &result.filename, &result.funcname, &result.line); } - if (!result.found && fobj.dynamic_symtab) { + if (!result.found && fobj->dynamic_symtab) { result.found = bfd_find_nearest_line( - fobj.handle.get(), + fobj->handle.get(), section, - fobj.dynamic_symtab.get(), + fobj->dynamic_symtab.get(), addr - sec_addr, &result.filename, &result.funcname, @@ -1517,14 +1773,14 @@ class TraceResolverLinuxImpl : public TraceResolverL # endif } - ResolvedTrace::source_locs_t backtrace_inliners(bfd_fileobject& fobj, find_sym_result previous_result) + ResolvedTrace::source_locs_t backtrace_inliners(bfd_fileobject* fobj, find_sym_result previous_result) { // This function can be called ONLY after a SUCCESSFUL call to // find_symbol_details. The state is global to the bfd_handle. ResolvedTrace::source_locs_t results; while (previous_result.found) { find_sym_result result; - result.found = bfd_find_inliner_info(fobj.handle.get(), &result.filename, &result.funcname, &result.line); + result.found = bfd_find_inliner_info(fobj->handle.get(), &result.filename, &result.funcname, &result.line); if (result.found) /* and not ( cstrings_eq(previous_result.filename, @@ -1565,12 +1821,7 @@ class TraceResolverLinuxImpl : public TraceResolverLi public: TraceResolverLinuxImpl() : _dwfl_handle_initialized(false) {} - template - void load_stacktrace(ST&) - { - } - - ResolvedTrace resolve(ResolvedTrace trace) + ResolvedTrace resolve(ResolvedTrace trace) override { using namespace details; @@ -1861,9 +2112,9 @@ class TraceResolverLinuxImpl : public TraceResolverLi static const char* die_call_file(Dwarf_Die* die) { Dwarf_Attribute attr_mem; - Dwarf_Sword file_idx = 0; + Dwarf_Word file_idx = 0; - dwarf_formsdata(dwarf_attr(die, DW_AT_call_file, &attr_mem), &file_idx); + dwarf_formudata(dwarf_attr(die, DW_AT_call_file, &attr_mem), &file_idx); if (file_idx == 0) { return 0; @@ -1894,12 +2145,7 @@ class TraceResolverLinuxImpl : public TraceResolve public: TraceResolverLinuxImpl() : _dwarf_loaded(false) {} - template - void load_stacktrace(ST&) - { - } - - ResolvedTrace resolve(ResolvedTrace trace) + ResolvedTrace resolve(ResolvedTrace trace) override { // trace.addr is a virtual address in memory pointing to some code. // Let's try to find from which loaded object it comes from. @@ -2901,7 +3147,7 @@ class TraceResolverLinuxImpl : public TraceResolve trace.object_function = demangler.demangle(linkage); dwarf_dealloc(dwarf, linkage, DW_DLA_STRING); } - dwarf_dealloc(dwarf, name, DW_DLA_ATTR); + dwarf_dealloc(dwarf, attr_mem, DW_DLA_ATTR); } break; @@ -3112,12 +3358,12 @@ class TraceResolverLinuxImpl : public TraceResolve { Dwarf_Attribute attr_mem; Dwarf_Error error = DW_DLE_NE; - Dwarf_Signed file_index; + Dwarf_Unsigned file_index; std::string file; if (dwarf_attr(die, DW_AT_call_file, &attr_mem, &error) == DW_DLV_OK) { - if (dwarf_formsdata(attr_mem, &file_index, &error) != DW_DLV_OK) { + if (dwarf_formudata(attr_mem, &file_index, &error) != DW_DLV_OK) { file_index = 0; } dwarf_dealloc(dwarf, attr_mem, DW_DLA_ATTR); @@ -3129,8 +3375,9 @@ class TraceResolverLinuxImpl : public TraceResolve char** srcfiles = 0; Dwarf_Signed file_count = 0; if (dwarf_srcfiles(cu_die, &srcfiles, &file_count, &error) == DW_DLV_OK) { - if (file_index <= file_count) + if (file_count > 0 && file_index <= static_cast(file_count)) { file = std::string(srcfiles[file_index - 1]); + } // Deallocate all strings! for (int i = 0; i < file_count; ++i) { @@ -3259,17 +3506,15 @@ class TraceResolverDarwinImpl; template <> class TraceResolverDarwinImpl : public TraceResolverImplBase { public: - template - void load_stacktrace(ST& st) + void load_addresses(void* const* addresses, int address_count) override { - using namespace details; - if (st.size() == 0) { + if (address_count == 0) { return; } - _symbols.reset(backtrace_symbols(st.begin(), (int)st.size())); + _symbols.reset(backtrace_symbols(addresses, address_count)); } - ResolvedTrace resolve(ResolvedTrace trace) + ResolvedTrace resolve(ResolvedTrace trace) override { // parse: // + @@ -3368,9 +3613,9 @@ class get_mod_info { ret.base_address = mi.lpBaseOfDll; ret.load_size = mi.SizeOfImage; - GetModuleFileNameEx(process, module, temp, sizeof(temp)); + GetModuleFileNameExA(process, module, temp, sizeof(temp)); ret.image_name = temp; - GetModuleBaseName(process, module, temp, sizeof(temp)); + GetModuleBaseNameA(process, module, temp, sizeof(temp)); ret.module_name = temp; std::vector img(ret.image_name.begin(), ret.image_name.end()); std::vector mod(ret.module_name.begin(), ret.module_name.end()); @@ -3380,7 +3625,7 @@ class get_mod_info { }; template <> -class TraceResolverImpl { +class TraceResolverImpl : public TraceResolverImplBase { public: TraceResolverImpl() { @@ -3404,11 +3649,6 @@ class TraceResolverImpl { image_type = h->FileHeader.Machine; } - template - void load_stacktrace(ST&) - { - } - static const int max_sym_len = 255; struct symbol_t { SYMBOL_INFO sym; @@ -3417,31 +3657,32 @@ class TraceResolverImpl { DWORD64 displacement; - ResolvedTrace resolve(ResolvedTrace t) + ResolvedTrace resolve(ResolvedTrace t) override { HANDLE process = GetCurrentProcess(); char name[256]; - memset(&sym, 0, sizeof sym); + memset(&sym, 0, sizeof(sym)); sym.sym.SizeOfStruct = sizeof(SYMBOL_INFO); sym.sym.MaxNameLen = max_sym_len; if (!SymFromAddr(process, (ULONG64)t.addr, &displacement, &sym.sym)) { // TODO: error handling everywhere - LPTSTR lpMsgBuf; + char* lpMsgBuf; DWORD dw = GetLastError(); - FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - dw, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR)&lpMsgBuf, - 0, - NULL); - - printf(lpMsgBuf); + if (FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + dw, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (char*)&lpMsgBuf, + 0, + NULL)) { + std::fprintf(stderr, "%s\n", lpMsgBuf); + LocalFree(lpMsgBuf); + } // abort(); } @@ -3691,7 +3932,7 @@ class cfile_streambuf : public std::streambuf { int_type underflow() override { return traits_type::eof(); } int_type overflow(int_type ch) override { - if (traits_type::not_eof(ch) && fwrite(&ch, sizeof ch, 1, sink) == 1) { + if (traits_type::not_eof(ch) && fputc(ch, sink) != EOF) { return ch; } return traits_type::eof(); @@ -4029,11 +4270,17 @@ class SignalHandling { # elif defined(__arm__) error_addr = reinterpret_cast(uctx->uc_mcontext.arm_pc); # elif defined(__aarch64__) +# if defined(__APPLE__) + error_addr = reinterpret_cast(uctx->uc_mcontext->__ss.__pc); +# else error_addr = reinterpret_cast(uctx->uc_mcontext.pc); +# endif # elif defined(__mips__) error_addr = reinterpret_cast(reinterpret_cast(&uctx->uc_mcontext)->sc_pc); # elif defined(__ppc__) || defined(__powerpc) || defined(__powerpc__) || defined(__POWERPC__) error_addr = reinterpret_cast(uctx->uc_mcontext.regs->nip); +# elif defined(__riscv) + error_addr = reinterpret_cast(uctx->uc_mcontext.__gregs[REG_PC]); # elif defined(__s390x__) error_addr = reinterpret_cast(uctx->uc_mcontext.psw.addr); # elif defined(__APPLE__) && defined(__x86_64__) @@ -4044,10 +4291,10 @@ class SignalHandling { # warning ":/ sorry, ain't know no nothing none not of your architecture!" # endif if (error_addr) { - st.load_from(error_addr, 32); + st.load_from(error_addr, 32, reinterpret_cast(uctx), info->si_addr); } else { - st.load_here(32); + st.load_here(32, reinterpret_cast(uctx), info->si_addr); } Printer printer; @@ -4117,8 +4364,10 @@ class SignalHandling { signal(SIGABRT, signal_handler); _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT); - set_terminate(&terminator); - set_unexpected(&terminator); + std::set_terminate(&terminator); +# ifndef BACKWARD_ATLEAST_CXX17 + std::set_unexpected(&terminator); +# endif _set_purecall_handler(&terminator); _set_invalid_parameter_handler(&invalid_parameter_handler); } @@ -4266,9 +4515,8 @@ class SignalHandling { StackTrace st; st.set_machine_type(printer.resolver().machine_type()); - st.set_context(ctx()); st.set_thread_handle(thread_handle()); - st.load_here(32 + skip_frames); + st.load_here(32 + skip_frames, ctx()); st.skip_n_firsts(skip_frames); printer.address = true; @@ -4292,4 +4540,3 @@ class SignalHandling { } // namespace backward #endif /* H_GUARD */ -// clang-format on diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ddec1a8..06bf89a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,4 +1,5 @@ project(aws-lambda-runtime-tests LANGUAGES CXX) + find_package(AWSSDK COMPONENTS lambda iam) add_executable(${PROJECT_NAME} diff --git a/tests/resources/lambda_function.cpp b/tests/resources/lambda_function.cpp index 43f3dac..7cd62e5 100644 --- a/tests/resources/lambda_function.cpp +++ b/tests/resources/lambda_function.cpp @@ -1,6 +1,7 @@ #include #include +#include #include #include #include @@ -26,12 +27,19 @@ invocation_response binary_response(invocation_request const& /*request*/) return invocation_response::success(png, "image/png"); } +invocation_response crash_backtrace(invocation_request const& /*request*/) +{ + throw std::runtime_error("barf"); + return invocation_response::failure("unreachable", "unreachable"); +} + int main(int argc, char* argv[]) { std::unordered_map> handlers; handlers.emplace("echo_success", echo_success); handlers.emplace("echo_failure", echo_failure); handlers.emplace("binary_response", binary_response); + handlers.emplace("crash_backtrace", crash_backtrace); if (argc < 2) { aws::logging::log_error("lambda_fun", "Missing handler argument. Exiting."); diff --git a/tests/runtime_tests.cpp b/tests/runtime_tests.cpp index 9d0ee72..a65a267 100644 --- a/tests/runtime_tests.cpp +++ b/tests/runtime_tests.cpp @@ -11,13 +11,16 @@ #include #include #include -#include #include +#include #include "gtest/gtest.h" +#include #include +#include #include #include #include +#include extern std::string aws_prefix; @@ -63,6 +66,7 @@ struct LambdaRuntimeTest : public ::testing::Test { delete_function(build_resource_name("echo_success"), false /*assert*/); delete_function(build_resource_name("echo_failure"), false /*assert*/); delete_function(build_resource_name("binary_response"), false /*assert*/); + delete_function(build_resource_name("crash_backtrace"), false /*assert*/); } Aws::String get_role_arn(Aws::String const& role_name) @@ -217,4 +221,25 @@ TEST_F(LambdaRuntimeTest, binary_response) EXPECT_EQ(expected_length, invoke_outcome.GetResult().GetPayload().tellp()); delete_function(funcname); } + +TEST_F(LambdaRuntimeTest, crash) +{ + Aws::String const funcname = build_resource_name("crash_backtrace"); + create_function(funcname, "crash_backtrace" /*handler_name*/); + Model::InvokeRequest invoke_request; + invoke_request.SetFunctionName(funcname); + invoke_request.SetInvocationType(Model::InvocationType::RequestResponse); + invoke_request.SetLogType(Model::LogType::Tail); + + Model::InvokeOutcome invoke_outcome = m_lambda_client.Invoke(invoke_request); + EXPECT_TRUE(invoke_outcome.IsSuccess()); + EXPECT_EQ(200, invoke_outcome.GetResult().GetStatusCode()); + EXPECT_STREQ("Unhandled", invoke_outcome.GetResult().GetFunctionError().c_str()); + Aws::Utils::Base64::Base64 base64; + auto decoded = base64.Decode(invoke_outcome.GetResult().GetLogResult()); + std::string tail_logs(reinterpret_cast(decoded.GetUnderlyingData()), decoded.GetLength()); + EXPECT_NE(tail_logs.find("Stack trace (most recent call last):"), std::string::npos); + delete_function(funcname); +} + } // namespace From ed43dbb6f72fa21d3dfc2313646cf7291c6572fa Mon Sep 17 00:00:00 2001 From: Bryan Moffatt Date: Tue, 23 Aug 2022 00:58:55 -0700 Subject: [PATCH 60/84] Add AWS CodeBuild workflow and Dockerfile for ArchLinux (#161) --- ci/codebuild/arch-linux.yml | 9 +++++++++ ci/codebuild/build.sh | 6 +++++- ci/docker/arch-linux | 22 ++++++++++++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 ci/codebuild/arch-linux.yml create mode 100644 ci/docker/arch-linux diff --git a/ci/codebuild/arch-linux.yml b/ci/codebuild/arch-linux.yml new file mode 100644 index 0000000..4262f50 --- /dev/null +++ b/ci/codebuild/arch-linux.yml @@ -0,0 +1,9 @@ +version: 0.2 +# This uses the docker image specified in ci/docker/arch-linux +phases: + build: + commands: + - echo Build started on `date` + - ./ci/codebuild/build.sh -DTEST_RESOURCE_PREFIX=lambda-cpp-archbtw + - ./ci/codebuild/run-tests.sh aws-lambda-package-lambda-test-fun + - echo Build completed on `date` diff --git a/ci/codebuild/build.sh b/ci/codebuild/build.sh index 53a9544..8a90d30 100755 --- a/ci/codebuild/build.sh +++ b/ci/codebuild/build.sh @@ -6,6 +6,10 @@ set -euo pipefail cd $CODEBUILD_SRC_DIR mkdir build cd build -cmake .. -GNinja -DBUILD_SHARED_LIBS=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=/install $@ +cmake .. -GNinja \ + -DBUILD_SHARED_LIBS=ON \ + -DCMAKE_BUILD_TYPE=Debug \ + -DENABLE_TESTS=ON \ + -DCMAKE_INSTALL_PREFIX=/install $@ ninja ninja install diff --git a/ci/docker/arch-linux b/ci/docker/arch-linux new file mode 100644 index 0000000..dce1a50 --- /dev/null +++ b/ci/docker/arch-linux @@ -0,0 +1,22 @@ +FROM public.ecr.aws/docker/library/archlinux:latest + +RUN pacman -Sy --noconfirm git +RUN git clone --recurse-submodules https://github.com/aws/aws-sdk-cpp.git +RUN pacman -Sy --noconfirm \ + cmake \ + ninja \ + clang \ + curl \ + zip + + +# Note: (2022-08-23) +# Using -DUSE_OPENSSL=OFF as a workaround to an AWS SDK dependency issue with this distro. +# The current SDK version has a dependency on a static build version of openssl, not available through pacman. +# ref: https://github.com/aws/aws-sdk-cpp/issues/1910 +RUN CC=/usr/bin/clang CXX=/usr/bin/clang++ cmake -Saws-sdk-cpp -Baws-sdk-cpp/build -GNinja \ + -DBUILD_ONLY=lambda \ + -DUSE_OPENSSL=OFF \ + -DENABLE_TESTING=OFF +RUN cmake --build aws-sdk-cpp/build -t install + From f385f53ab6e3f4b247501e39523bb9260cb60e81 Mon Sep 17 00:00:00 2001 From: Ildar Sagdejev Date: Tue, 23 Aug 2022 20:13:48 -0400 Subject: [PATCH 61/84] Updated CMake commands to reflect that ENABLE_UNITY_BUILDS now defaults to ON in the AWS SDK (#156) Co-authored-by: Bryan Moffatt --- ci/codebuild/build-cpp-sdk.sh | 1 - examples/api-gateway/README.md | 3 +-- examples/dynamodb/README.md | 3 +-- examples/s3/README.md | 5 ++--- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/ci/codebuild/build-cpp-sdk.sh b/ci/codebuild/build-cpp-sdk.sh index 59a8748..7f84aab 100755 --- a/ci/codebuild/build-cpp-sdk.sh +++ b/ci/codebuild/build-cpp-sdk.sh @@ -8,7 +8,6 @@ mkdir build cd build cmake .. -GNinja -DBUILD_ONLY="lambda" \ -DCMAKE_BUILD_TYPE=Release \ - -DENABLE_UNITY_BUILD=ON \ -DBUILD_SHARED_LIBS=ON \ -DENABLE_TESTING=OFF \ -DCMAKE_INSTALL_PREFIX=/install $@ diff --git a/examples/api-gateway/README.md b/examples/api-gateway/README.md index d1245fb..720f875 100644 --- a/examples/api-gateway/README.md +++ b/examples/api-gateway/README.md @@ -15,8 +15,7 @@ $ cmake .. -DBUILD_ONLY="core" \ -DCMAKE_BUILD_TYPE=Release \ -DBUILD_SHARED_LIBS=OFF \ -DCUSTOM_MEMORY_MANAGEMENT=OFF \ - -DCMAKE_INSTALL_PREFIX=~/install \ - -DENABLE_UNITY_BUILD=ON + -DCMAKE_INSTALL_PREFIX=~/install $ make $ make install ``` diff --git a/examples/dynamodb/README.md b/examples/dynamodb/README.md index 044877f..ebd6316 100644 --- a/examples/dynamodb/README.md +++ b/examples/dynamodb/README.md @@ -17,8 +17,7 @@ $ cmake .. -DBUILD_ONLY="dynamodb" \ -DCMAKE_BUILD_TYPE=Release \ -DBUILD_SHARED_LIBS=OFF \ -DCUSTOM_MEMORY_MANAGEMENT=OFF \ - -DCMAKE_INSTALL_PREFIX=~/install \ - -DENABLE_UNITY_BUILD=ON + -DCMAKE_INSTALL_PREFIX=~/install $ make -j 4 $ make install diff --git a/examples/s3/README.md b/examples/s3/README.md index 8bc3255..efc0c77 100644 --- a/examples/s3/README.md +++ b/examples/s3/README.md @@ -17,8 +17,7 @@ $ cmake .. -DBUILD_ONLY="s3" \ -DCMAKE_BUILD_TYPE=Release \ -DBUILD_SHARED_LIBS=OFF \ -DCUSTOM_MEMORY_MANAGEMENT=OFF \ - -DCMAKE_INSTALL_PREFIX=~/install \ - -DENABLE_UNITY_BUILD=ON + -DCMAKE_INSTALL_PREFIX=~/install $ make $ make install @@ -34,7 +33,7 @@ $ mkdir build $ cd build $ cmake .. -DCMAKE_BUILD_TYPE=Release \ -DBUILD_SHARED_LIBS=OFF \ - -DCMAKE_INSTALL_PREFIX=~/install \ + -DCMAKE_INSTALL_PREFIX=~/install $ make $ make install ``` From 5928a6f5e2a321657fa4a7f238d6f396c26c5cac Mon Sep 17 00:00:00 2001 From: Bryan Moffatt Date: Tue, 23 Aug 2022 18:41:56 -0700 Subject: [PATCH 62/84] Re-write codebuild.yml and dockerfiles for consistency and code build execution speed (#162) * Start making the CI workflows follow a more common naming convention, workflow structure, put more dependency build into the docker image, etc * Empty commit --- ci/codebuild/alpine-3.15.yml | 11 ++--------- ci/codebuild/amazonlinux-2.yml | 13 +++++-------- ci/codebuild/amazonlinux-2017.03.yml | 15 +++++---------- ci/codebuild/ubuntu-18.04.yml | 12 +++--------- ci/docker/alpine-linux-3.15 | 18 ++++++++++++++++-- ci/docker/amazon-linux-2 | 14 ++++++++++++-- ci/docker/amazon-linux-2017.03 | 24 ++++++++++++++++-------- ci/docker/ubuntu-linux-18.04 | 27 +++++++++++++++++---------- 8 files changed, 76 insertions(+), 58 deletions(-) diff --git a/ci/codebuild/alpine-3.15.yml b/ci/codebuild/alpine-3.15.yml index 6954b97..616fed9 100644 --- a/ci/codebuild/alpine-3.15.yml +++ b/ci/codebuild/alpine-3.15.yml @@ -1,16 +1,9 @@ version: 0.2 # This uses the docker image specified in ci/docker/alpine-linux-3.15 phases: - pre_build: - commands: - - pip install awscli - - ci/codebuild/build-cpp-sdk.sh build: commands: - echo Build started on `date` - - ci/codebuild/build.sh -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DENABLE_TESTS=ON -DTEST_RESOURCE_PREFIX=alpine315 - - ci/codebuild/run-tests.sh aws-lambda-package-lambda-test-fun alpine315 - post_build: - commands: + - ./ci/codebuild/build.sh -DTEST_RESOURCE_PREFIX=lambda-cpp-alpine315 + - ./ci/codebuild/run-tests.sh aws-lambda-package-lambda-test-fun - echo Build completed on `date` - diff --git a/ci/codebuild/amazonlinux-2.yml b/ci/codebuild/amazonlinux-2.yml index 7a5441c..e2f6d76 100644 --- a/ci/codebuild/amazonlinux-2.yml +++ b/ci/codebuild/amazonlinux-2.yml @@ -1,12 +1,9 @@ version: 0.2 phases: - pre_build: - commands: - - yum install -y zip build: commands: - - cmake3 -S . -B build -DBUILD_SHARED_LIBS=ON -DENABLE_TESTS=ON -DTEST_RESOURCE_PREFIX=al2arm -GNinja - - cd build - - ninja-build - - ninja-build aws-lambda-package-lambda-test-fun - - ctest3 --output-on-failure + - echo Build started on `date` + - ./ci/codebuild/build.sh -DTEST_RESOURCE_PREFIX=lambda-cpp-al2_$(arch) + - ./ci/codebuild/run-tests.sh aws-lambda-package-lambda-test-fun + - ./ci/codebuild/run-tests.sh aws-lambda-package-lambda-test-fun-no-glibc + - echo Build completed on `date` \ No newline at end of file diff --git a/ci/codebuild/amazonlinux-2017.03.yml b/ci/codebuild/amazonlinux-2017.03.yml index b5cbcad..d4d0b5c 100644 --- a/ci/codebuild/amazonlinux-2017.03.yml +++ b/ci/codebuild/amazonlinux-2017.03.yml @@ -1,17 +1,12 @@ -version: 0.1 +version: 0.2 # This uses the docker image specified in ci/docker/amazon-linux-2017.03 phases: - pre_build: - commands: - - alias cmake=cmake3 - - ci/codebuild/build-cpp-sdk.sh build: commands: - echo Build started on `date` - - ci/codebuild/build.sh -DENABLE_TESTS=ON -DTEST_RESOURCE_PREFIX=amzn201703 - - ci/codebuild/run-tests.sh aws-lambda-package-lambda-test-fun amzn201703 - - ci/codebuild/run-tests.sh aws-lambda-package-lambda-test-fun-no-glibc amzn201703 - post_build: - commands: + - yum install -y binutils + - ./ci/codebuild/build.sh -DTEST_RESOURCE_PREFIX=lambda-cpp-amzn201703 + - ./ci/codebuild/run-tests.sh aws-lambda-package-lambda-test-fun + - ./ci/codebuild/run-tests.sh aws-lambda-package-lambda-test-fun-no-glibc - echo Build completed on `date` diff --git a/ci/codebuild/ubuntu-18.04.yml b/ci/codebuild/ubuntu-18.04.yml index eee4d57..273fc4c 100644 --- a/ci/codebuild/ubuntu-18.04.yml +++ b/ci/codebuild/ubuntu-18.04.yml @@ -1,15 +1,9 @@ -version: 0.1 +version: 0.2 # This uses the docker image specified in ci/docker/ubuntu-linux-18.04 phases: - pre_build: - commands: - - ci/codebuild/build-cpp-sdk.sh build: commands: - echo Build started on `date` - - ci/codebuild/build.sh -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DENABLE_TESTS=ON -DTEST_RESOURCE_PREFIX=ubuntu1804 - - ci/codebuild/run-tests.sh aws-lambda-package-lambda-test-fun ubuntu1804 - post_build: - commands: + - ./ci/codebuild/build.sh -DTEST_RESOURCE_PREFIX=lambda-cpp-ubuntu1804 + - ./ci/codebuild/run-tests.sh aws-lambda-package-lambda-test-fun - echo Build completed on `date` - diff --git a/ci/docker/alpine-linux-3.15 b/ci/docker/alpine-linux-3.15 index 8b0837e..c8d33b5 100644 --- a/ci/docker/alpine-linux-3.15 +++ b/ci/docker/alpine-linux-3.15 @@ -1,5 +1,19 @@ -FROM alpine:3.15 +FROM public.ecr.aws/docker/library/alpine:3.15 -RUN apk add --no-cache g++ cmake git bash py3-pip libexecinfo-dev ninja curl-dev zlib-dev zip +RUN apk add --no-cache \ + bash \ + cmake \ + curl-dev \ + g++ \ + git \ + libexecinfo-dev \ + ninja \ + openssl-libs-static \ + zlib-dev \ + zip RUN git clone --recurse-submodules https://github.com/aws/aws-sdk-cpp.git +RUN cmake -Saws-sdk-cpp -Baws-sdk-cpp/build -GNinja \ + -DBUILD_ONLY=lambda \ + -DENABLE_TESTING=OFF +RUN cd aws-sdk-cpp/build && ninja && ninja install diff --git a/ci/docker/amazon-linux-2 b/ci/docker/amazon-linux-2 index 787af12..452d1f4 100644 --- a/ci/docker/amazon-linux-2 +++ b/ci/docker/amazon-linux-2 @@ -1,6 +1,16 @@ FROM public.ecr.aws/amazonlinux/amazonlinux:2 -RUN yum install -y cmake3 ninja-build git gcc-c++ openssl-devel curl-devel +RUN yum install -y \ + cmake3 \ + ninja-build \ + git \ + gcc-c++ \ + openssl-devel \ + curl-devel \ + openssl-static \ + zip RUN git clone https://github.com/aws/aws-sdk-cpp --recurse-submodules RUN cmake3 -Saws-sdk-cpp -Baws-sdk-cpp/build -DBUILD_ONLY=lambda -DENABLE_TESTING=OFF -GNinja RUN cd aws-sdk-cpp/build && ninja-build && ninja-build install -RUN yum install -y openssl-static +RUN ln -s /usr/bin/cmake3 /usr/local/bin/cmake +RUN ln -s /usr/bin/ctest3 /usr/local/bin/ctest +RUN ln -s /usr/bin/ninja-build /usr/local/bin/ninja diff --git a/ci/docker/amazon-linux-2017.03 b/ci/docker/amazon-linux-2017.03 index 0ad4621..142dec2 100644 --- a/ci/docker/amazon-linux-2017.03 +++ b/ci/docker/amazon-linux-2017.03 @@ -1,10 +1,18 @@ -FROM amazonlinux:2017.03 +FROM public.ecr.aws/amazonlinux/amazonlinux:2018.03 -RUN yum install gcc64-c++ git ninja-build curl-devel openssl-devel zlib-devel gtest-devel python36-pip zip -y +RUN yum install -y \ + gcc-c++ \ + git \ + ninja-build \ + curl-devel \ + openssl-devel \ + openssl-static \ + zlib-devel \ + gtest-devel \ + zip +RUN curl -fLo cmake-install https://github.com/Kitware/CMake/releases/download/v3.13.0/cmake-3.13.0-Linux-x86_64.sh && \ + sh cmake-install --skip-license --prefix=/usr --exclude-subdirectory; RUN git clone --recurse-submodules https://github.com/aws/aws-sdk-cpp - -RUN curl -fLo cmake-install https://github.com/Kitware/CMake/releases/download/v3.13.0/cmake-3.13.0-Linux-x86_64.sh; \ -sh cmake-install --skip-license --prefix=/usr --exclude-subdirectory; - -RUN pip-3.6 install --upgrade pip - +RUN cmake -Saws-sdk-cpp -Baws-sdk-cpp/build -DBUILD_ONLY=lambda -DENABLE_TESTING=OFF -GNinja +RUN cd aws-sdk-cpp/build && ninja-build && ninja-build install +RUN ln -s /usr/bin/ninja-build /usr/local/bin/ninja diff --git a/ci/docker/ubuntu-linux-18.04 b/ci/docker/ubuntu-linux-18.04 index 0c43c97..3730f57 100644 --- a/ci/docker/ubuntu-linux-18.04 +++ b/ci/docker/ubuntu-linux-18.04 @@ -1,15 +1,22 @@ -FROM ubuntu:18.04 +FROM public.ecr.aws/ubuntu/ubuntu:18.04 -RUN apt-get update; apt-get install git clang clang-tidy clang-format zlib1g-dev libssl-dev libcurl4-openssl-dev wget \ -ninja-build python3-pip zip -y +RUN apt-get update +RUN apt-get install -y \ + git \ + clang \ + zlib1g-dev \ + libssl-dev \ + libcurl4-openssl-dev \ + wget \ + ninja-build \ + zip - -RUN wget -O cmake-install https://github.com/Kitware/CMake/releases/download/v3.13.0/cmake-3.13.0-Linux-x86_64.sh; \ -sh cmake-install --skip-license --prefix=/usr --exclude-subdirectory; - -RUN pip3 install --upgrade pip - -RUN git clone https://github.com/aws/aws-sdk-cpp.git --recurse-submodules +RUN wget -O cmake-install https://github.com/Kitware/CMake/releases/download/v3.13.0/cmake-3.13.0-Linux-x86_64.sh && \ + sh cmake-install --skip-license --prefix=/usr --exclude-subdirectory; RUN update-alternatives --set cc /usr/bin/clang RUN update-alternatives --set c++ /usr/bin/clang++ + +RUN git clone https://github.com/aws/aws-sdk-cpp.git --recurse-submodules +RUN cmake -Saws-sdk-cpp -Baws-sdk-cpp/build -DBUILD_ONLY=lambda -DENABLE_TESTING=OFF -GNinja +RUN cd aws-sdk-cpp/build && ninja && ninja install From 9dd0bdfeaf8992e62b8ca14272fa26fbffae0f0b Mon Sep 17 00:00:00 2001 From: Bryan Moffatt Date: Fri, 26 Aug 2022 21:11:35 -0700 Subject: [PATCH 63/84] CloudFormation template for managing the project's AWS CodeBuild workflows (#159) * CloudFormation template to model the AWS Code Build resources to help maintainers with adding/modifying the CI workflows also adds helper script `ci/update-images.sh` for re-building and re-uploading the `ci/docker/*` images * fix dockerfile name in update-images --- ci/README.md | 14 ++ ci/codebuild.yml | 412 ++++++++++++++++++++++++++++++++++++++++ ci/update-images.sh | 29 +++ tests/runtime_tests.cpp | 6 +- 4 files changed, 460 insertions(+), 1 deletion(-) create mode 100644 ci/README.md create mode 100644 ci/codebuild.yml create mode 100755 ci/update-images.sh diff --git a/ci/README.md b/ci/README.md new file mode 100644 index 0000000..9e50181 --- /dev/null +++ b/ci/README.md @@ -0,0 +1,14 @@ +## AWS CodeBuild Stack Setup + +create or update the stack +``` +aws cloudformation deploy --capabilities CAPABILITY_IAM --stack-name aws-lambda-cpp-ci --template-file codebuild.yml +``` + +(optional) trigger docker build and docker push of the build environment images. +A project to do this is pre-configured in the deployed stack. +``` +aws cloudformation describe-stacks --stack-name aws-lambda-cpp-ci --query "Stacks[].Outputs[].OutputValue" +# run command output from above, will look like: +# aws codebuild start-build --project-name +``` diff --git a/ci/codebuild.yml b/ci/codebuild.yml new file mode 100644 index 0000000..1205407 --- /dev/null +++ b/ci/codebuild.yml @@ -0,0 +1,412 @@ + +Parameters: + GitHub: + Type: String + Default: https://github.com/awslabs/aws-lambda-cpp.git + +Resources: + + ECR: + Type: AWS::ECR::Repository + + LambdaTestRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Principal: + Service: lambda.amazonaws.com + Action: sts:AssumeRole + Policies: + - PolicyName: can-log + PolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Resource: + - !Join [':', [ arn:aws:logs, !Ref AWS::Region, !Ref AWS::AccountId, log-group:/aws/lambda/lambda-cpp-* ] ] + - !Join [':', [ arn:aws:logs, !Ref AWS::Region, !Ref AWS::AccountId, log-group:/aws/lambda/lambda-cpp-*:* ] ] + Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + + LogsAccessRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: codebuild.amazonaws.com + Action: + - sts:AssumeRole + Policies: + - PolicyName: readthelogs + PolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Resource: + - !Join [':', [ arn:aws:logs, !Ref AWS::Region, !Ref AWS::AccountId, log-group:/aws/codebuild/aws-lambda-cpp-ci:* ] ] + Action: + - logs:GetLogEvents + + CodeBuildRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Principal: + Service: codebuild.amazonaws.com + Action: sts:AssumeRole + Policies: + - PolicyName: thepolicy + PolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Resource: + - !Join [':', [ arn:aws:logs, !Ref AWS::Region, !Ref AWS::AccountId, log-group:/aws/codebuild/aws-lambda-cpp-ci ] ] + - !Join [':', [ arn:aws:logs, !Ref AWS::Region, !Ref AWS::AccountId, log-group:/aws/codebuild/aws-lambda-cpp-ci:* ] ] + Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + - Effect: Allow + Resource: + - !Join [ '', [ arn:aws:s3:::codepipeline-, !Ref AWS::Region, -* ] ] + Action: + - s3:PutObject + - s3:GetObject + - s3:GetObjectVersion + - s3:GetBucketAcl + - s3:GetBucketLocation + - Effect: Allow + Resource: + - !Join [ ':', [ arn:aws:codebuild, !Ref AWS::Region, !Ref AWS::AccountId, report-group/test-* ] ] + Action: + - codebuild:CreateReportGroup + - codebuild:CreateReport + - codebuild:UpdateReport + - codebuild:BatchPutTestCases + - codebuild:BatchPutCodeCoverages + - Effect: Allow + Resource: + - '*' + Action: + - ecr:GetAuthorizationToken + - Effect: Allow + Resource: + - !GetAtt ECR.Arn + Action: + # pulling + - ecr:BatchCheckLayerAvailability + - ecr:GetDownloadUrlForLayer + - ecr:BatchGetImage + # pushing + - ecr:CompleteLayerUpload + - ecr:GetAuthorizationToken + - ecr:UploadLayerPart + - ecr:InitiateLayerUpload + - ecr:BatchCheckLayerAvailability + - ecr:PutImage + - Effect: Allow + Resource: + - !GetAtt LambdaTestRole.Arn + Action: + - iam:GetRole + - iam:PassRole + - Effect: Allow + Resource: + - !Join [':', [ arn:aws:lambda, !Ref AWS::Region, !Ref AWS::AccountId, function:lambda-cpp-* ] ] + Action: + - lambda:CreateFunction + - lambda:DeleteFunction + - lambda:InvokeFunction + + UpdateArmBuildEnvironments: + Type: AWS::CodeBuild::Project + Properties: + Artifacts: + Type: NO_ARTIFACTS + BadgeEnabled: True + Visibility: PUBLIC_READ + ConcurrentBuildLimit: 1 + ServiceRole: !GetAtt CodeBuildRole.Arn + ResourceAccessRole: !GetAtt LogsAccessRole.Arn + LogsConfig: + CloudWatchLogs: + Status: ENABLED + GroupName: /aws/codebuild/aws-lambda-cpp-ci + Environment: + ImagePullCredentialsType: CODEBUILD + ComputeType: BUILD_GENERAL1_SMALL + Image: aws/codebuild/amazonlinux2-aarch64-standard:2.0 + Type: ARM_CONTAINER + PrivilegedMode: True + EnvironmentVariables: + - Name: ECR_NAME + Type: PLAINTEXT + Value: !Ref ECR + Source: + Type: GITHUB + Location: !Ref GitHub + BuildSpec: | + version: 0.2 + phases: + build: + commands: + - ./ci/update-images.sh + + UpdateX86BuildEnvironments: + Type: AWS::CodeBuild::Project + Properties: + Artifacts: + Type: NO_ARTIFACTS + BadgeEnabled: True + Visibility: PUBLIC_READ + ConcurrentBuildLimit: 1 + ServiceRole: !GetAtt CodeBuildRole.Arn + ResourceAccessRole: !GetAtt LogsAccessRole.Arn + LogsConfig: + CloudWatchLogs: + Status: ENABLED + GroupName: /aws/codebuild/aws-lambda-cpp-ci + Environment: + ImagePullCredentialsType: CODEBUILD + ComputeType: BUILD_GENERAL1_MEDIUM + Image: aws/codebuild/amazonlinux2-x86_64-standard:4.0 + Type: LINUX_CONTAINER + PrivilegedMode: True + EnvironmentVariables: + - Name: ECR_NAME + Type: PLAINTEXT + Value: !Ref ECR + Source: + Type: GITHUB + Location: !Ref GitHub + BuildSpec: | + version: 0.2 + phases: + build: + commands: + - ./ci/update-images.sh + + + Amazon2Arm: + Type: AWS::CodeBuild::Project + Properties: + Artifacts: + Type: NO_ARTIFACTS + BadgeEnabled: True + Visibility: PUBLIC_READ + ConcurrentBuildLimit: 1 + ServiceRole: !GetAtt CodeBuildRole.Arn + ResourceAccessRole: !GetAtt LogsAccessRole.Arn + LogsConfig: + CloudWatchLogs: + Status: ENABLED + GroupName: /aws/codebuild/aws-lambda-cpp-ci + Triggers: + BuildType: BUILD + Webhook: True + FilterGroups: + - - Type: EVENT + Pattern: PUSH,PULL_REQUEST_CREATED,PULL_REQUEST_UPDATED + Environment: + ImagePullCredentialsType: SERVICE_ROLE + ComputeType: BUILD_GENERAL1_SMALL + Type: ARM_CONTAINER + Image: !Join [ ':', [ !GetAtt ECR.RepositoryUri, amazon-linux-2-linux-arm64 ]] + EnvironmentVariables: + - Name: LAMBDA_TEST_ROLE + Type: PLAINTEXT + Value: !Ref LambdaTestRole + Source: + Type: GITHUB + Location: !Ref GitHub + BuildSpec: ci/codebuild/amazonlinux-2.yml + + Amazon2: + Type: AWS::CodeBuild::Project + Properties: + Artifacts: + Type: NO_ARTIFACTS + BadgeEnabled: True + Visibility: PUBLIC_READ + ConcurrentBuildLimit: 1 + ServiceRole: !GetAtt CodeBuildRole.Arn + ResourceAccessRole: !GetAtt LogsAccessRole.Arn + LogsConfig: + CloudWatchLogs: + Status: ENABLED + GroupName: /aws/codebuild/aws-lambda-cpp-ci + Triggers: + BuildType: BUILD + Webhook: True + FilterGroups: + - - Type: EVENT + Pattern: PUSH,PULL_REQUEST_CREATED,PULL_REQUEST_UPDATED + Environment: + ImagePullCredentialsType: SERVICE_ROLE + ComputeType: BUILD_GENERAL1_SMALL + Type: LINUX_CONTAINER + Image: !Join [ ':', [ !GetAtt ECR.RepositoryUri, amazon-linux-2-linux-amd64 ]] + EnvironmentVariables: + - Name: LAMBDA_TEST_ROLE + Type: PLAINTEXT + Value: !Ref LambdaTestRole + Source: + Type: GITHUB + Location: !Ref GitHub + BuildSpec: ci/codebuild/amazonlinux-2.yml + + Amazon201803: + Type: AWS::CodeBuild::Project + Properties: + Artifacts: + Type: NO_ARTIFACTS + BadgeEnabled: True + Visibility: PUBLIC_READ + ConcurrentBuildLimit: 1 + ServiceRole: !GetAtt CodeBuildRole.Arn + ResourceAccessRole: !GetAtt LogsAccessRole.Arn + LogsConfig: + CloudWatchLogs: + Status: ENABLED + GroupName: /aws/codebuild/aws-lambda-cpp-ci + Triggers: + BuildType: BUILD + Webhook: True + FilterGroups: + - - Type: EVENT + Pattern: PUSH,PULL_REQUEST_CREATED,PULL_REQUEST_UPDATED + Environment: + ImagePullCredentialsType: SERVICE_ROLE + ComputeType: BUILD_GENERAL1_SMALL + Type: LINUX_CONTAINER + Image: !Join [ ':', [ !GetAtt ECR.RepositoryUri, amazon-linux-2018.03-linux-amd64 ]] + EnvironmentVariables: + - Name: LAMBDA_TEST_ROLE + Type: PLAINTEXT + Value: !Ref LambdaTestRole + Source: + Type: GITHUB + Location: !Ref GitHub + BuildSpec: ci/codebuild/amazonlinux-2018.03.yml + + Ubuntu1804: + Type: AWS::CodeBuild::Project + Properties: + Artifacts: + Type: NO_ARTIFACTS + BadgeEnabled: True + Visibility: PUBLIC_READ + ConcurrentBuildLimit: 1 + ServiceRole: !GetAtt CodeBuildRole.Arn + ResourceAccessRole: !GetAtt LogsAccessRole.Arn + LogsConfig: + CloudWatchLogs: + Status: ENABLED + GroupName: /aws/codebuild/aws-lambda-cpp-ci + Triggers: + BuildType: BUILD + Webhook: True + FilterGroups: + - - Type: EVENT + Pattern: PUSH,PULL_REQUEST_CREATED,PULL_REQUEST_UPDATED + Environment: + ImagePullCredentialsType: SERVICE_ROLE + ComputeType: BUILD_GENERAL1_SMALL + Type: LINUX_CONTAINER + Image: !Join [ ':', [ !GetAtt ECR.RepositoryUri, ubuntu-linux-18.04-linux-amd64 ]] + EnvironmentVariables: + - Name: LAMBDA_TEST_ROLE + Type: PLAINTEXT + Value: !Ref LambdaTestRole + Source: + Type: GITHUB + Location: !Ref GitHub + BuildSpec: ci/codebuild/ubuntu-18.04.yml + + Alpine315: + Type: AWS::CodeBuild::Project + Properties: + Artifacts: + Type: NO_ARTIFACTS + BadgeEnabled: True + Visibility: PUBLIC_READ + ConcurrentBuildLimit: 1 + ServiceRole: !GetAtt CodeBuildRole.Arn + ResourceAccessRole: !GetAtt LogsAccessRole.Arn + LogsConfig: + CloudWatchLogs: + Status: ENABLED + GroupName: /aws/codebuild/aws-lambda-cpp-ci + Triggers: + BuildType: BUILD + Webhook: True + FilterGroups: + - - Type: EVENT + Pattern: PUSH,PULL_REQUEST_CREATED,PULL_REQUEST_UPDATED + Environment: + ImagePullCredentialsType: SERVICE_ROLE + ComputeType: BUILD_GENERAL1_SMALL + Type: LINUX_CONTAINER + Image: !Join [ ':', [ !GetAtt ECR.RepositoryUri, alpine-linux-3.15-linux-amd64 ]] + EnvironmentVariables: + - Name: LAMBDA_TEST_ROLE + Type: PLAINTEXT + Value: !Ref LambdaTestRole + Source: + Type: GITHUB + Location: !Ref GitHub + BuildSpec: ci/codebuild/alpine-3.15.yml + + Arch: + Type: AWS::CodeBuild::Project + Properties: + Artifacts: + Type: NO_ARTIFACTS + BadgeEnabled: True + Visibility: PUBLIC_READ + ConcurrentBuildLimit: 1 + ServiceRole: !GetAtt CodeBuildRole.Arn + ResourceAccessRole: !GetAtt LogsAccessRole.Arn + LogsConfig: + CloudWatchLogs: + Status: ENABLED + GroupName: /aws/codebuild/aws-lambda-cpp-ci + Triggers: + BuildType: BUILD + Webhook: True + FilterGroups: + - - Type: EVENT + Pattern: PUSH,PULL_REQUEST_CREATED,PULL_REQUEST_UPDATED + Environment: + ImagePullCredentialsType: SERVICE_ROLE + ComputeType: BUILD_GENERAL1_SMALL + Type: LINUX_CONTAINER + Image: !Join [ ':', [ !GetAtt ECR.RepositoryUri, arch-linux-linux-amd64 ]] + EnvironmentVariables: + - Name: LAMBDA_TEST_ROLE + Type: PLAINTEXT + Value: !Ref LambdaTestRole + Source: + Type: GITHUB + Location: !Ref GitHub + BuildSpec: ci/codebuild/arch-linux.yml + +Outputs: + BootstrapArmImages: + Description: to bootstrap or update the arm images, run the command! + Value: !Join [' ', [ aws codebuild start-build --project-name, !Ref UpdateArmBuildEnvironments ] ] + BootstrapX86Images: + Description: to bootstrap or update the arm images, run the command! + Value: !Join [' ', [ aws codebuild start-build --project-name, !Ref UpdateX86BuildEnvironments ] ] diff --git a/ci/update-images.sh b/ci/update-images.sh new file mode 100755 index 0000000..b711ebb --- /dev/null +++ b/ci/update-images.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +set -euo pipefail + +PRJ_ROOT=$(git rev-parse --show-toplevel) +ECR_NAME=${ECR_NAME:-aws-lambda-cpp-ci} +REGION=${AWS_DEFAULT_REGION:-us-west-2} +ACCOUNT_ID=$(aws sts get-caller-identity --output text --query "Account") + +aws ecr get-login-password --region $REGION | docker login --username AWS --password-stdin $ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com + +# on Linux, if buildx is giving trouble - run: +# docker run --rm --privileged multiarch/qemu-user-static --reset -p yes + +build-and-push () { + TAG=$ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com/$ECR_NAME:$1-$(echo $2 | sed 's|/|-|g') + docker build --platform $2 -t $TAG -f "$PRJ_ROOT/ci/docker/$1" . + docker push $TAG +} + +if [[ $(arch) == "aarch64" ]]; then + build-and-push amazon-linux-2 linux/arm64 +else + build-and-push ubuntu-linux-18.04 linux/amd64 + build-and-push alpine-linux-3.15 linux/amd64 + build-and-push amazon-linux-2017.03 linux/amd64 + build-and-push amazon-linux-2 linux/amd64 + build-and-push arch-linux linux/amd64 +fi diff --git a/tests/runtime_tests.cpp b/tests/runtime_tests.cpp index a65a267..f118dab 100644 --- a/tests/runtime_tests.cpp +++ b/tests/runtime_tests.cpp @@ -89,7 +89,11 @@ struct LambdaRuntimeTest : public ::testing::Test { create_function_request.SetHandler(handler_name); create_function_request.SetFunctionName(function_name); // I ran into eventual-consistency issues when creating the role dynamically as part of the test. - create_function_request.SetRole(get_role_arn("integration-tests")); + auto exec_role = Aws::Environment::GetEnv("LAMBDA_TEST_ROLE"); + if (exec_role.empty()) { + exec_role = "integration-tests"; + } + create_function_request.SetRole(get_role_arn(exec_role)); struct stat s; auto rc = stat(ZIP_FILE_PATH, &s); From 5fb60b9d93c685e15d036889eb992dabe296d0bc Mon Sep 17 00:00:00 2001 From: Ildar Sagdejev Date: Mon, 29 Aug 2022 17:52:05 -0400 Subject: [PATCH 64/84] Simplified method for picking out shared libraries from system package query result (#136) --- packaging/packager | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/packaging/packager b/packaging/packager index 0c4e749..4e8759e 100755 --- a/packaging/packager +++ b/packaging/packager @@ -56,7 +56,7 @@ if ! type zip > /dev/null 2>&1; then exit 1 fi -function pluck_so_files() { +function find_so_files() { sed -E '/\.so$|\.so\.[0-9]+$/!d' } @@ -64,7 +64,7 @@ function package_libc_alpine() { # -F matches a fixed string rather than a regex (grep that comes with busybox doesn't know --fixed-strings) if grep -F "Alpine Linux" < /etc/os-release > /dev/null; then if type apk > /dev/null 2>&1; then - apk info --contents musl 2>/dev/null | pluck_so_files | sed 's/^/\//' + apk info --contents musl 2>/dev/null | find_so_files | sed 's/^/\//' fi fi } @@ -72,27 +72,20 @@ function package_libc_alpine() { function package_libc_pacman() { if grep --extended-regexp "Arch Linux|Manjaro Linux" < /etc/os-release > /dev/null 2>&1; then if type pacman > /dev/null 2>&1; then - pacman --query --list --quiet glibc | pluck_so_files + pacman --query --list --quiet glibc | find_so_files fi fi } function package_libc_dpkg() { if type dpkg-query > /dev/null 2>&1; then - architecture=$(dpkg --print-architecture) - if [[ $(dpkg-query --listfiles libc6:$architecture | wc -l) -gt 0 ]]; then - dpkg-query --listfiles libc6:$architecture | pluck_so_files - fi + dpkg-query --listfiles libc6:$(dpkg --print-architecture) | find_so_files fi } function package_libc_rpm() { - arch=$(uname -m) - if type rpm > /dev/null 2>&1; then - if [[ $(rpm --query --list glibc.$arch | wc -l) -gt 1 ]]; then - rpm --query --list glibc.$arch | pluck_so_files - fi + rpm --query --list glibc.$(uname -m) | find_so_files fi } From 9e2c1a3a29af07d3e62da2fe5c53de96edb0eb08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Ben=C3=ADcio?= Date: Mon, 29 Aug 2022 21:45:31 -0300 Subject: [PATCH 65/84] faq: adds section about linkers errors when using linkers incompatible with compilers. related #151 (#163) Co-authored-by: Bryan Moffatt --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 0812476..460da4b 100644 --- a/README.md +++ b/README.md @@ -214,6 +214,8 @@ curl_easy_setopt(curl_handle, CURLOPT_CAINFO, "/etc/pki/tls/certs/ca-bundle.crt" - You can try hitting the non-TLS version of the endpoint if available. (Not Recommended). 1. **No known conversion between `std::string` and `Aws::String`** - Either turn off custom memory management in the AWS C++ SDK or build it as a static library (`-DBUILD_SHARED_LIBS=OFF`) +1. **I'm getting wierd linking errors like `/usr/bin/ld: /home/<...>bin/lib/libaws-lambda-runtime.a: error adding symbols: file format not recognized clang: error: linker command failed with exit code 1 (use -v to see invocation)`** + - By default this project enables _link-time optimization (LTO)_ (configurable with `ENABLE_LTO` _cmake_ option). This tells compilers to delay optimizations until the linking phase. For some compilers (like _clang_) this means that each compilation unit should be compiled down only to intermediate representations (_e.g._ _clang_ uses _LLVM IR_) instead of directly to native object files. As a side-effect, library archives (like _aws-lambda-runtime_) would also contain only _IR_ code. This may result in linker errors like the above if you use a linker incompatible with the _IR_ code generated by your compiler (e.g. _GNU ld_ linker doesn't support _LLVM IR_). In order for the linking step to succeed with _LTO_ you must either use an appropriate linker with something like `-DCMAKE_CXX_FLAGS="-fuse-ld=lld"` (_GNU ld_ for _gcc_ and _lld_ for _clang_ are known to work) or disable _LTO_ (`-DENABLE_LTO=OFF`). ## License From ba96347fb343863ea161ce2f045205386d93f939 Mon Sep 17 00:00:00 2001 From: Marco Magdy Date: Thu, 8 Sep 2022 19:15:40 -0700 Subject: [PATCH 66/84] Make LTO opt-in by default instead of opt-out (#167) --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 01e6313..76702cb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ project(aws-lambda-runtime VERSION 0.0.0 LANGUAGES CXX) -option(ENABLE_LTO "Enables link-time optimization, requires compiler support." ON) +option(ENABLE_LTO "Enables link-time optimization, requires compiler support." OFF) option(ENABLE_TESTS "Enables building the test project, requires AWS C++ SDK." OFF) add_library(${PROJECT_NAME} From 365a4c401fe0bbfd79c94885be9b70570d718cf9 Mon Sep 17 00:00:00 2001 From: Marco Magdy Date: Thu, 8 Sep 2022 19:39:57 -0700 Subject: [PATCH 67/84] Update README.md (#165) --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 460da4b..0812476 100644 --- a/README.md +++ b/README.md @@ -214,8 +214,6 @@ curl_easy_setopt(curl_handle, CURLOPT_CAINFO, "/etc/pki/tls/certs/ca-bundle.crt" - You can try hitting the non-TLS version of the endpoint if available. (Not Recommended). 1. **No known conversion between `std::string` and `Aws::String`** - Either turn off custom memory management in the AWS C++ SDK or build it as a static library (`-DBUILD_SHARED_LIBS=OFF`) -1. **I'm getting wierd linking errors like `/usr/bin/ld: /home/<...>bin/lib/libaws-lambda-runtime.a: error adding symbols: file format not recognized clang: error: linker command failed with exit code 1 (use -v to see invocation)`** - - By default this project enables _link-time optimization (LTO)_ (configurable with `ENABLE_LTO` _cmake_ option). This tells compilers to delay optimizations until the linking phase. For some compilers (like _clang_) this means that each compilation unit should be compiled down only to intermediate representations (_e.g._ _clang_ uses _LLVM IR_) instead of directly to native object files. As a side-effect, library archives (like _aws-lambda-runtime_) would also contain only _IR_ code. This may result in linker errors like the above if you use a linker incompatible with the _IR_ code generated by your compiler (e.g. _GNU ld_ linker doesn't support _LLVM IR_). In order for the linking step to succeed with _LTO_ you must either use an appropriate linker with something like `-DCMAKE_CXX_FLAGS="-fuse-ld=lld"` (_GNU ld_ for _gcc_ and _lld_ for _clang_ are known to work) or disable _LTO_ (`-DENABLE_LTO=OFF`). ## License From c3a79b4c75577f0726c712203ffb9d9b960a3688 Mon Sep 17 00:00:00 2001 From: Bryan Moffatt Date: Fri, 16 Sep 2022 23:38:07 -0700 Subject: [PATCH 68/84] Update build badges in README (#166) * Update build badges in README * Update README.md fix links --- README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0812476..8149740 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,15 @@ [![GitHub](https://img.shields.io/github/license/awslabs/aws-lambda-cpp.svg)](https://github.com/awslabs/aws-lambda-cpp/blob/master/LICENSE) -![CodeBuild](https://codebuild.us-west-2.amazonaws.com/badges?uuid=eyJlbmNyeXB0ZWREYXRhIjoiQkN1b0srbWtnUjNibFVyL2psNmdaM0l4RnVQNzVBeG84QnQvUjRmOEJVdXdHUXMxZ25iWnFZQUtGTkUxVGJhcGZaVEhXY2JOSTFHTlkvaGF2RDRIZlpVPSIsIml2UGFyYW1ldGVyU3BlYyI6IjRiS3hlRjFxVFZHSWViQmQiLCJtYXRlcmlhbFNldFNlcmlhbCI6MX0%3D&branch=master) [![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/awslabs/aws-lambda-cpp.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/awslabs/aws-lambda-cpp/context:cpp) + +| OS | Arch | Status | +|----|------|--------| +| Amazon Linux 2 | x86_64 | [![](https://codebuild.us-west-2.amazonaws.com/badges?uuid=eyJlbmNyeXB0ZWREYXRhIjoiQ1EvQXE0ODBLK0VnQitMaVdvZ1J0QkhTMlpNbk8wS0lRbWZvRDlPSHB0V0VXb1VLazdSdzRMWHhMeUdpYjdOT1hCc1hjL3BKei96ZVpzeTdrMVd4c3BRPSIsIml2UGFyYW1ldGVyU3BlYyI6IkhjTTNoSzJwb1hldk9zZFYiLCJtYXRlcmlhbFNldFNlcmlhbCI6MX0%3D&branch=master)](https://us-west-2.codebuild.aws.amazon.com/project/eyJlbmNyeXB0ZWREYXRhIjoicnpvbytDV0grMHh2c09ONi9kQ3ZuOVVwckxISElKRENEVy9CL0pvd3VvLzQwZ21pdzBOdGtNWUFLRy9VRkw1NldSMmRlVXV5R0NhN1k1OWI0bDY1N2MyMzR2SmhseWlma0hmWTlBUkwzcVp0TEJlQm1RPT0iLCJpdlBhcmFtZXRlclNwZWMiOiI3MzM4WDUybk9hSkl1bllRIiwibWF0ZXJpYWxTZXRTZXJpYWwiOjF9) | +| Amazon Linux 2 | aarch64 | [![](https://codebuild.us-west-2.amazonaws.com/badges?uuid=eyJlbmNyeXB0ZWREYXRhIjoicWNGSmJtaGdPSCtqR25KQ1k3RWNZS1pwWlZScGZ3WU1JM0lISnZJVkhVNy8zbVIyVHp6RlBmRjN4cjZJd2xWNEd0eWZmUy9JaE1vRzBYWFcrbnpFdDUwPSIsIml2UGFyYW1ldGVyU3BlYyI6ImVoeHl5TTNtMmdERjJuWisiLCJtYXRlcmlhbFNldFNlcmlhbCI6MX0%3D&branch=master)](https://us-west-2.codebuild.aws.amazon.com/project/eyJlbmNyeXB0ZWREYXRhIjoiVUVaNzBYMXVjUUl1djdlS3pTSXVxMUhKcHB4ZC96ZjlDOWM3bUxiRmtITnVGYzdxTDJveFY3eVFqanpHbzhYRUdWVjVhZFhnOGt0NldETEVMamN0alRoZzYwMyszU1lVMjJNR0lUWGNCQjVYNzhuUzZwZ0ptZz09IiwiaXZQYXJhbWV0ZXJTcGVjIjoicmtKaUVoM2pmUVdibVZuOSIsIm1hdGVyaWFsU2V0U2VyaWFsIjoxfQ%3D%3D) | +| Amazon Linux (ALAMI) | x86_64 | [![](https://codebuild.us-west-2.amazonaws.com/badges?uuid=eyJlbmNyeXB0ZWREYXRhIjoiWUNqeG9FcmUyQzVSaUkydFd6UkU5Sm42cTViSExXOFZURHRBQlM0dDJDOThMWEFYLzN4NitQR0w1ZzNKcjAwOVNUYXY5ZUljU1hzcEtrU0N0dEhUN0M0PSIsIml2UGFyYW1ldGVyU3BlYyI6ImtYU0ZjSzh3ekFKazlBVVUiLCJtYXRlcmlhbFNldFNlcmlhbCI6MX0%3D&branch=master)](https://us-west-2.codebuild.aws.amazon.com/project/eyJlbmNyeXB0ZWREYXRhIjoiTEJJVVFIOXp6VjUvWExqODN1K1NPQmRTVm9iQy9ZK2tmKzkrbVdTNlh1LzV1UlpQL2lPN1Faak0yc0pOaGpEVlRpai9yS3JCRjBRQU5lMVFVU1hRU1hyekxpVi8yNWV0ZE44SElWdlRpNld4bmkwdE1oQjcxN0NtIiwiaXZQYXJhbWV0ZXJTcGVjIjoiZnBBUi9uOU8yVjJ4RENpRyIsIm1hdGVyaWFsU2V0U2VyaWFsIjoxfQ%3D%3D) | +| Alpine | x86_64 | [![](https://codebuild.us-west-2.amazonaws.com/badges?uuid=eyJlbmNyeXB0ZWREYXRhIjoiTkhhOEJGNjVOTG5NZWVNWDNjSGNEdWEwY0J2ZUNLMkE2aU83UVdYc3VMU0V5b1JqdXY0OXUxNkxYRDUxU0VJOTByL3NLUTE3djBMNWh2VldXdk0xamJZPSIsIml2UGFyYW1ldGVyU3BlYyI6ImQxSjc2Vnd3czF2QWphRS8iLCJtYXRlcmlhbFNldFNlcmlhbCI6MX0%3D&branch=master)](https://us-west-2.codebuild.aws.amazon.com/project/eyJlbmNyeXB0ZWREYXRhIjoiQzJVUzZML1dLTkpRNGcxSjVyUXVEd1BCY2poZUhydWZLeGE5MGU1c05vNDVObG44bnpKZFhlZVJKSm50ZnpaalRENUxxOHpPNGdPTDRlTGc4WW81UHd4L3hCeTgyTm5vRVR0RW5FempKdk00aDlPRk02WGQiLCJpdlBhcmFtZXRlclNwZWMiOiJUMFhCQktLMExQMXc3Q0lHIiwibWF0ZXJpYWxTZXRTZXJpYWwiOjF9) | +| Arch Linux | x86_64 | [![](https://codebuild.us-west-2.amazonaws.com/badges?uuid=eyJlbmNyeXB0ZWREYXRhIjoib2cxaHp3bE5ndWhWR0RIRkxxQzRwR1dHa05DWmQ0bENnWGNHYzM2YmR3OFRHNWpPYStGYUM1WXBQVUNoZjJRa2xrZVpuRXVyWVVvQVNzNExqSlN5TGEwPSIsIml2UGFyYW1ldGVyU3BlYyI6Ii9zSjVybGNsNEJMUEZwSlUiLCJtYXRlcmlhbFNldFNlcmlhbCI6MX0%3D&branch=master)](https://us-west-2.codebuild.aws.amazon.com/project/eyJlbmNyeXB0ZWREYXRhIjoiRWVOYlA5OHZqUVVLUTZLYlJzZmdOQkR5dmpVSTBPS1h1M3RxQkxXa3pyMC9OOUw5dDJlUDcyYm05Q3pBOEZ1aWJFYkFBajFGZ3RJWUM5WkpoZUE4K0IrdFIvYytyNVRYREpQTUNHL05vTXlLQ0E9PSIsIml2UGFyYW1ldGVyU3BlYyI6InFuS1hJY3JTaWpSWENLM1EiLCJtYXRlcmlhbFNldFNlcmlhbCI6MX0%3D) | +| Ubuntu 18.04 | x86_64 | [![](https://codebuild.us-west-2.amazonaws.com/badges?uuid=eyJlbmNyeXB0ZWREYXRhIjoiVkhsbmdlYkk3M1JESVdiTHc0elpobXEvUk4wRWlBZUpEZzdmem1QbGJRZ3dMbVE2RWZpbHZjNmVCd0dJaUFSZ1pzQVlyZ1dvdndWTjZSRjg0WDRYRFh3PSIsIml2UGFyYW1ldGVyU3BlYyI6IjJic2dnR3ZpTEQyMmRPMXQiLCJtYXRlcmlhbFNldFNlcmlhbCI6MX0%3D&branch=master)](https://us-west-2.codebuild.aws.amazon.com/project/eyJlbmNyeXB0ZWREYXRhIjoiSlNPak1vQmVBR3JnUlAwRWg2N3hHRHF1U2Z6RkQvY1NHRHM4RTJ0WEFBdjFTSzBzY21kZEpPMDk2QXdwRStUWUZmWWFmTkRkU1FGa0lQUGoxbU9GNU45QVJ1YVkzZkY0dmsxV2FRZVljakt3UmJpdTM2a0JnQT09IiwiaXZQYXJhbWV0ZXJTcGVjIjoieE5LSUlmNVN1UWdqbWg0cSIsIm1hdGVyaWFsU2V0U2VyaWFsIjoxfQ%3D%3D) | + ## AWS Lambda C++ Runtime C++ implementation of the lambda runtime API From e66f5203f460819bb3bb9c7fefc6d66032b80996 Mon Sep 17 00:00:00 2001 From: Bryan Moffatt Date: Fri, 16 Sep 2022 23:49:59 -0700 Subject: [PATCH 69/84] fixup CI configuration for 2018.03 (#168) * update ci references for al 2018.03 * empty --- .../{amazonlinux-2017.03.yml => amazonlinux-2018.03.yml} | 0 ci/docker/{amazon-linux-2017.03 => amazon-linux-2018.03} | 0 ci/update-images.sh | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename ci/codebuild/{amazonlinux-2017.03.yml => amazonlinux-2018.03.yml} (100%) rename ci/docker/{amazon-linux-2017.03 => amazon-linux-2018.03} (100%) diff --git a/ci/codebuild/amazonlinux-2017.03.yml b/ci/codebuild/amazonlinux-2018.03.yml similarity index 100% rename from ci/codebuild/amazonlinux-2017.03.yml rename to ci/codebuild/amazonlinux-2018.03.yml diff --git a/ci/docker/amazon-linux-2017.03 b/ci/docker/amazon-linux-2018.03 similarity index 100% rename from ci/docker/amazon-linux-2017.03 rename to ci/docker/amazon-linux-2018.03 diff --git a/ci/update-images.sh b/ci/update-images.sh index b711ebb..ffff6e5 100755 --- a/ci/update-images.sh +++ b/ci/update-images.sh @@ -23,7 +23,7 @@ if [[ $(arch) == "aarch64" ]]; then else build-and-push ubuntu-linux-18.04 linux/amd64 build-and-push alpine-linux-3.15 linux/amd64 - build-and-push amazon-linux-2017.03 linux/amd64 + build-and-push amazon-linux-2018.03 linux/amd64 build-and-push amazon-linux-2 linux/amd64 build-and-push arch-linux linux/amd64 fi From 1129e531bae450b6fb78ad5fc08d6222ceb9f68d Mon Sep 17 00:00:00 2001 From: Marco Magdy Date: Sun, 18 Sep 2022 09:33:09 -0700 Subject: [PATCH 70/84] Fix a typo in README (#169) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8149740..f86004a 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Make sure you have the following packages installed first: 1. git 1. Make or Ninja 1. zip -1. libcurl-devel (on Debian-basded distros it's libcurl4-openssl-dev) +1. libcurl-devel (on Debian-based distros it's libcurl4-openssl-dev) In a terminal, run the following commands: ```bash From 08002c5400d799a959f3b06dd36d4c2765fce44b Mon Sep 17 00:00:00 2001 From: Marco Magdy Date: Wed, 19 Oct 2022 08:48:20 -0700 Subject: [PATCH 71/84] Add GitHub code scanner workflow (#172) * Add support for Github code scanner 'lgtm.com' is shutting down in December 2022. It has been replaced by 'GitHub code scanning'. * Install libcurl as part of the build steps * Replace lgtm badge with GitHub code analyzer * fixup! Replace lgtm badge with GitHub code analyzer --- .github/workflows/code-quality.yml | 58 ++++++++++++++++++++++++++++++ README.md | 2 +- 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/code-quality.yml diff --git a/.github/workflows/code-quality.yml b/.github/workflows/code-quality.yml new file mode 100644 index 0000000..9ccfc82 --- /dev/null +++ b/.github/workflows/code-quality.yml @@ -0,0 +1,58 @@ +name: "Code Quality" + +on: + push: + branches: [ "master" ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ "master" ] + schedule: + - cron: '32 14 * * 2' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'cpp' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] + # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + # Install libcurl dependency + - name: Install dependencies + run: sudo apt install -y libcurl4-openssl-dev + + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + + - run: | + echo "Run, CMake build script" + cmake -B ${{github.workspace}}/build -DBUILD_SHARED_LIBS=ON -DBUILD_TESTING=OFF + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 + with: + category: "/language:${{matrix.language}}" + diff --git a/README.md b/README.md index f86004a..74e60af 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ [![GitHub](https://img.shields.io/github/license/awslabs/aws-lambda-cpp.svg)](https://github.com/awslabs/aws-lambda-cpp/blob/master/LICENSE) -[![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/awslabs/aws-lambda-cpp.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/awslabs/aws-lambda-cpp/context:cpp) +![Code Quality badge](https://github.com/awslabs/aws-lambda-cpp/actions/workflows/code-quality.yml/badge.svg) | OS | Arch | Status | |----|------|--------| From 8e98808f346964a85ede585e0fdd5874d43b325f Mon Sep 17 00:00:00 2001 From: Marco Magdy Date: Wed, 19 Oct 2022 13:20:43 -0700 Subject: [PATCH 72/84] Pass payload by value to enable moving arguments (#173) * Pass payload by value to enable moving arguments * Update the tests to use std::move * empty commit Co-authored-by: Bryan Moffatt Co-authored-by: Bryan Moffatt --- examples/dynamodb/main.cpp | 8 ++++---- examples/s3/main.cpp | 2 +- include/aws/lambda-runtime/runtime.h | 2 +- src/runtime.cpp | 6 +++--- tests/resources/lambda_function.cpp | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/examples/dynamodb/main.cpp b/examples/dynamodb/main.cpp index a8b8662..6089fa3 100644 --- a/examples/dynamodb/main.cpp +++ b/examples/dynamodb/main.cpp @@ -173,9 +173,9 @@ aws::lambda_runtime::invocation_response my_handler( if (cr.error_msg) { JsonValue response; response.WithString("body", cr.error_msg).WithInteger("statusCode", 400); - auto const apig_response = response.View().WriteCompact(); + auto apig_response = response.View().WriteCompact(); AWS_LOGSTREAM_ERROR(TAG, "Validation failed. " << apig_response); - return aws::lambda_runtime::invocation_response::success(apig_response, "application/json"); + return aws::lambda_runtime::invocation_response::success(std::move(apig_response), "application/json"); } auto result = query(cr, client); @@ -190,10 +190,10 @@ aws::lambda_runtime::invocation_response my_handler( response.WithString("body", "No data found for this product.").WithInteger("statusCode", 400); } - auto const apig_response = response.View().WriteCompact(); + auto apig_response = response.View().WriteCompact(); AWS_LOGSTREAM_DEBUG(TAG, "api gateway response: " << apig_response); - return aws::lambda_runtime::invocation_response::success(apig_response, "application/json"); + return aws::lambda_runtime::invocation_response::success(std::move(apig_response), "application/json"); } std::function()> GetConsoleLoggerFactory() diff --git a/examples/s3/main.cpp b/examples/s3/main.cpp index 45b935b..a389121 100644 --- a/examples/s3/main.cpp +++ b/examples/s3/main.cpp @@ -50,7 +50,7 @@ static invocation_response my_handler(invocation_request const& req, Aws::S3::S3 return invocation_response::failure(err, "DownloadFailure"); } - return invocation_response::success(base64_encoded_file, "application/base64"); + return invocation_response::success(std::move(base64_encoded_file), "application/base64"); } std::function()> GetConsoleLoggerFactory() diff --git a/include/aws/lambda-runtime/runtime.h b/include/aws/lambda-runtime/runtime.h index 9602369..d19dbc2 100644 --- a/include/aws/lambda-runtime/runtime.h +++ b/include/aws/lambda-runtime/runtime.h @@ -105,7 +105,7 @@ class invocation_response { /** * Create a successful invocation response with the given payload and content-type. */ - static invocation_response success(std::string const& payload, std::string const& content_type); + static invocation_response success(std::string payload, std::string content_type); /** * Create a failure response with the given error message and error type. diff --git a/src/runtime.cpp b/src/runtime.cpp index 47ead0e..3968adb 100644 --- a/src/runtime.cpp +++ b/src/runtime.cpp @@ -506,12 +506,12 @@ static std::string json_escape(std::string const& in) } AWS_LAMBDA_RUNTIME_API -invocation_response invocation_response::success(std::string const& payload, std::string const& content_type) +invocation_response invocation_response::success(std::string payload, std::string content_type) { invocation_response r; r.m_success = true; - r.m_content_type = content_type; - r.m_payload = payload; + r.m_content_type = std::move(content_type); + r.m_payload = std::move(payload); return r; } diff --git a/tests/resources/lambda_function.cpp b/tests/resources/lambda_function.cpp index 7cd62e5..b0228d3 100644 --- a/tests/resources/lambda_function.cpp +++ b/tests/resources/lambda_function.cpp @@ -23,8 +23,8 @@ invocation_response echo_failure(invocation_request const& /*request*/) invocation_response binary_response(invocation_request const& /*request*/) { - const std::string png((char*)awslogo_png, AWSLOGO_PNG_LEN); - return invocation_response::success(png, "image/png"); + std::string png((char*)awslogo_png, AWSLOGO_PNG_LEN); + return invocation_response::success(std::move(png), "image/png"); } invocation_response crash_backtrace(invocation_request const& /*request*/) From 2601aeaa686086a20d1d87eb1bb68d5bcdfe8f1f Mon Sep 17 00:00:00 2001 From: Marco Magdy Date: Wed, 19 Oct 2022 13:36:14 -0700 Subject: [PATCH 73/84] Build with ASan and UBSan (#174) Co-authored-by: Bryan Moffatt --- CMakeLists.txt | 6 ++++++ ci/codebuild/arch-linux.yml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 76702cb..14ee99f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,7 @@ project(aws-lambda-runtime option(ENABLE_LTO "Enables link-time optimization, requires compiler support." OFF) option(ENABLE_TESTS "Enables building the test project, requires AWS C++ SDK." OFF) +option(ENABLE_SANITIZERS "Enables ASan and UBSan." OFF) add_library(${PROJECT_NAME} "src/logging.cpp" @@ -22,6 +23,11 @@ target_include_directories(${PROJECT_NAME} PUBLIC $ $) +if (ENABLE_SANITIZERS) + target_compile_options(${PROJECT_NAME} PUBLIC "-fsanitize=address,undefined") + target_link_libraries(${PROJECT_NAME} PUBLIC "-fsanitize=address,undefined") +endif() + if (ENABLE_LTO) include(CheckIPOSupported) check_ipo_supported(RESULT has_lto OUTPUT lto_check_output) diff --git a/ci/codebuild/arch-linux.yml b/ci/codebuild/arch-linux.yml index 4262f50..0a12a5d 100644 --- a/ci/codebuild/arch-linux.yml +++ b/ci/codebuild/arch-linux.yml @@ -4,6 +4,6 @@ phases: build: commands: - echo Build started on `date` - - ./ci/codebuild/build.sh -DTEST_RESOURCE_PREFIX=lambda-cpp-archbtw + - ./ci/codebuild/build.sh -DTEST_RESOURCE_PREFIX=lambda-cpp-archbtw -DENABLE_SANITIZERS=ON - ./ci/codebuild/run-tests.sh aws-lambda-package-lambda-test-fun - echo Build completed on `date` From 78ffe176de2ae98e1a9ae513abaad9d74b1bfb14 Mon Sep 17 00:00:00 2001 From: Marco Magdy Date: Fri, 4 Nov 2022 12:03:51 -0700 Subject: [PATCH 74/84] Update code-quality.yml (#176) --- .github/workflows/code-quality.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/code-quality.yml b/.github/workflows/code-quality.yml index 9ccfc82..495f6a6 100644 --- a/.github/workflows/code-quality.yml +++ b/.github/workflows/code-quality.yml @@ -31,7 +31,7 @@ jobs: # Install libcurl dependency - name: Install dependencies - run: sudo apt install -y libcurl4-openssl-dev + run: sudo apt-get update && sudo apt install -y libcurl4-openssl-dev # Initializes the CodeQL tools for scanning. From e3e9e096a0fa4537e35f32c4ea10ea62fe7c9f5a Mon Sep 17 00:00:00 2001 From: Maxi Mittelhammer Date: Thu, 2 Feb 2023 17:58:46 +0100 Subject: [PATCH 75/84] Changed sprintf to snprintf (#180) --- src/runtime.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime.cpp b/src/runtime.cpp index 3968adb..4ca70dc 100644 --- a/src/runtime.cpp +++ b/src/runtime.cpp @@ -496,7 +496,7 @@ static std::string json_escape(std::string const& in) // escape and print as unicode codepoint constexpr int printed_unicode_length = 6; // 4 hex + letter 'u' + \0 std::array buf; - sprintf(buf.data(), "u%04x", ch); + snprintf(buf.data(), buf.size(), "u%04x", ch); out.append(buf.data(), buf.size() - 1); // add only five, discarding the null terminator. break; } From fbfdaec9777adac9f6b50d9acd23edc24ca2b3e2 Mon Sep 17 00:00:00 2001 From: Marco Magdy Date: Tue, 14 Feb 2023 13:01:15 -0800 Subject: [PATCH 76/84] Fix clang-tidy benign warnings (#185) --- .clang-tidy | 3 ++- ci/codebuild/format-check.sh | 5 +++++ include/aws/lambda-runtime/runtime.h | 3 +-- src/runtime.cpp | 9 +++++++-- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 7d343ea..d42139e 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,6 +1,7 @@ --- Checks: -'clang-diagnostic-*,clang-analyzer-*,performance-*,readability-*,modernize-*,bugprone-*,misc-*,-modernize-use-trailing-return-type' +'clang-diagnostic-*,clang-analyzer-*,performance-*,readability-*,modernize-*,bugprone-*,misc-*, +-modernize-use-trailing-return-type,-bugprone-easily-swappable-parameters,-readability-identifier-length' WarningsAsErrors: '*' HeaderFilterRegex: 'include/aws/.*\.h$' FormatStyle: 'none' diff --git a/ci/codebuild/format-check.sh b/ci/codebuild/format-check.sh index 222b784..035bd54 100755 --- a/ci/codebuild/format-check.sh +++ b/ci/codebuild/format-check.sh @@ -13,6 +13,11 @@ FAIL=0 SOURCE_FILES=$(find src include tests -type f -name "*.h" -o -name "*.cpp") for i in $SOURCE_FILES do + if [[ "$i" == *"gtest.h" || "$i" == *"backward.h" ]]; then + continue + fi + + echo "$i\n" if [ $($CLANG_FORMAT -output-replacements-xml $i | grep -c " #include #include +#include #include // for strtoul #include @@ -133,12 +134,16 @@ static size_t read_data(char* buffer, size_t size, size_t nitems, void* userdata } if (unread <= limit) { - std::copy_n(ctx->first.begin() + ctx->second, unread, buffer); + auto from = ctx->first.begin(); + std::advance(from, ctx->second); + std::copy_n(from, unread, buffer); ctx->second += unread; return unread; } - std::copy_n(ctx->first.begin() + ctx->second, limit, buffer); + auto from = ctx->first.begin(); + std::advance(from, ctx->second); + std::copy_n(from, limit, buffer); ctx->second += limit; return limit; } From fa438eba19f3c536cfcce74737f336146767fde8 Mon Sep 17 00:00:00 2001 From: Krzysiek Karbowiak Date: Wed, 15 Feb 2023 09:16:17 +0100 Subject: [PATCH 77/84] Update actions/checkout to v3 (#181) --- .github/workflows/workflow.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 14bb1da..5cadaf0 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install Dependencies run: sudo apt-get update && sudo apt-get install -y clang-tidy libcurl4-openssl-dev @@ -36,7 +36,7 @@ jobs: build-on-arm-too: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: uraimo/run-on-arch-action@v2 with: arch: aarch64 @@ -52,7 +52,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Check Formatting run: ./ci/codebuild/format-check.sh From c09c86e0268ab8965ebd0ebee142c69c655a3207 Mon Sep 17 00:00:00 2001 From: Krzysiek Karbowiak Date: Mon, 27 Feb 2023 05:45:06 +0100 Subject: [PATCH 78/84] Add building and packaging a demo project to CI and revert #136 (#183) * Add demo project * Add build-demo CI job * Revert "Simplified method for picking out shared libraries from system package query result (#136)" This reverts commit 5fb60b9d93c685e15d036889eb992dabe296d0bc. --------- Co-authored-by: Bryan Moffatt Co-authored-by: Bryan Moffatt --- .github/workflows/workflow.yml | 22 ++++++++++++++++++++++ examples/demo/CMakeLists.txt | 11 +++++++++++ examples/demo/main.cpp | 20 ++++++++++++++++++++ packaging/packager | 17 ++++++++++++----- 4 files changed, 65 insertions(+), 5 deletions(-) create mode 100644 examples/demo/CMakeLists.txt create mode 100644 examples/demo/main.cpp diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 5cadaf0..526b38a 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -46,6 +46,28 @@ jobs: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_CXX_CLANG_TIDY=clang-tidy cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} + build-demo: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Install Dependencies + run: sudo apt-get update && sudo apt-get install -y clang-tidy libcurl4-openssl-dev + + - name: Build and install lambda runtime + run: | + mkdir build && cd build + cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=~/lambda-install + make + make install + + - name: Build and package demo project + run: | + cd examples/demo + mkdir build && cd build + cmake .. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=~/lambda-install + make + make aws-lambda-package-demo format: diff --git a/examples/demo/CMakeLists.txt b/examples/demo/CMakeLists.txt new file mode 100644 index 0000000..06aad51 --- /dev/null +++ b/examples/demo/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.9) +set(CMAKE_CXX_STANDARD 11) +project(demo LANGUAGES CXX) +find_package(aws-lambda-runtime) +add_executable(${PROJECT_NAME} "main.cpp") +target_link_libraries(${PROJECT_NAME} PRIVATE AWS::aws-lambda-runtime) +target_compile_features(${PROJECT_NAME} PRIVATE "cxx_std_11") +target_compile_options(${PROJECT_NAME} PRIVATE "-Wall" "-Wextra") + +# this line creates a target that packages your binary and zips it up +aws_lambda_package_target(${PROJECT_NAME}) diff --git a/examples/demo/main.cpp b/examples/demo/main.cpp new file mode 100644 index 0000000..358efe0 --- /dev/null +++ b/examples/demo/main.cpp @@ -0,0 +1,20 @@ +#include + +using namespace aws::lambda_runtime; + +static invocation_response my_handler(invocation_request const& req) +{ + if (req.payload.length() > 42) { + return invocation_response::failure("error message here"/*error_message*/, + "error type here" /*error_type*/); + } + + return invocation_response::success("json payload here" /*payload*/, + "application/json" /*MIME type*/); +} + +int main() +{ + run_handler(my_handler); + return 0; +} diff --git a/packaging/packager b/packaging/packager index 4e8759e..0c4e749 100755 --- a/packaging/packager +++ b/packaging/packager @@ -56,7 +56,7 @@ if ! type zip > /dev/null 2>&1; then exit 1 fi -function find_so_files() { +function pluck_so_files() { sed -E '/\.so$|\.so\.[0-9]+$/!d' } @@ -64,7 +64,7 @@ function package_libc_alpine() { # -F matches a fixed string rather than a regex (grep that comes with busybox doesn't know --fixed-strings) if grep -F "Alpine Linux" < /etc/os-release > /dev/null; then if type apk > /dev/null 2>&1; then - apk info --contents musl 2>/dev/null | find_so_files | sed 's/^/\//' + apk info --contents musl 2>/dev/null | pluck_so_files | sed 's/^/\//' fi fi } @@ -72,20 +72,27 @@ function package_libc_alpine() { function package_libc_pacman() { if grep --extended-regexp "Arch Linux|Manjaro Linux" < /etc/os-release > /dev/null 2>&1; then if type pacman > /dev/null 2>&1; then - pacman --query --list --quiet glibc | find_so_files + pacman --query --list --quiet glibc | pluck_so_files fi fi } function package_libc_dpkg() { if type dpkg-query > /dev/null 2>&1; then - dpkg-query --listfiles libc6:$(dpkg --print-architecture) | find_so_files + architecture=$(dpkg --print-architecture) + if [[ $(dpkg-query --listfiles libc6:$architecture | wc -l) -gt 0 ]]; then + dpkg-query --listfiles libc6:$architecture | pluck_so_files + fi fi } function package_libc_rpm() { + arch=$(uname -m) + if type rpm > /dev/null 2>&1; then - rpm --query --list glibc.$(uname -m) | find_so_files + if [[ $(rpm --query --list glibc.$arch | wc -l) -gt 1 ]]; then + rpm --query --list glibc.$arch | pluck_so_files + fi fi } From f0ad0623682cd9bf9bc9ae2e362cb5a00b28e59a Mon Sep 17 00:00:00 2001 From: Mart Haarman Date: Fri, 24 Mar 2023 22:29:03 +0100 Subject: [PATCH 79/84] Update main.cpp (#178) Co-authored-by: Bryan Moffatt --- examples/s3/main.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/s3/main.cpp b/examples/s3/main.cpp index a389121..892560c 100644 --- a/examples/s3/main.cpp +++ b/examples/s3/main.cpp @@ -73,8 +73,7 @@ int main() config.region = Aws::Environment::GetEnv("AWS_REGION"); config.caFile = "/etc/pki/tls/certs/ca-bundle.crt"; - auto credentialsProvider = Aws::MakeShared(TAG); - S3::S3Client client(credentialsProvider, config); + S3::S3Client client(config); auto handler_fn = [&client](aws::lambda_runtime::invocation_request const& req) { return my_handler(req, client); }; From e08ca6e065877b0ab4eb0e1e43e21c3a3c5f274a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C8=98tefan=20Toma?= <34220105+Stefan9283@users.noreply.github.com> Date: Mon, 23 Oct 2023 20:46:26 +0300 Subject: [PATCH 80/84] Making libbacktrace optional (#189) * Making libbacktrace optional --------- Co-authored-by: Stefan Toma --- CMakeLists.txt | 39 +++++++++++++++++++++++---------------- src/backward.cpp | 6 +++++- src/backward.h | 6 ++++++ 3 files changed, 34 insertions(+), 17 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 14ee99f..09e226f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,8 +47,29 @@ endif() target_include_directories(${PROJECT_NAME} PRIVATE ${CURL_INCLUDE_DIRS}) -find_package(Backtrace REQUIRED) -target_link_libraries(${PROJECT_NAME} PRIVATE ${Backtrace_LIBRARIES}) +find_package(Backtrace QUIET) +if (${Backtrace_FOUND}) + target_link_libraries(${PROJECT_NAME} PRIVATE ${Backtrace_LIBRARIES}) + + find_library(DW_LIB NAMES dw) + if (NOT DW_LIB STREQUAL DW_LIB-NOTFOUND) + message("-- Enhanced stack-traces are enabled via libdw: ${DW_LIB}") + target_compile_definitions(${PROJECT_NAME} PRIVATE "BACKWARD_HAS_DW=1") + target_link_libraries(${PROJECT_NAME} PUBLIC "${DW_LIB}") + else() + find_library(BFD_LIB NAMES bfd) + if (NOT BFD_LIB STREQUAL BFD_LIB-NOTFOUND) + message("-- Enhanced stack-traces are enabled via libbfd: ${BFD_LIB}") + target_compile_definitions(${PROJECT_NAME} PRIVATE "BACKWARD_HAS_BFD=1") + target_link_libraries(${PROJECT_NAME} PRIVATE "${BFD_LIB}") + endif() + endif() + +else() + message("-- libbacktrace was not installed. Stacktracing will be disabled") + add_definitions(-Dno_backtrace) +endif() + target_compile_options(${PROJECT_NAME} PRIVATE "-fno-exceptions" @@ -61,20 +82,6 @@ target_compile_options(${PROJECT_NAME} PRIVATE "-Wconversion" "-Wno-sign-conversion") -find_library(DW_LIB NAMES dw) -if (NOT DW_LIB STREQUAL DW_LIB-NOTFOUND) - message("-- Enhanced stack-traces are enabled via libdw: ${DW_LIB}") - target_compile_definitions(${PROJECT_NAME} PRIVATE "BACKWARD_HAS_DW=1") - target_link_libraries(${PROJECT_NAME} PUBLIC "${DW_LIB}") -else() - find_library(BFD_LIB NAMES bfd) - if (NOT BFD_LIB STREQUAL BFD_LIB-NOTFOUND) - message("-- Enhanced stack-traces are enabled via libbfd: ${BFD_LIB}") - target_compile_definitions(${PROJECT_NAME} PRIVATE "BACKWARD_HAS_BFD=1") - target_link_libraries(${PROJECT_NAME} PRIVATE "${BFD_LIB}") - endif() -endif() - if (LOG_VERBOSITY) target_compile_definitions(${PROJECT_NAME} PRIVATE "AWS_LAMBDA_LOG=${LOG_VERBOSITY}") elseif(CMAKE_BUILD_TYPE STREQUAL Debug) diff --git a/src/backward.cpp b/src/backward.cpp index cc64abd..8649fd5 100644 --- a/src/backward.cpp +++ b/src/backward.cpp @@ -23,10 +23,14 @@ // - g++/clang++ -lbfd ... // #define BACKWARD_HAS_BFD 1 -#include "backward.h" +#ifndef no_backtrace + +# include "backward.h" namespace backward { backward::SignalHandling sh; } // namespace backward + +#endif diff --git a/src/backward.h b/src/backward.h index c421378..832c452 100644 --- a/src/backward.h +++ b/src/backward.h @@ -28,6 +28,10 @@ # error "It's not going to compile without a C++ compiler..." #endif +#ifdef no_backtrace +# pragma message "Disabling stacktracing" +#else + #if defined(BACKWARD_CXX11) #elif defined(BACKWARD_CXX98) #else @@ -4539,4 +4543,6 @@ class SignalHandling { } // namespace backward +#endif /* no_backtrace */ + #endif /* H_GUARD */ From 934d2547fd573ece89ccbdaad2161a7e4d46fd1e Mon Sep 17 00:00:00 2001 From: Marco Magdy Date: Thu, 16 Nov 2023 09:31:17 -0800 Subject: [PATCH 81/84] Use the Lambda executable as the bootstrap when glibc is not required (#191) * Use the Lambda executable as the bootstrap when glibc is not required * Fix integration tests --------- Co-authored-by: Marco Magdy --- packaging/packager | 13 ++----------- tests/resources/lambda_function.cpp | 9 +++------ 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/packaging/packager b/packaging/packager index 0c4e749..c050696 100755 --- a/packaging/packager +++ b/packaging/packager @@ -171,20 +171,11 @@ exec \$LAMBDA_TASK_ROOT/lib/$PKG_LD --library-path \$LAMBDA_TASK_ROOT/lib \$LAMB EOF ) -bootstrap_script_no_libc=$(cat < "$PKG_DIR/bootstrap" else - echo -e "$bootstrap_script_no_libc" > "$PKG_DIR/bootstrap" + cp "$PKG_BIN_PATH" "$PKG_DIR/bootstrap" fi chmod +x "$PKG_DIR/bootstrap" # some shenanigans to create the right layout in the zip file without extraneous directories diff --git a/tests/resources/lambda_function.cpp b/tests/resources/lambda_function.cpp index b0228d3..bf12fc0 100644 --- a/tests/resources/lambda_function.cpp +++ b/tests/resources/lambda_function.cpp @@ -41,12 +41,9 @@ int main(int argc, char* argv[]) handlers.emplace("binary_response", binary_response); handlers.emplace("crash_backtrace", crash_backtrace); - if (argc < 2) { - aws::logging::log_error("lambda_fun", "Missing handler argument. Exiting."); - return -1; - } - - auto it = handlers.find(argv[1]); + // Read the handler from the environment variable + const char* handler_name = std::getenv("_HANDLER"); + auto it = handlers.find(handler_name == nullptr ? "" : handler_name); if (it == handlers.end()) { aws::logging::log_error("lambda_fun", "Handler %s not found. Exiting.", argv[1]); return -2; From 074d122b34da828fca25a5050a9935dfe85c6c80 Mon Sep 17 00:00:00 2001 From: Christian Ulbrich Date: Tue, 29 Apr 2025 12:52:35 +0200 Subject: [PATCH 82/84] Bugfix/fix minor documentation issues (#203) * Fix docs for current AWS CLI and current AWS Lambda runtimes * provided has to be either provided.al2023 or provided.al2 * AWS CLI2 has changed the param format * add docs about building on arm64 * minor docs update * use proper JSON in example * add hint on how to update example Lambda --- README.md | 18 +++++++++++++----- examples/demo/main.cpp | 2 +- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 74e60af..f702470 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ static invocation_response my_handler(invocation_request const& req) "error type here" /*error_type*/); } - return invocation_response::success("json payload here" /*payload*/, + return invocation_response::success("{\"message:\":\"I fail if body length is bigger than 42!\"}" /*payload*/, "application/json" /*MIME type*/); } @@ -130,13 +130,19 @@ And finally, create the Lambda function: ``` $ aws lambda create-function --function-name demo \ --role \ ---runtime provided --timeout 15 --memory-size 128 \ +--runtime provided.al2023 --timeout 15 --memory-size 128 \ --handler demo --zip-file fileb://demo.zip ``` +> **N.B.** If you are building on `arm64`, you have to explicitly add the param `--architectures arm64`, so that you are setting up the proper architecture on AWS to run your supplied Lambda function. And to invoke the function: ```bash -$ aws lambda invoke --function-name demo --payload '{"answer":42}' output.txt +$ aws lambda invoke --function-name demo --cli-binary-format raw-in-base64-out --payload '{"answer":42}' output.txt +``` + +You can update your supplied function: +```bash +$ aws lambda update-function-code --function-name demo --zip-file fileb://demo.zip ``` ## Using the C++ SDK for AWS with this runtime @@ -150,7 +156,7 @@ Any *fully* compliant C++11 compiler targeting GNU/Linux x86-64 should work. Ple - Use Clang v3.3 or above ## Packaging, ABI, GNU C Library, Oh My! -Lambda runs your code on some version of Amazon Linux. It would be a less than ideal customer experience if you are forced to build your application on that platform and that platform only. +Lambda runs your code on some version of Amazon Linux. It would be a less than ideal customer experience if you are forced to build your application on that platform and that platform only. However, the freedom to build on any linux distro brings a challenge. The GNU C Library ABI. There is no guarantee the platform used to build the Lambda function has the same GLIBC version as the one used by AWS Lambda. In fact, you might not even be using GNU's implementation. For example you could build a C++ Lambda function using musl libc. @@ -196,10 +202,12 @@ curl_easy_setopt(curl_handle, CURLOPT_CAINFO, "/etc/pki/tls/certs/ca-bundle.crt" ```bash $ aws lambda create-function --function-name demo \ --role \ - --runtime provided --timeout 15 --memory-size 128 \ + --runtime provided.al2023 --timeout 15 --memory-size 128 \ --handler demo --code "S3Bucket=mys3bucket,S3Key=demo.zip" ``` +> **N.B.** See hint above if you are building on `arm64`. + 1. **My code is crashing, how can I debug it?** - Starting with [v0.2.0](https://github.com/awslabs/aws-lambda-cpp/releases/tag/v0.2.0) you should see a stack-trace of the crash site in the logs (which are typically stored in CloudWatch). diff --git a/examples/demo/main.cpp b/examples/demo/main.cpp index 358efe0..5381311 100644 --- a/examples/demo/main.cpp +++ b/examples/demo/main.cpp @@ -9,7 +9,7 @@ static invocation_response my_handler(invocation_request const& req) "error type here" /*error_type*/); } - return invocation_response::success("json payload here" /*payload*/, + return invocation_response::success("{\"message:\":\"I fail if body length is bigger than 42!\"}" /*payload*/, "application/json" /*MIME type*/); } From 0e99247d90dbec53f68c4f7ffafab321e582e1d4 Mon Sep 17 00:00:00 2001 From: koki watanabe <56009584+math-hiyoko@users.noreply.github.com> Date: Tue, 29 Apr 2025 21:33:10 +0900 Subject: [PATCH 83/84] delete extra space (#198) --- src/runtime.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime.cpp b/src/runtime.cpp index 2ae91e2..1013a19 100644 --- a/src/runtime.cpp +++ b/src/runtime.cpp @@ -527,7 +527,7 @@ invocation_response invocation_response::failure(std::string const& error_messag r.m_success = false; r.m_content_type = "application/json"; r.m_payload = R"({"errorMessage":")" + json_escape(error_message) + R"(","errorType":")" + json_escape(error_type) + - R"(", "stackTrace":[]})"; + R"(","stackTrace":[]})"; return r; } From d89a26aa818cf4c61fa442287e2ed548ae63c42f Mon Sep 17 00:00:00 2001 From: Maxime David Date: Wed, 30 Apr 2025 13:35:38 +0100 Subject: [PATCH 84/84] feat: add unit tests in ci (#201) --- .clang-tidy | 1 + .github/workflows/workflow.yml | 35 ++++----------- README.md | 17 ++++++++ tests/CMakeLists.txt | 53 ++++++++++++++++++----- tests/{ => integration}/main.cpp | 2 +- tests/{ => integration}/runtime_tests.cpp | 2 +- tests/{ => integration}/version_tests.cpp | 2 +- tests/unit/no_op_test.cpp | 6 +++ 8 files changed, 78 insertions(+), 40 deletions(-) rename tests/{ => integration}/main.cpp (97%) rename tests/{ => integration}/runtime_tests.cpp (99%) rename tests/{ => integration}/version_tests.cpp (93%) create mode 100644 tests/unit/no_op_test.cpp diff --git a/.clang-tidy b/.clang-tidy index d42139e..616d471 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -4,6 +4,7 @@ Checks: -modernize-use-trailing-return-type,-bugprone-easily-swappable-parameters,-readability-identifier-length' WarningsAsErrors: '*' HeaderFilterRegex: 'include/aws/.*\.h$' +ExcludeHeaderFilter: 'build/_deps/gtest-src.*' FormatStyle: 'none' CheckOptions: - key: modernize-pass-by-value.ValuesOnly diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 526b38a..7da0628 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -12,39 +12,24 @@ env: jobs: build: - # The CMake configure and build commands are platform agnostic and should work equally - # well on Windows or Mac. You can convert this to a matrix build if you need - # cross-platform coverage. - # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix - runs-on: ubuntu-latest + strategy: + matrix: + arch: [ubuntu-latest, ubuntu-24.04-arm] + runs-on: ${{ matrix.arch }} steps: - uses: actions/checkout@v3 - - name: Install Dependencies run: sudo apt-get update && sudo apt-get install -y clang-tidy libcurl4-openssl-dev - name: Configure CMake - # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. - # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type - run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_CXX_CLANG_TIDY=clang-tidy + run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_CXX_CLANG_TIDY=clang-tidy -DENABLE_TESTS=ON - name: Build It - # Build your program with the given configuration run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} - build-on-arm-too: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: uraimo/run-on-arch-action@v2 - with: - arch: aarch64 - distro: ubuntu20.04 - run: | - apt-get update && apt-get install -y cmake g++ clang-tidy libcurl4-openssl-dev - cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_CXX_CLANG_TIDY=clang-tidy - cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} + - name: Test It + run: cd build && make && ctest build-demo: runs-on: ubuntu-latest @@ -68,15 +53,11 @@ jobs: cmake .. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=~/lambda-install make make aws-lambda-package-demo - - + format: runs-on: ubuntu-latest - steps: - uses: actions/checkout@v3 - name: Check Formatting run: ./ci/codebuild/format-check.sh - - diff --git a/README.md b/README.md index f702470..0f58b28 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,23 @@ $ cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=~/lambda-install $ make && make install ``` +### Running Unit Tests Locally + +To run the unit tests locally, follow these steps to build: + +```bash +$ cd aws-lambda-cpp +$ mkdir build +$ cd build +$ cmake .. -DCMAKE_BUILD_TYPE=Debug -DENABLE_TESTS=ON +$ make +``` + +Run unit tests: +```bash +$ ctest +``` + To consume this library in a project that is also using CMake, you would do: ```cmake diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 06bf89a..7406096 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,17 +1,50 @@ +cmake_minimum_required(VERSION 3.11) project(aws-lambda-runtime-tests LANGUAGES CXX) -find_package(AWSSDK COMPONENTS lambda iam) +if(DEFINED ENV{GITHUB_ACTIONS}) + # Fetch Google Test for unit tests + include(FetchContent) + FetchContent_Declare(gtest + URL https://github.com/google/googletest/archive/v1.12.0.tar.gz + DOWNLOAD_EXTRACT_TIMESTAMP TRUE + ) + # Configure build of googletest + set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + set(BUILD_GMOCK OFF CACHE BOOL "" FORCE) + set(INSTALL_GTEST OFF) + FetchContent_MakeAvailable(gtest) -add_executable(${PROJECT_NAME} - main.cpp - runtime_tests.cpp - version_tests.cpp - gtest/gtest-all.cc) + add_executable(unit_tests + unit/no_op_test.cpp) + target_link_libraries(unit_tests PRIVATE gtest_main aws-lambda-runtime) -target_link_libraries(${PROJECT_NAME} PRIVATE ${AWSSDK_LINK_LIBRARIES} aws-lambda-runtime) + # Register unit tests + include(GoogleTest) + gtest_discover_tests(unit_tests + PROPERTIES + LABELS "unit" + DISCOVERY_TIMEOUT 10) +else() + message(STATUS "Unit tests skipped: Not in GitHub Actions environment") +endif() -include(GoogleTest) -gtest_discover_tests(${PROJECT_NAME} EXTRA_ARGS "--aws_prefix=${TEST_RESOURCE_PREFIX}") # requires CMake 3.10 or later -add_subdirectory(resources) +find_package(AWSSDK COMPONENTS lambda iam QUIET) + +if(AWSSDK_FOUND) + add_executable(${PROJECT_NAME} + integration/main.cpp + integration/runtime_tests.cpp + integration/version_tests.cpp + gtest/gtest-all.cc) + + target_link_libraries(${PROJECT_NAME} PRIVATE ${AWSSDK_LINK_LIBRARIES} aws-lambda-runtime) + + include(GoogleTest) + gtest_discover_tests(${PROJECT_NAME} EXTRA_ARGS "--aws_prefix=${TEST_RESOURCE_PREFIX}") + + add_subdirectory(resources) +else() + message(STATUS "Integration tests skipped: AWS SDK not found or not in GitHub Actions environment") +endif() diff --git a/tests/main.cpp b/tests/integration/main.cpp similarity index 97% rename from tests/main.cpp rename to tests/integration/main.cpp index d7700e8..2a112d3 100644 --- a/tests/main.cpp +++ b/tests/integration/main.cpp @@ -1,6 +1,6 @@ #include #include -#include "gtest/gtest.h" +#include "../gtest/gtest.h" std::function()> get_console_logger_factory() { diff --git a/tests/runtime_tests.cpp b/tests/integration/runtime_tests.cpp similarity index 99% rename from tests/runtime_tests.cpp rename to tests/integration/runtime_tests.cpp index f118dab..843f815 100644 --- a/tests/runtime_tests.cpp +++ b/tests/integration/runtime_tests.cpp @@ -13,7 +13,7 @@ #include #include #include -#include "gtest/gtest.h" +#include "../gtest/gtest.h" #include #include #include diff --git a/tests/version_tests.cpp b/tests/integration/version_tests.cpp similarity index 93% rename from tests/version_tests.cpp rename to tests/integration/version_tests.cpp index 070b6dd..a0f546e 100644 --- a/tests/version_tests.cpp +++ b/tests/integration/version_tests.cpp @@ -1,5 +1,5 @@ #include -#include "gtest/gtest.h" +#include "../gtest/gtest.h" using namespace aws::lambda_runtime; diff --git a/tests/unit/no_op_test.cpp b/tests/unit/no_op_test.cpp new file mode 100644 index 0000000..c9a3b7d --- /dev/null +++ b/tests/unit/no_op_test.cpp @@ -0,0 +1,6 @@ +#include + +TEST(noop, dummy_test) +{ + ASSERT_EQ(0, 0); +}