Loading...
--- libmalloc/libmalloc-116.30.3/tests/stack_logging_test.c
+++ libmalloc/libmalloc-166.200.60/tests/stack_logging_test.c
@@ -4,8 +4,11 @@
#include <malloc/malloc.h>
#include <mach/mach.h>
#include <mach/mach_vm.h>
-#include "stack_logging.h"
+#include <stack_logging.h>
#include <sys/stat.h>
+#include <sys/event.h>
+#include <malloc_private.h>
+#include <TargetConditionals.h>
#if DARWINTEST
#include <darwintest.h>
@@ -96,7 +99,7 @@
for (int i = 0; i < num_ptrs; i++) {
kern_return_t ret = (lite_mode) ?
- __mach_stack_logging_frames_for_uniqued_stack(mach_task_self(), get_stack_id_from_ptr(ptrs[i]), frames, MAX_FRAMES, &frames_count) :
+ __mach_stack_logging_get_frames_for_stackid(mach_task_self(), get_stack_id_from_ptr(ptrs[i]), frames, MAX_FRAMES, &frames_count, NULL) :
__mach_stack_logging_get_frames(mach_task_self(), (mach_vm_address_t) ptrs[i], frames, MAX_FRAMES, &frames_count);
EXPECT_TRUE(ret == KERN_SUCCESS, "return from __mach_stack_logging_get_frames = %d\n", (int) ret);
@@ -428,7 +431,7 @@
mach_vm_address_t frames[MAX_FRAMES];
uint32_t frames_count;
- kern_return_t ret = __mach_stack_logging_frames_for_uniqued_stack(mach_task_self(), get_stack_id_from_ptr(new_ptr), frames, MAX_FRAMES, &frames_count);
+ kern_return_t ret = __mach_stack_logging_get_frames_for_stackid(mach_task_self(), get_stack_id_from_ptr(new_ptr), frames, MAX_FRAMES, &frames_count, NULL);
EXPECT_TRUE(ret == KERN_SUCCESS, "return from __mach_stack_logging_get_frames = %d\n", (int) ret);
EXPECT_TRUE(frames_count > 0, "number of frames returned from __mach_stack_logging_get_frames = %u\n", frames_count);
@@ -436,7 +439,7 @@
// test that we can realloc the ptr now that it's in the lite zone
new_ptr = realloc(new_ptr, 100);
- ret = __mach_stack_logging_frames_for_uniqued_stack(mach_task_self(), get_stack_id_from_ptr(new_ptr), frames, MAX_FRAMES, &frames_count);
+ ret = __mach_stack_logging_get_frames_for_stackid(mach_task_self(), get_stack_id_from_ptr(new_ptr), frames, MAX_FRAMES, &frames_count, NULL);
EXPECT_TRUE(ret == KERN_SUCCESS, "return from __mach_stack_logging_get_frames = %d\n", (int) ret);
EXPECT_TRUE(frames_count > 0, "number of frames returned from __mach_stack_logging_get_frames = %u\n", frames_count);
@@ -592,6 +595,67 @@
}
}
+static void
+test_enable_disable_enable_msl(unsigned long enable_value_1, unsigned long enable_value_2, boolean_t vm_only)
+{
+ unsigned long event = enable_value_1;
+ // Turn on MSL malloc mode
+ malloc_memory_event_handler(event);
+
+ char *ptrs[1];
+ ptrs[0] = malloc(10);
+
+ boolean_t lite_or_vmlite_mode;
+ boolean_t expected_lite_mode = (enable_value_1 & MEMORYSTATUS_ENABLE_MSL_LITE) != 0;
+ kern_return_t ret = __mach_stack_logging_start_reading(mach_task_self(), __mach_stack_logging_shared_memory_address, &lite_or_vmlite_mode);
+ EXPECT_TRUE(ret == KERN_SUCCESS, "return from __mach_stack_logging_start_reading = %d", ret);
+ EXPECT_TRUE(lite_or_vmlite_mode == expected_lite_mode, "return from __mach_stack_logging_start_reading - lite_or_vmlite_mode = %d", lite_or_vmlite_mode);
+
+ // check to see if malloc stacks are present
+ if (!vm_only) {
+ check_stacks(ptrs, 1, lite_or_vmlite_mode);
+ }
+
+ // Turn off malloc mode
+ event = MEMORYSTATUS_DISABLE_MSL;
+ malloc_memory_event_handler(event);
+
+ // verify that the stacks are still there
+ // First have to clear any cached uniquing table, then check again
+ __mach_stack_logging_stop_reading(mach_task_self());
+ ret = __mach_stack_logging_start_reading(mach_task_self(), __mach_stack_logging_shared_memory_address, &lite_or_vmlite_mode);
+ EXPECT_TRUE(ret == KERN_SUCCESS, "return from __mach_stack_logging_start_reading = %d", ret);
+ EXPECT_TRUE(lite_or_vmlite_mode == expected_lite_mode, "return from __mach_stack_logging_start_reading - lite_or_vmlite_mode = %d", lite_or_vmlite_mode);
+
+ if (!vm_only) {
+ check_stacks(ptrs, 1, lite_or_vmlite_mode);
+ }
+
+ // now see if we can turn on malloc stack logging again
+ event = enable_value_2;
+ malloc_memory_event_handler(event);
+
+ __mach_stack_logging_stop_reading(mach_task_self());
+ ret = __mach_stack_logging_start_reading(mach_task_self(), __mach_stack_logging_shared_memory_address, &lite_or_vmlite_mode);
+ EXPECT_TRUE(ret == KERN_SUCCESS, "return from __mach_stack_logging_start_reading = %d", ret);
+ EXPECT_TRUE(lite_or_vmlite_mode == expected_lite_mode, "return from __mach_stack_logging_start_reading - lite_or_vmlite_mode = %d", lite_or_vmlite_mode);
+
+ extern int stack_logging_enable_logging;
+ extern boolean_t is_stack_logging_lite_enabled(void);
+
+ if (lite_or_vmlite_mode && enable_value_1 == enable_value_2 && enable_value_1 != MEMORYSTATUS_ENABLE_MSL_LITE_VM) {
+ EXPECT_TRUE(is_stack_logging_lite_enabled(), "is_stack_logging_lite_enabled() = %d", is_stack_logging_lite_enabled());
+ } else {
+ int expected_stack_logging_enable_logging = (enable_value_1 == enable_value_2);
+ EXPECT_TRUE(expected_stack_logging_enable_logging == stack_logging_enable_logging, "stack_logging_enable_logging = %d", stack_logging_enable_logging);
+ }
+
+ if (!vm_only) {
+ check_stacks(ptrs, 1, lite_or_vmlite_mode);
+ }
+
+ free(ptrs[0]);
+}
#if DARWINTEST
@@ -755,7 +819,7 @@
kr = __mach_stack_logging_start_reading(mach_task_self(), __mach_stack_logging_shared_memory_address, &lite_mode);
T_ASSERT_MACH_SUCCESS(kr, "start reading");
- kr = __mach_stack_logging_frames_for_uniqued_stack(mach_task_self(), stackid, frames1, STACK_LOGGING_MAX_STACK_SIZE, &count1);
+ kr = __mach_stack_logging_get_frames_for_stackid(mach_task_self(), stackid, frames1, STACK_LOGGING_MAX_STACK_SIZE, &count1, NULL);
T_ASSERT_MACH_SUCCESS(kr, "get frames");
T_ASSERT_TRUE(count1 > 0, "frames not empty");
@@ -790,6 +854,257 @@
__mach_stack_logging_stop_reading(mach_task_self());
}
+static vm_address_t
+__attribute__((noinline))
+allocate() {
+ vm_address_t region = 0;
+ vm_allocate(mach_task_self(), ®ion, 0x1000, VM_FLAGS_ANYWHERE);
+ return region;
+}
+
+static void
+__attribute__((noinline))
+allocate_end() {
+}
+
+static
+void
+do_test_msl_vm_stacks()
+{
+ vm_address_t region = allocate();
+
+ T_ASSERT_NOTNULL((void *)region, "allocated region");
+
+ boolean_t lite_mode;
+ kern_return_t kr = __mach_stack_logging_start_reading(mach_task_self(), __mach_stack_logging_shared_memory_address, &lite_mode);
+ T_ASSERT_MACH_SUCCESS(kr, "start reading");
+
+ T_ASSERT_TRUE(lite_mode, "check lite mode");
+
+ uint64_t stackid = __mach_stack_logging_stackid_for_vm_region(mach_task_self(), region);
+
+ T_EXPECT_FALSE(stackid == -1, "check that stackid is valid");
+
+ mach_vm_address_t frames[512];
+ uint32_t count =0;
+ bool last_frame_is_threadid;
+ kr = __mach_stack_logging_get_frames_for_stackid(mach_task_self(), stackid, frames, sizeof(frames)/sizeof(frames[0]), &count, &last_frame_is_threadid);
+ T_ASSERT_MACH_SUCCESS(kr, "get frames");
+
+ void *allocate_ptr = allocate;
+ void *allocate_end_ptr = allocate_end;
+#if __has_feature(ptrauth_calls)
+ allocate_ptr = ptrauth_strip(allocate_ptr, ptrauth_key_function_pointer);
+ allocate_end_ptr = ptrauth_strip(allocate_end_ptr, ptrauth_key_function_pointer);
+#endif /* __has_feature(ptrauth_calls) */
+
+ T_LOG("allocate = %p", allocate_ptr);
+ T_LOG("allocate_end = %p", allocate_end_ptr);
+
+ bool found = false;
+ for (uint32_t i = 0; i < count; i++) {
+ T_LOG("frames[%d] = %llx", (int)i, frames[i]);
+ if (frames[i] >= (uintptr_t)allocate_ptr && frames[i] < (uintptr_t)allocate_end_ptr) {
+ T_LOG("found!");
+ found = true;
+ }
+ }
+
+ T_EXPECT_TRUE(found, "found allocate() in the frames");
+
+ vm_deallocate(mach_task_self(), region, 0x1000);
+
+ __mach_stack_logging_stop_reading(mach_task_self());
+
+}
+
+static
+void
+do_test_msl_no_vm_stacks()
+{
+ vm_address_t region = allocate();
+
+ T_ASSERT_NOTNULL((void *)region, "allocated region");
+
+ boolean_t lite_mode = false;
+ kern_return_t kr = __mach_stack_logging_start_reading(mach_task_self(), __mach_stack_logging_shared_memory_address, &lite_mode);
+ if (__mach_stack_logging_shared_memory_address) {
+ T_ASSERT_MACH_SUCCESS(kr, "start_reading return code with initialized __mach_stack_logging_shared_memory_address");
+ T_ASSERT_TRUE(lite_mode, "check lite mode with initialized __mach_stack_logging_shared_memory_address");
+ } else {
+ T_ASSERT_MACH_ERROR_(kr, KERN_FAILURE, "start_reading return code with uninitialized __mach_stack_logging_shared_memory_address");
+ T_ASSERT_FALSE(lite_mode, "check lite mode with uninitialized __mach_stack_logging_shared_memory_address");
+ }
+
+ uint64_t stackid = __mach_stack_logging_stackid_for_vm_region(mach_task_self(), region);
+ T_EXPECT_TRUE(stackid == -1, "check that no stackid is available for VM region");
+
+ __mach_stack_logging_stop_reading(mach_task_self());
+}
+
+T_DECL(msl_lite_vm_stacks, "test that we can read stack logs for VM region in lite mode", T_META_ENVVAR("MallocStackLogging=lite"))
+{
+ do_test_msl_vm_stacks();
+}
+
+T_DECL(msl_lite_vm_stacks_no_env, "like msl_vmlite but we turn on stack logging with a function call ")
+{
+ turn_on_stack_logging(stack_logging_mode_lite);
+ do_test_msl_vm_stacks();
+}
+
+T_DECL(msl_vmlite_vm_stacks, "test that we can read stack logs for VM region in vmlite mode", T_META_ENVVAR("MallocStackLogging=vmlite"))
+{
+ do_test_msl_vm_stacks();
+}
+
+T_DECL(msl_vmlite_no_malloc_stacks, "test that no malloc stacks are logged in vmlite mode", T_META_ENVVAR("MallocStackLogging=vmlite"))
+{
+ extern boolean_t is_stack_logging_lite_enabled(void);
+ T_EXPECT_FALSE(is_stack_logging_lite_enabled(), "is_stack_logging_lite_enabled() = %d", is_stack_logging_lite_enabled());
+}
+
+T_DECL(msl_vmlite_vm_stacks_no_env, "test absence/presence of vm stacks in vmlite mode, controlled with function calls")
+{
+ do_test_msl_no_vm_stacks();
+ turn_on_stack_logging(stack_logging_mode_vmlite);
+ do_test_msl_vm_stacks();
+ turn_off_stack_logging();
+ do_test_msl_no_vm_stacks();
+}
+
+T_DECL(msl_vmlite_stress, "stress test for VM region in lite mode", T_META_ENVVAR("MallocStackLogging=lite"))
+{
+ vm_size_t size = 0xff00000;
+ vm_size_t minsize = 0x1000;
+ vm_address_t region;
+ vm_allocate(mach_task_self(), ®ion, size, VM_FLAGS_ANYWHERE);
+ T_EXPECT_TRUE(region != 0, "allocated region %llx", (long long) region);
+ for (vm_address_t addr = region; addr < region + size; addr += minsize) {
+ vm_size_t index = (addr - region) / minsize;
+ if (index % 2) {
+ //T_LOG("deallocate %llx", (long long)addr);
+ vm_deallocate(mach_task_self(), addr, minsize);
+ }
+ }
+ for (vm_address_t addr = region; addr < region + size; addr += minsize) {
+ vm_size_t index = (addr - region) / minsize;
+ if (!(index % 2)) {
+ //T_LOG("deallocate %llx", (long long)addr);
+ vm_deallocate(mach_task_self(), addr, minsize);
+ }
+ }
+
+ ;
+
+ vm_address_t regions[5000];
+ for (int i = 0; i < sizeof(regions)/sizeof(regions[0]); i++) {
+ vm_allocate(mach_task_self(), ®ions[i], minsize, VM_FLAGS_ANYWHERE);
+ T_QUIET;
+ T_EXPECT_TRUE(regions[i] != 0, "allocation succeeded %llx", (long long) regions[i]);
+ }
+ for (int i = 0; i < sizeof(regions)/sizeof(regions[0]); i++) {
+ vm_deallocate(mach_task_self(), regions[i], minsize);
+ }
+
+ T_END;
+}
+
+T_DECL(msl_test_malloc_memory_event_handler, "Test the memory event handler")
+{
+#if !TARGET_OS_OSX
+ T_SKIP("Skipping for non-OSX platform")
+#endif
+
+ unsigned long event = NOTE_MEMORYSTATUS_PROC_LIMIT_WARN;
+ // Trigger a memory resource exception warning
+ malloc_memory_event_handler(event);
+
+ char *ptrs[1];
+ ptrs[0] = malloc(10);
+
+ boolean_t lite_mode;
+ kern_return_t ret = __mach_stack_logging_start_reading(mach_task_self(), __mach_stack_logging_shared_memory_address, &lite_mode);
+ EXPECT_TRUE(ret == KERN_SUCCESS, "return from __mach_stack_logging_start_reading = %d", ret);
+ EXPECT_TRUE(lite_mode, "return from __mach_stack_logging_start_reading - lite_mode = %d", lite_mode);
+
+ // check to see if malloc stacks are present
+ check_stacks(ptrs, 1, true);
+
+ // enter critical, should turn off stack logging and delete stack table
+ event = NOTE_MEMORYSTATUS_PROC_LIMIT_CRITICAL;
+ malloc_memory_event_handler(event);
+
+ // verify that there are no stacks
+ // First have to clear any cached uniquing table, then check again
+ __mach_stack_logging_stop_reading(mach_task_self());
+ ret = __mach_stack_logging_start_reading(mach_task_self(), __mach_stack_logging_shared_memory_address, &lite_mode);
+ EXPECT_TRUE(ret != KERN_SUCCESS, "return from __mach_stack_logging_start_reading = %d", ret);
+ __mach_stack_logging_stop_reading(mach_task_self());
+
+ // now see if we can turn on malloc stack logging via the MSL commands - this should fail
+ event = MEMORYSTATUS_ENABLE_MSL_MALLOC;
+ malloc_memory_event_handler(event);
+ ret = __mach_stack_logging_start_reading(mach_task_self(), __mach_stack_logging_shared_memory_address, &lite_mode);
+ EXPECT_TRUE(ret != KERN_SUCCESS, "return from __mach_stack_logging_start_reading = %d", ret);
+
+ free(ptrs[0]);
+}
+
+T_DECL(msl_test_enable_disable_msl_malloc_malloc, "Test enabling and disabling msl. malloc:malloc")
+{
+ test_enable_disable_enable_msl(MEMORYSTATUS_ENABLE_MSL_MALLOC, MEMORYSTATUS_ENABLE_MSL_MALLOC, false);
+}
+
+T_DECL(msl_test_enable_disable_msl_vm_vm, "Test enabling and disabling msl. vm:vm")
+{
+ test_enable_disable_enable_msl(MEMORYSTATUS_ENABLE_MSL_VM, MEMORYSTATUS_ENABLE_MSL_VM, true);
+}
+
+T_DECL(msl_test_enable_disable_msl_all, "Test enabling and disabling msl. all:all")
+{
+ test_enable_disable_enable_msl(MEMORYSTATUS_ENABLE_MSL_MALLOC | MEMORYSTATUS_ENABLE_MSL_VM, MEMORYSTATUS_ENABLE_MSL_MALLOC | MEMORYSTATUS_ENABLE_MSL_VM, false);
+}
+
+T_DECL(msl_test_enable_disable_msl_litefull_litefull, "Test enabling and disabling msl. litefull:litefull")
+{
+ test_enable_disable_enable_msl(MEMORYSTATUS_ENABLE_MSL_LITE_FULL, MEMORYSTATUS_ENABLE_MSL_LITE_FULL, false);
+}
+
+T_DECL(msl_test_enable_disable_msl_litefull_malloc, "Test enabling and disabling msl. litefull:malloc")
+{
+ test_enable_disable_enable_msl(MEMORYSTATUS_ENABLE_MSL_LITE_FULL, MEMORYSTATUS_ENABLE_MSL_MALLOC, false);
+}
+
+T_DECL(msl_test_enable_disable_msl_malloc_litefull, "Test enabling and disabling msl. malloc:litefull")
+{
+ test_enable_disable_enable_msl(MEMORYSTATUS_ENABLE_MSL_MALLOC, MEMORYSTATUS_ENABLE_MSL_LITE_FULL, false);
+}
+
+T_DECL(msl_test_enable_disable_msl_litevm_malloc, "Test enabling and disabling msl. litevm:malloc")
+{
+ test_enable_disable_enable_msl(MEMORYSTATUS_ENABLE_MSL_LITE_VM, MEMORYSTATUS_ENABLE_MSL_MALLOC, true);
+}
+
+T_DECL(msl_test_enable_disable_msl_malloc_litevm, "Test enabling and disabling msl. malloc:litevm")
+{
+ test_enable_disable_enable_msl(MEMORYSTATUS_ENABLE_MSL_MALLOC, MEMORYSTATUS_ENABLE_MSL_LITE_VM, false);
+}
+
+T_DECL(msl_test_enable_disable_msl_litevm_litevm, "Test enabling and disabling msl. litevm:litevm")
+{
+ test_enable_disable_enable_msl(MEMORYSTATUS_ENABLE_MSL_LITE_VM, MEMORYSTATUS_ENABLE_MSL_LITE_VM, true);
+}
+
+T_DECL(msl_test_enable_disable_msl_litefull_litevm, "Test enabling and disabling msl. litefull:litevm")
+{
+ test_enable_disable_enable_msl(MEMORYSTATUS_ENABLE_MSL_LITE_FULL, MEMORYSTATUS_ENABLE_MSL_LITE_VM, false);
+}
+
+T_DECL(msl_test_enable_disable_msl_litevm_litefull, "Test enabling and disabling msl. litevm:litefull")
+{
+ test_enable_disable_enable_msl(MEMORYSTATUS_ENABLE_MSL_LITE_VM, MEMORYSTATUS_ENABLE_MSL_LITE_FULL, true);
+}
#else