Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 63 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ option(SNMALLOC_ENABLE_DYNAMIC_LOADING "Build such that snmalloc can be dynamica
option(SNMALLOC_ENABLE_WAIT_ON_ADDRESS "Use wait on address backoff strategy if it is available" ON)
option(SNMALLOC_PTHREAD_FORK_PROTECTION "Guard against forking while allocator locks are held using pthread_atfork hooks" OFF)
option(SNMALLOC_ENABLE_FUZZING "Enable fuzzing instrumentation tests" OFF)
option(SNMALLOC_ENABLE_LIFETIME_SAFETY "Enable Clang lifetime safety diagnostics when supported" ON)
option(SNMALLOC_USE_SELF_VENDORED_STL "Avoid using system STL" OFF)
# Options that apply only if we're not building the header-only library
cmake_dependent_option(SNMALLOC_RUST_SUPPORT "Build static library for rust" OFF "NOT SNMALLOC_HEADER_ONLY_LIBRARY" OFF)
Expand Down Expand Up @@ -374,6 +375,61 @@ if(SNMALLOC_COMPILER_SUPPORT_MCX16)
target_compile_options(snmalloc INTERFACE $<$<COMPILE_LANGUAGE:CXX>:-mcx16>)
endif()

set(SNMALLOC_LIFETIME_SAFETY_FLAGS "")
if(SNMALLOC_ENABLE_LIFETIME_SAFETY AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
check_cxx_compiler_flag(
"-Werror -Wlifetime-safety-permissive"
SNMALLOC_COMPILER_SUPPORT_LIFETIME_SAFETY_PERMISSIVE)
if(SNMALLOC_COMPILER_SUPPORT_LIFETIME_SAFETY_PERMISSIVE)
list(APPEND SNMALLOC_LIFETIME_SAFETY_FLAGS -Wlifetime-safety-permissive)
else()
check_cxx_compiler_flag(
"-Werror -Wexperimental-lifetime-safety-permissive"
SNMALLOC_COMPILER_SUPPORT_EXPERIMENTAL_LIFETIME_SAFETY_PERMISSIVE)
if(SNMALLOC_COMPILER_SUPPORT_EXPERIMENTAL_LIFETIME_SAFETY_PERMISSIVE)
list(APPEND SNMALLOC_LIFETIME_SAFETY_FLAGS
-Wexperimental-lifetime-safety-permissive)
endif()
endif()

check_cxx_compiler_flag(
"-Werror -Wlifetime-safety-suggestions"
SNMALLOC_COMPILER_SUPPORT_LIFETIME_SAFETY_SUGGESTIONS)
if(SNMALLOC_COMPILER_SUPPORT_LIFETIME_SAFETY_SUGGESTIONS)
list(APPEND SNMALLOC_LIFETIME_SAFETY_FLAGS -Wlifetime-safety-suggestions)
else()
check_cxx_compiler_flag(
"-Werror -Wexperimental-lifetime-safety-suggestions"
SNMALLOC_COMPILER_SUPPORT_EXPERIMENTAL_LIFETIME_SAFETY_SUGGESTIONS)
if(SNMALLOC_COMPILER_SUPPORT_EXPERIMENTAL_LIFETIME_SAFETY_SUGGESTIONS)
list(APPEND SNMALLOC_LIFETIME_SAFETY_FLAGS
-Wexperimental-lifetime-safety-suggestions)
endif()
endif()

check_cxx_compiler_flag(
"-flifetime-safety-inference"
SNMALLOC_COMPILER_SUPPORT_LIFETIME_SAFETY_INFERENCE)
if(SNMALLOC_COMPILER_SUPPORT_LIFETIME_SAFETY_INFERENCE)
list(APPEND SNMALLOC_LIFETIME_SAFETY_FLAGS -flifetime-safety-inference)
endif()

check_cxx_compiler_flag(
"-fexperimental-lifetime-safety-tu-analysis"
SNMALLOC_COMPILER_SUPPORT_EXPERIMENTAL_LIFETIME_SAFETY_TU_ANALYSIS)
if(SNMALLOC_COMPILER_SUPPORT_EXPERIMENTAL_LIFETIME_SAFETY_TU_ANALYSIS)
list(APPEND SNMALLOC_LIFETIME_SAFETY_FLAGS
-fexperimental-lifetime-safety-tu-analysis)
endif()

if(SNMALLOC_LIFETIME_SAFETY_FLAGS)
string(JOIN " " SNMALLOC_LIFETIME_SAFETY_FLAGS_MESSAGE
${SNMALLOC_LIFETIME_SAFETY_FLAGS})
message(STATUS
"snmalloc: Enabling lifetime safety flags: ${SNMALLOC_LIFETIME_SAFETY_FLAGS_MESSAGE}")
endif()
endif()

if (NOT SNMALLOC_HEADER_ONLY_LIBRARY AND SNMALLOC_IPO)
check_ipo_supported(RESULT HAS_IPO)
if (HAS_IPO)
Expand Down Expand Up @@ -442,8 +498,13 @@ endif()
function(add_warning_flags name)
target_compile_options(${name} PRIVATE
$<$<CXX_COMPILER_ID:MSVC>:/Zi /W4 /WX /wd4127 /wd4324 /wd4201>
$<$<NOT:$<OR:$<CXX_COMPILER_ID:MSVC>,$<STREQUAL:${CMAKE_CXX_SIMULATE_ID},MSVC>>>:-fno-rtti -Wall -Wextra -Werror -Wundef>
$<$<CXX_COMPILER_ID:Clang>:-Wsign-conversion -Wconversion>)
$<$<NOT:$<OR:$<CXX_COMPILER_ID:MSVC>,$<STREQUAL:${CMAKE_CXX_SIMULATE_ID},MSVC>>>:-fno-rtti -Wall -Wextra -Werror -Wundef>)
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
target_compile_options(${name} PRIVATE -Wsign-conversion -Wconversion)
if(SNMALLOC_LIFETIME_SAFETY_FLAGS)
target_compile_options(${name} PRIVATE ${SNMALLOC_LIFETIME_SAFETY_FLAGS})
endif()
endif()
target_link_options(${name} PRIVATE
$<$<BOOL:${SNMALLOC_LINKER_SUPPORT_NO_ALLOW_SHLIB_UNDEF}>:-Wl,--no-undefined>
$<$<PLATFORM_ID:Windows>:$<${ci_or_debug}:/DEBUG>>)
Expand Down
46 changes: 23 additions & 23 deletions src/snmalloc/backend/globalconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,42 +95,42 @@ namespace snmalloc

// Performs initialisation for this configuration
// of allocators.
SNMALLOC_SLOW_PATH static void ensure_init_slow()
SNMALLOC_SLOW_PATH static void
ensure_init_slow() SNMALLOC_EXCLUDES(initialisation_lock)
{
if (initialised)
return;

with(initialisation_lock, [&]() {
FlagLock guard(initialisation_lock);
#ifdef SNMALLOC_TRACING
message<1024>("Run init_impl");
message<1024>("Run init_impl");
#endif

if (initialised)
return;
if (initialised)
return;

SecondaryAllocator::initialize();
SecondaryAllocator::initialize();

LocalEntropy entropy;
entropy.init<Pal>();
// Initialise key for remote deallocation lists
entropy.make_free_list_key(RemoteAllocator::key_global);
entropy.make_free_list_key(freelist::Object::key_root);
LocalEntropy entropy;
entropy.init<Pal>();
// Initialise key for remote deallocation lists
entropy.make_free_list_key(RemoteAllocator::key_global);
entropy.make_free_list_key(freelist::Object::key_root);

// Need to randomise pagemap location. If requested and not a
// StrictProvenance architecture, randomize its table's location within
// a significantly larger address space allocation.
static constexpr bool pagemap_randomize =
mitigations(random_pagemap) && !aal_supports<StrictProvenance>;
// Need to randomise pagemap location. If requested and not a
// StrictProvenance architecture, randomize its table's location within
// a significantly larger address space allocation.
static constexpr bool pagemap_randomize =
mitigations(random_pagemap) && !aal_supports<StrictProvenance>;

Pagemap::concretePagemap.template init<pagemap_randomize>();
Pagemap::concretePagemap.template init<pagemap_randomize>();

if constexpr (aal_supports<StrictProvenance>)
{
Authmap::init();
}
if constexpr (aal_supports<StrictProvenance>)
{
Authmap::init();
}

initialised.store(true, stl::memory_order_release);
});
initialised.store(true, stl::memory_order_release);
}

public:
Expand Down
5 changes: 3 additions & 2 deletions src/snmalloc/backend_helpers/commonconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ namespace snmalloc
return 1;
}

static DataRef get(StorageType* base, size_t)
static DataRef get(SNMALLOC_LIFETIMEBOUND StorageType* base, size_t)
{
return *base;
}
Expand All @@ -96,7 +96,8 @@ namespace snmalloc
return max_count;
}

static DataRef get(StorageType* base, size_t index)
static DataRef
get(SNMALLOC_LIFETIMEBOUND StorageType* base, size_t index)
{
return base[index];
}
Expand Down
16 changes: 5 additions & 11 deletions src/snmalloc/ds_aal/flaglock.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace snmalloc
* Wrapper for stl::AtomicBool so that we can examine
* the re-entrancy problem at debug mode.
*/
struct DebugFlagWord
struct SNMALLOC_CAPABILITY("mutex") DebugFlagWord
{
using ThreadIdentity = size_t;

Expand Down Expand Up @@ -80,7 +80,7 @@ namespace snmalloc
* all member functions associated with ownership checkings
* are empty so that they can be optimised out at Release mode.
*/
struct ReleaseFlagWord
struct SNMALLOC_CAPABILITY("mutex") ReleaseFlagWord
{
stl::AtomicBool flag{false};

Expand All @@ -104,7 +104,7 @@ namespace snmalloc
using FlagWord = DebugFlagWord;
#endif

class FlagLock
class SNMALLOC_SCOPED_CAPABILITY FlagLock
{
private:
FlagWord& lock;
Expand All @@ -114,7 +114,7 @@ namespace snmalloc
PreventFork pf{};

public:
FlagLock(FlagWord& lock) : lock(lock)
FlagLock(FlagWord& lock) SNMALLOC_ACQUIRE(lock) : lock(lock)
{
while (
SNMALLOC_UNLIKELY(lock.flag.exchange(true, stl::memory_order_acquire)))
Expand All @@ -133,17 +133,11 @@ namespace snmalloc
lock.set_owner();
}

~FlagLock()
~FlagLock() SNMALLOC_RELEASE()
{
lock.clear_owner();
lock.flag.store(false, stl::memory_order_release);
}
};

template<typename F>
inline void with(FlagWord& lock, F&& f)
{
FlagLock l(lock);
f();
}
} // namespace snmalloc
75 changes: 75 additions & 0 deletions src/snmalloc/ds_core/defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,85 @@
# define SNMALLOC_FORCE_BSS
#endif

#ifndef __has_attribute
# define __has_attribute(x) 0
#endif

#ifndef __has_cpp_attribute
# define __has_cpp_attribute(x) 0
#endif

#ifndef __has_builtin
# define __has_builtin(x) 0
#endif

// Clang's thread-safety annotations are used opportunistically and compile
// away on other toolchains.
#if defined(__clang__) && __has_attribute(capability) && !defined(SWIG)
# define SNMALLOC_THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
#else
# define SNMALLOC_THREAD_ANNOTATION_ATTRIBUTE__(x)
#endif

#define SNMALLOC_CAPABILITY(x) \
SNMALLOC_THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
#define SNMALLOC_REENTRANT_CAPABILITY \
SNMALLOC_THREAD_ANNOTATION_ATTRIBUTE__(reentrant_capability)
#define SNMALLOC_SCOPED_CAPABILITY \
SNMALLOC_THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
#define SNMALLOC_GUARDED_BY(...) \
SNMALLOC_THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(__VA_ARGS__))
#define SNMALLOC_PT_GUARDED_BY(...) \
SNMALLOC_THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(__VA_ARGS__))
#define SNMALLOC_ACQUIRED_BEFORE(...) \
SNMALLOC_THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
#define SNMALLOC_ACQUIRED_AFTER(...) \
SNMALLOC_THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
#define SNMALLOC_REQUIRES(...) \
SNMALLOC_THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__))
#define SNMALLOC_REQUIRES_SHARED(...) \
SNMALLOC_THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__))
#define SNMALLOC_ACQUIRE(...) \
SNMALLOC_THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__))
#define SNMALLOC_ACQUIRE_SHARED(...) \
SNMALLOC_THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__))
#define SNMALLOC_RELEASE(...) \
SNMALLOC_THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__))
#define SNMALLOC_RELEASE_SHARED(...) \
SNMALLOC_THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__))
#define SNMALLOC_RELEASE_GENERIC(...) \
SNMALLOC_THREAD_ANNOTATION_ATTRIBUTE__(release_generic_capability(__VA_ARGS__))
#define SNMALLOC_TRY_ACQUIRE(...) \
SNMALLOC_THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__))
#define SNMALLOC_TRY_ACQUIRE_SHARED(...) \
SNMALLOC_THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__))
#define SNMALLOC_EXCLUDES(...) \
SNMALLOC_THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
#define SNMALLOC_ASSERT_CAPABILITY(x) \
SNMALLOC_THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x))
#define SNMALLOC_ASSERT_SHARED_CAPABILITY(x) \
SNMALLOC_THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x))
#define SNMALLOC_RETURN_CAPABILITY(x) \
SNMALLOC_THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
#define SNMALLOC_NO_THREAD_SAFETY_ANALYSIS \
SNMALLOC_THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)

// Clang lifetime annotations are also opportunistic and erase cleanly on
// older or non-Clang toolchains.
#if __has_cpp_attribute(clang::lifetimebound)
# define SNMALLOC_LIFETIMEBOUND [[clang::lifetimebound]]
#elif __has_cpp_attribute(_Clang::__lifetimebound__)
# define SNMALLOC_LIFETIMEBOUND [[_Clang::__lifetimebound__]]
#else
# define SNMALLOC_LIFETIMEBOUND
#endif

#if __has_cpp_attribute(clang::noescape)
# define SNMALLOC_NOESCAPE [[clang::noescape]]
#else
# define SNMALLOC_NOESCAPE
#endif

namespace snmalloc
{
#ifdef NDEBUG
Expand Down
2 changes: 1 addition & 1 deletion src/snmalloc/global/scopedalloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ namespace snmalloc
* Arrow operator, allows methods exposed by `Alloc` to be called on the
* wrapper.
*/
SAlloc* operator->()
SAlloc* operator->() SNMALLOC_LIFETIMEBOUND
{
return alloc;
}
Expand Down
Loading
Loading