[libcxx-commits] [libcxx] [libc++] Introduce a standalone __scope_guard and use it in <string> (PR #114867)
via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Nov 4 12:53:50 PST 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libcxx
Author: Nikolas Klauser (philnik777)
<details>
<summary>Changes</summary>
This introduces a new `__scope_guard` without any fancy features. The scope guard is used in `<string>` to simplify some of the ASan annotations (especially by making it harder to forget them where exceptions are thrown).
---
Full diff: https://github.com/llvm/llvm-project/pull/114867.diff
4 Files Affected:
- (modified) libcxx/include/__flat_map/flat_map.h (+1-1)
- (modified) libcxx/include/__utility/exception_guard.h (-6)
- (added) libcxx/include/__utility/scope_guard.h (+46)
- (modified) libcxx/include/string (+13-6)
``````````diff
diff --git a/libcxx/include/__flat_map/flat_map.h b/libcxx/include/__flat_map/flat_map.h
index 5c14c0ac693b08..076c14f64018af 100644
--- a/libcxx/include/__flat_map/flat_map.h
+++ b/libcxx/include/__flat_map/flat_map.h
@@ -50,7 +50,7 @@
#include <__type_traits/is_nothrow_constructible.h>
#include <__type_traits/is_same.h>
#include <__type_traits/maybe_const.h>
-#include <__utility/exception_guard.h>
+#include <__utility/scope_guard.h>
#include <__utility/pair.h>
#include <initializer_list>
#include <stdexcept>
diff --git a/libcxx/include/__utility/exception_guard.h b/libcxx/include/__utility/exception_guard.h
index 00b835d3e2a2fc..a03bd7e8f35227 100644
--- a/libcxx/include/__utility/exception_guard.h
+++ b/libcxx/include/__utility/exception_guard.h
@@ -137,12 +137,6 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __exception_guard<_Rollback> __make_exce
return __exception_guard<_Rollback>(std::move(__rollback));
}
-template <class _Rollback>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __exception_guard_exceptions<_Rollback>
-__make_scope_guard(_Rollback __rollback) {
- return __exception_guard_exceptions<_Rollback>(std::move(__rollback));
-}
-
_LIBCPP_END_NAMESPACE_STD
_LIBCPP_POP_MACROS
diff --git a/libcxx/include/__utility/scope_guard.h b/libcxx/include/__utility/scope_guard.h
new file mode 100644
index 00000000000000..865ced71ffc44c
--- /dev/null
+++ b/libcxx/include/__utility/scope_guard.h
@@ -0,0 +1,46 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___UTILITY_SCOPE_GUARD_H
+#define _LIBCPP___UTILITY_SCOPE_GUARD_H
+
+#include <__config>
+#include <__utility/move.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template <class _Func>
+class __scope_guard {
+ _Func __func_;
+
+public:
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __scope_guard(_Func __func) : __func_(std::move(__func)) {}
+ _LIBCPP_HIDE_FROM_ABI ~__scope_guard() { __func_(); }
+
+ __scope_guard(const __scope_guard&) = delete;
+ __scope_guard& operator=(const __scope_guard&) = delete;
+};
+
+template <class _Func>
+__scope_guard<_Func> __make_scope_guard(_Func __func) {
+ return __scope_guard<_Func>(std::move(__func));
+}
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___UTILITY_SCOPE_GUARD_H
diff --git a/libcxx/include/string b/libcxx/include/string
index 20e44eaca2ac7a..caea2707fbd479 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -638,6 +638,7 @@ basic_string<char32_t> operator""s( const char32_t *str, size_t len );
#include <__utility/forward.h>
#include <__utility/is_pointer_in_range.h>
#include <__utility/move.h>
+#include <__utility/scope_guard.h>
#include <__utility/swap.h>
#include <__utility/unreachable.h>
#include <climits>
@@ -929,6 +930,13 @@ private:
_LIBCPP_COMPRESSED_PAIR(__rep, __rep_, allocator_type, __alloc_);
+ // annotate the string with its size() at scope exit. The string has to be in a valid state at that point.
+ struct __annotate_new_size {
+ basic_string& __str_;
+
+ void operator()() { __str_.__annotate_new(__str_.size()); }
+ };
+
// Construct a string with the given allocator and enough storage to hold `__size` characters, but
// don't initialize the characters. The contents of the string, including the null terminator, must be
// initialized separately.
@@ -2169,6 +2177,7 @@ private:
__alloc_ = __str.__alloc_;
} else {
__annotate_delete();
+ auto __guard = std::__make_scope_guard(__annotate_new_size(*this));
allocator_type __a = __str.__alloc_;
auto __allocation = std::__allocate_at_least(__a, __str.__get_long_cap());
__begin_lifetime(__allocation.ptr, __allocation.count);
@@ -2178,7 +2187,6 @@ private:
__set_long_pointer(__allocation.ptr);
__set_long_cap(__allocation.count);
__set_long_size(__str.size());
- __annotate_new(__get_long_size());
}
}
}
@@ -2506,6 +2514,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::__
size_type __cap =
__old_cap < __ms / 2 - __alignment ? __recommend(std::max(__old_cap + __delta_cap, 2 * __old_cap)) : __ms - 1;
__annotate_delete();
+ auto __guard = std::__make_scope_guard(__annotate_new_size(*this));
auto __allocation = std::__allocate_at_least(__alloc_, __cap + 1);
pointer __p = __allocation.ptr;
__begin_lifetime(__p, __allocation.count);
@@ -2524,7 +2533,6 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::__
__old_sz = __n_copy + __n_add + __sec_cp_sz;
__set_long_size(__old_sz);
traits_type::assign(__p[__old_sz], value_type());
- __annotate_new(__old_sz);
}
// __grow_by is deprecated because it does not set the size. It may not update the size when the size is changed, and it
@@ -2548,7 +2556,6 @@ _LIBCPP_DEPRECATED_("use __grow_by_without_replace") basic_string<_CharT, _Trait
pointer __old_p = __get_pointer();
size_type __cap =
__old_cap < __ms / 2 - __alignment ? __recommend(std::max(__old_cap + __delta_cap, 2 * __old_cap)) : __ms - 1;
- __annotate_delete();
auto __allocation = std::__allocate_at_least(__alloc_, __cap + 1);
pointer __p = __allocation.ptr;
__begin_lifetime(__p, __allocation.count);
@@ -2573,11 +2580,12 @@ basic_string<_CharT, _Traits, _Allocator>::__grow_by_without_replace(
size_type __n_copy,
size_type __n_del,
size_type __n_add) {
+ __annotate_delete();
+ auto __guard = std::__make_scope_guard(__annotate_new_size(*this));
_LIBCPP_SUPPRESS_DEPRECATED_PUSH
__grow_by(__old_cap, __delta_cap, __old_sz, __n_copy, __n_del, __n_add);
_LIBCPP_SUPPRESS_DEPRECATED_POP
__set_long_size(__old_sz - __n_del + __n_add);
- __annotate_new(__old_sz - __n_del + __n_add);
}
// assign
@@ -3367,6 +3375,7 @@ template <class _CharT, class _Traits, class _Allocator>
inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void
basic_string<_CharT, _Traits, _Allocator>::__shrink_or_extend(size_type __target_capacity) {
__annotate_delete();
+ auto __guard = std::__make_scope_guard(__annotate_new_size(*this));
size_type __cap = capacity();
size_type __sz = size();
@@ -3398,7 +3407,6 @@ basic_string<_CharT, _Traits, _Allocator>::__shrink_or_extend(size_type __target
// due to swapping the elements.
if (__allocation.count - 1 > __target_capacity) {
__alloc_traits::deallocate(__alloc_, __allocation.ptr, __allocation.count);
- __annotate_new(__sz); // Undoes the __annotate_delete()
return;
}
__new_data = __allocation.ptr;
@@ -3423,7 +3431,6 @@ basic_string<_CharT, _Traits, _Allocator>::__shrink_or_extend(size_type __target
__set_long_pointer(__new_data);
} else
__set_short_size(__sz);
- __annotate_new(__sz);
}
template <class _CharT, class _Traits, class _Allocator>
``````````
</details>
https://github.com/llvm/llvm-project/pull/114867
More information about the libcxx-commits
mailing list