diff --git a/AK/NoAllocationGuard.h b/AK/NoAllocationGuard.h new file mode 100644 index 00000000000..5778f7fd859 --- /dev/null +++ b/AK/NoAllocationGuard.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2022, kleines Filmröllchen . + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +#if defined(KERNEL) +# include +# include +#else +# include +#endif + +namespace AK { + +class NoAllocationGuard { + AK_MAKE_NONCOPYABLE(NoAllocationGuard); + AK_MAKE_NONMOVABLE(NoAllocationGuard); + +public: + NoAllocationGuard() + : m_allocation_enabled_previously(get_thread_allocation_state()) + { + set_thread_allocation_state(false); + } + + ~NoAllocationGuard() + { + set_thread_allocation_state(m_allocation_enabled_previously); + } + +private: + static bool get_thread_allocation_state() + { +#if defined(KERNEL) + return Processor::current_thread()->get_allocation_enabled(); +#else + return s_allocation_enabled; +#endif + } + + static void set_thread_allocation_state(bool value) + { +#if defined(KERNEL) + Processor::current_thread()->set_allocation_enabled(value); +#else + s_allocation_enabled = value; +#endif + } + + bool m_allocation_enabled_previously; +}; + +} + +using AK::NoAllocationGuard; diff --git a/Userland/Libraries/LibC/malloc.cpp b/Userland/Libraries/LibC/malloc.cpp index bdaf8b1f534..a059e558952 100644 --- a/Userland/Libraries/LibC/malloc.cpp +++ b/Userland/Libraries/LibC/malloc.cpp @@ -198,8 +198,18 @@ enum class CallerWillInitializeMemory { Yes, }; +#ifndef NO_TLS +// HACK: This is a __thread - marked thread-local variable. If we initialize it globally here, VERY weird errors happen. +// The initialization happens in __malloc_init() and pthread_create_helper(). +__thread bool s_allocation_enabled; +#endif + static void* malloc_impl(size_t size, CallerWillInitializeMemory caller_will_initialize_memory) { +#ifndef NO_TLS + VERIFY(s_allocation_enabled); +#endif + if (s_log_malloc) dbgln("LibC: malloc({})", size); @@ -330,6 +340,10 @@ static void* malloc_impl(size_t size, CallerWillInitializeMemory caller_will_ini static void free_impl(void* ptr) { +#ifndef NO_TLS + VERIFY(s_allocation_enabled); +#endif + ScopedValueRollback rollback(errno); if (!ptr) @@ -534,6 +548,12 @@ void* realloc(void* ptr, size_t size) void __malloc_init() { +#ifndef NO_TLS + // HACK: This is a __thread - marked thread-local variable. If we initialize it globally, VERY weird errors happen. + // Therefore, we need to do the initialization here and in pthread_create_helper(). + s_allocation_enabled = true; +#endif + s_in_userspace_emulator = (int)syscall(SC_emuctl, 0) != -ENOSYS; if (s_in_userspace_emulator) { // Don't bother scrubbing memory if we're running in UE since it diff --git a/Userland/Libraries/LibC/mallocdefs.h b/Userland/Libraries/LibC/mallocdefs.h index da4c8c61a59..dd2c3f5cd99 100644 --- a/Userland/Libraries/LibC/mallocdefs.h +++ b/Userland/Libraries/LibC/mallocdefs.h @@ -19,6 +19,12 @@ static constexpr unsigned short size_classes[] = { 16, 32, 64, 128, 256, 496, 1008, 2032, 4080, 8176, 16368, 32752, 0 }; static constexpr size_t num_size_classes = (sizeof(size_classes) / sizeof(unsigned short)) - 1; +#ifndef NO_TLS +extern "C" { +extern __thread bool s_allocation_enabled; +} +#endif + consteval bool check_size_classes_alignment() { for (size_t i = 0; i < num_size_classes; i++) { diff --git a/Userland/Libraries/LibPthread/pthread.cpp b/Userland/Libraries/LibPthread/pthread.cpp index f5855780940..38997a8139e 100644 --- a/Userland/Libraries/LibPthread/pthread.cpp +++ b/Userland/Libraries/LibPthread/pthread.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -43,6 +44,9 @@ extern "C" { static void* pthread_create_helper(void* (*routine)(void*), void* argument, void* stack_location, size_t stack_size) { + // HACK: This is a __thread - marked thread-local variable. If we initialize it globally, VERY weird errors happen. + // Therefore, we need to do the initialization here and in __malloc_init(). + s_allocation_enabled = true; s_stack_location = stack_location; s_stack_size = stack_size; void* ret_val = routine(argument);