From 58f32435e8bf8e32c4e2fbe7ffa866ffc52fab13 Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Thu, 16 Apr 2020 16:59:35 -0400 Subject: [PATCH] [libc++abi] Add a rate limiter when logging dynamic_cast errors This upstreams a fix that Howard made a long time ago, where so many errors would be logged that applications were becoming sluggish. With this patch, the first three errors will be printed, and after that the printing frequency decreases exponentially. _LIBCXX_DYNAMIC_FALLBACK is only enabled on Apple platforms, so this should be NFC for other platforms. rdar://14996273 Differential Revision: https://reviews.llvm.org/D78330 --- libcxxabi/src/private_typeinfo.cpp | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/libcxxabi/src/private_typeinfo.cpp b/libcxxabi/src/private_typeinfo.cpp index 5ce762a22bc4..898cfaef7527 100644 --- a/libcxxabi/src/private_typeinfo.cpp +++ b/libcxxabi/src/private_typeinfo.cpp @@ -46,6 +46,7 @@ #ifdef _LIBCXX_DYNAMIC_FALLBACK #include "abort_message.h" #include +#include #endif static inline @@ -640,9 +641,12 @@ __dynamic_cast(const void *static_ptr, const __class_type_info *static_type, { // We get here only if there is some kind of visibility problem // in client code. - syslog(LOG_ERR, "dynamic_cast error 1: Both of the following type_info's " - "should have public visibility. At least one of them is hidden. %s" - ", %s.\n", static_type->name(), dynamic_type->name()); + static std::atomic error_count(0); + size_t error_count_snapshot = error_count.fetch_add(1, std::memory_order_relaxed); + if ((error_count_snapshot & (error_count_snapshot-1)) == 0) + syslog(LOG_ERR, "dynamic_cast error 1: Both of the following type_info's " + "should have public visibility. At least one of them is hidden. %s" + ", %s.\n", static_type->name(), dynamic_type->name()); // Redo the search comparing type_info's using strcmp info = {dst_type, static_ptr, static_type, src2dst_offset, 0}; info.number_of_dst_type = 1; @@ -663,11 +667,14 @@ __dynamic_cast(const void *static_ptr, const __class_type_info *static_type, if (info.path_dst_ptr_to_static_ptr == unknown && info.path_dynamic_ptr_to_static_ptr == unknown) { - syslog(LOG_ERR, "dynamic_cast error 2: One or more of the following type_info's " - "has hidden visibility or is defined in more than one translation " - "unit. They should all have public visibility. " - "%s, %s, %s.\n", static_type->name(), dynamic_type->name(), - dst_type->name()); + static std::atomic error_count(0); + size_t error_count_snapshot = error_count.fetch_add(1, std::memory_order_relaxed); + if ((error_count_snapshot & (error_count_snapshot-1)) == 0) + syslog(LOG_ERR, "dynamic_cast error 2: One or more of the following type_info's " + "has hidden visibility or is defined in more than one translation " + "unit. They should all have public visibility. " + "%s, %s, %s.\n", static_type->name(), dynamic_type->name(), + dst_type->name()); // Redo the search comparing type_info's using strcmp info = {dst_type, static_ptr, static_type, src2dst_offset, 0}; dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, true);