/* * Copyright (c) 2024 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. The rights granted to you under the License * may not be used to create, or enable the creation or redistribution of, * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* * vm_configurator_tests.h * * Virtual memory configurations and a test wrapper * available for use by tests that use vm_configurator. */ #ifndef VM_CONFIGURATOR_TESTS_H #define VM_CONFIGURATOR_TESTS_H #include "vm_configurator.h" /* * Tests * * To add a new configuration for all VM API to be tested with: * 1. Add a function definition `configure_` * that returns a vm_config_t representing the VM state * and address range to be tested. * 2. Add a field named `` to struct vm_tests_t. * 3. Add a call to `RUN_TEST()` in run_vm_tests() below. * * To help debug failing tests: * - Run a test executable with environment variable VERBOSE=1 * to print the checker and VM state frequently. * - Run a test executable with only a single VM configuration * by naming that configuration on the command line. * Example of verbosely running only one read fault test: * env VERBOSE=1 /path/to/configurator_fault -n fault_read permanent_before_allocation */ typedef vm_config_t *(*configure_fn_t)(void); typedef test_result_t (*test_fn_t)( checker_list_t *checker_list, mach_vm_address_t start, mach_vm_size_t size); /* single entry */ static inline vm_config_t * configure_single_entry_1(void) { /* one entry, tested address range is the entire entry */ vm_entry_template_t templates[] = { vm_entry_template(), END_ENTRIES }; return make_vm_config("single entry > entire entry", templates); } static inline vm_config_t * configure_single_entry_2(void) { /* one entry, tested address range includes only the first part of it */ vm_entry_template_t templates[] = { vm_entry_template(), END_ENTRIES }; return make_vm_config("single entry > first pages", templates, 0, -DEFAULT_PARTIAL_ENTRY_SIZE); } static inline vm_config_t * configure_single_entry_3(void) { /* one entry, tested address range includes only the last part of it */ vm_entry_template_t templates[] = { vm_entry_template(), END_ENTRIES }; return make_vm_config("single entry > last pages", templates, DEFAULT_PARTIAL_ENTRY_SIZE, 0); } static inline vm_config_t * configure_single_entry_4(void) { /* one entry, tested address range includes only the middle part of it */ vm_entry_template_t templates[] = { vm_entry_template(), END_ENTRIES }; return make_vm_config("single entry > middle pages", templates, DEFAULT_PARTIAL_ENTRY_SIZE / 2, -(DEFAULT_PARTIAL_ENTRY_SIZE / 2)); } /* multiple entries */ static inline vm_config_t * configure_multiple_entries_1(void) { /* two entries, tested address range includes both */ vm_entry_template_t templates[] = { vm_entry_template(), vm_entry_template(), END_ENTRIES }; return make_vm_config("multiple entries > two entries", templates); } static inline vm_config_t * configure_multiple_entries_2(void) { /* three entries, tested address range includes all of them */ vm_entry_template_t templates[] = { vm_entry_template(), vm_entry_template(), vm_entry_template(), END_ENTRIES }; return make_vm_config("multiple entries > three entries", templates); } static inline vm_config_t * configure_multiple_entries_3(void) { /* many entries, tested address range includes all of them */ vm_entry_template_t templates[] = { vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), vm_entry_template(), END_ENTRIES }; return make_vm_config("multiple entries > many entries", templates); } static inline vm_config_t * configure_multiple_entries_4(void) { /* three entries, tested address range excludes the end of the last one */ vm_entry_template_t templates[] = { vm_entry_template(), vm_entry_template(), vm_entry_template(), END_ENTRIES }; return make_vm_config("multiple entries > three entries, except the last pages", templates, 0, -DEFAULT_PARTIAL_ENTRY_SIZE); } static inline vm_config_t * configure_multiple_entries_5(void) { /* three entries, tested address range excludes the start of the first one */ vm_entry_template_t templates[] = { vm_entry_template(), vm_entry_template(), vm_entry_template(), END_ENTRIES }; return make_vm_config("multiple entries > three entries, except the first pages", templates, DEFAULT_PARTIAL_ENTRY_SIZE, 0); } static inline vm_config_t * configure_multiple_entries_6(void) { /* * three entries, tested address range excludes both * the start of the first one and the end of the last one */ vm_entry_template_t templates[] = { vm_entry_template(), vm_entry_template(), vm_entry_template(), END_ENTRIES }; assert(DEFAULT_PARTIAL_ENTRY_SIZE / 2 > 0); return make_vm_config("multiple entries > three entries, except the first and last pages", templates, DEFAULT_PARTIAL_ENTRY_SIZE / 2, -(DEFAULT_PARTIAL_ENTRY_SIZE / 2)); } /* some holes but not entirely holes */ static inline vm_config_t * configure_some_holes_1(void) { /* test address range begins in a hole and ends in an allocation */ vm_entry_template_t templates[] = { hole_template, vm_entry_template(), END_ENTRIES }; return make_vm_config("some holes > hole then one entry", templates); } static inline vm_config_t * configure_some_holes_2(void) { /* test address range begins in a hole and ends in three allocation */ vm_entry_template_t templates[] = { hole_template, vm_entry_template(), vm_entry_template(), vm_entry_template(), END_ENTRIES }; return make_vm_config("some holes > hole then multiple entries", templates); } static inline vm_config_t * configure_some_holes_3(void) { /* test address range begins in a hole and ends in the middle of an allocation */ vm_entry_template_t templates[] = { hole_template, vm_entry_template(), END_ENTRIES }; return make_vm_config("some holes > hole then partial entry", templates, 0, -DEFAULT_PARTIAL_ENTRY_SIZE); } static inline vm_config_t * configure_some_holes_4(void) { /* * test address range begins in a hole, covers two allocations, * and ends in the middle of a third allocation */ vm_entry_template_t templates[] = { hole_template, vm_entry_template(), vm_entry_template(), vm_entry_template(), END_ENTRIES }; return make_vm_config("some holes > hole then multiple entries then partial entry", templates, 0, -DEFAULT_PARTIAL_ENTRY_SIZE); } static inline vm_config_t * configure_some_holes_5(void) { /* test address range begins at an allocation and ends in a hole */ vm_entry_template_t templates[] = { vm_entry_template(), hole_template, END_ENTRIES }; return make_vm_config("some holes > one entry then hole", templates); } static inline vm_config_t * configure_some_holes_6(void) { /* * test address range begins at an allocation, covers two more allocations, * and ends in a hole */ vm_entry_template_t templates[] = { vm_entry_template(), vm_entry_template(), vm_entry_template(), hole_template, END_ENTRIES }; return make_vm_config("some holes > multiple entries then hole", templates); } static inline vm_config_t * configure_some_holes_7(void) { /* test address range begins in the middle of an allocation and ends in a hole */ vm_entry_template_t templates[] = { vm_entry_template(), hole_template, END_ENTRIES }; return make_vm_config("some holes > partial entry then hole", templates, DEFAULT_PARTIAL_ENTRY_SIZE, 0); } static inline vm_config_t * configure_some_holes_8(void) { /* * test address range begins in the middle of an allocation, covers * two more allocations, and ends in a hole */ vm_entry_template_t templates[] = { vm_entry_template(), vm_entry_template(), vm_entry_template(), hole_template, END_ENTRIES }; return make_vm_config("some holes > partial entry then multiple entries then hole", templates, DEFAULT_PARTIAL_ENTRY_SIZE, 0); } static inline vm_config_t * configure_some_holes_9(void) { /* test address range is an allocation, then a hole, then an allocation */ vm_entry_template_t templates[] = { vm_entry_template(), hole_template, vm_entry_template(), END_ENTRIES }; return make_vm_config("some holes > hole in the middle", templates); } static inline vm_config_t * configure_some_holes_10(void) { /* test address range is allocation-hole-allocation-hole-allocation */ vm_entry_template_t templates[] = { vm_entry_template(), hole_template, vm_entry_template(), hole_template, vm_entry_template(), END_ENTRIES }; return make_vm_config("some holes > two holes, three entries", templates); } static inline vm_config_t * configure_some_holes_11(void) { /* * test address range is * two allocations-hole-two allocations-hole-two allocations */ vm_entry_template_t templates[] = { vm_entry_template(), vm_entry_template(), hole_template, vm_entry_template(), vm_entry_template(), hole_template, vm_entry_template(), vm_entry_template(), END_ENTRIES }; return make_vm_config("some holes > two holes, six entries", templates); } static inline vm_config_t * configure_some_holes_12(void) { /* * test address range is * three allocations-hole-three allocations-hole-three allocations */ vm_entry_template_t templates[] = { vm_entry_template(), vm_entry_template(), vm_entry_template(), hole_template, vm_entry_template(), vm_entry_template(), vm_entry_template(), hole_template, vm_entry_template(), vm_entry_template(), vm_entry_template(), END_ENTRIES }; return make_vm_config("some holes > two holes, nine entries", templates); } /* all holes */ static inline vm_config_t * configure_all_holes_1(void) { /* test address range is unallocated, with allocations on both sides */ vm_entry_template_t templates[] = { vm_entry_template(), hole_template, vm_entry_template(), END_ENTRIES }; return make_vm_config("all holes > hole with entries on both sides", templates, DEFAULT_ENTRY_SIZE, -DEFAULT_ENTRY_SIZE); } static inline vm_config_t * configure_all_holes_2(void) { /* * test address range is unallocated, with an allocation before * and more unallocated space after */ vm_entry_template_t templates[] = { vm_entry_template(), hole_template, END_ENTRIES }; return make_vm_config("all holes > hole with entry before and hole after", templates, DEFAULT_ENTRY_SIZE, -DEFAULT_PARTIAL_ENTRY_SIZE); } static inline vm_config_t * configure_all_holes_3(void) { /* * test address range is unallocated, with more unallocated space before * and an allocation after */ vm_entry_template_t templates[] = { hole_template, vm_entry_template(), END_ENTRIES }; return make_vm_config("all holes > hole with hole before and entry after", templates, DEFAULT_PARTIAL_ENTRY_SIZE, -DEFAULT_ENTRY_SIZE); } static inline vm_config_t * configure_all_holes_4(void) { /* test address range is unallocated, with more unallocated space before and after */ vm_entry_template_t templates[] = { hole_template, END_ENTRIES }; return make_vm_config("all holes > hole with holes on both sides", templates, DEFAULT_PARTIAL_ENTRY_SIZE / 2, -(DEFAULT_PARTIAL_ENTRY_SIZE / 2)); } /* residency and sharing */ static inline vm_config_t * configure_null_entry(void) { vm_entry_template_t templates[] = { vm_entry_template(.share_mode = SM_EMPTY), END_ENTRIES }; return make_vm_config("residency > null entry", templates); } static inline vm_config_t * configure_nonresident_entry(void) { vm_entry_template_t templates[] = { vm_entry_template(.share_mode = SM_PRIVATE), END_ENTRIES }; return make_vm_config("residency > nonresident entry", templates); } static inline vm_config_t * configure_resident_entry(void) { vm_object_template_t object_templates[] = { vm_object_template(.fill_pattern = {Fill, 0}), END_OBJECTS }; vm_entry_template_t templates[] = { vm_entry_template(.share_mode = SM_PRIVATE, .object = &object_templates[0]), END_ENTRIES }; return make_vm_config("residency > resident entry", templates, object_templates); } static inline vm_config_t * configure_shared_entry(void) { /* * Two entries sharing the same object. * The address range covers only the left entry */ vm_object_template_t object_templates[] = { vm_object_template(), END_OBJECTS }; vm_entry_template_t templates[] = { vm_entry_template(.share_mode = SM_SHARED, .object = &object_templates[0]), vm_entry_template(.share_mode = SM_SHARED, .object = &object_templates[0]), END_ENTRIES }; return make_vm_config("sharing > simple shared entry", templates, object_templates, 0, -DEFAULT_ENTRY_SIZE); } static inline vm_config_t * configure_shared_entry_discontiguous(void) { /* * Two entries sharing the same object, * but not the same range inside that object. * The address range covers only the left entry. */ vm_object_template_t object_templates[] = { vm_object_template(), END_OBJECTS }; vm_entry_template_t templates[] = { vm_entry_template(.share_mode = SM_SHARED, .object = &object_templates[0], .offset = 0), vm_entry_template(.share_mode = SM_SHARED, .object = &object_templates[0], .offset = DEFAULT_ENTRY_SIZE), END_ENTRIES }; return make_vm_config("sharing > discontiguous shared entry", templates, object_templates, 0, -DEFAULT_ENTRY_SIZE); } static inline vm_config_t * configure_shared_entry_partial(void) { /* * Two entries sharing the same object, * but only partly overlap inside that object. * The address range covers only the left entry. */ vm_object_template_t object_templates[] = { vm_object_template(), END_OBJECTS }; vm_entry_template_t templates[] = { vm_entry_template(.share_mode = SM_SHARED, .object = &object_templates[0], .offset = 0), vm_entry_template(.share_mode = SM_SHARED, .object = &object_templates[0], .offset = DEFAULT_PARTIAL_ENTRY_SIZE), END_ENTRIES }; return make_vm_config("sharing > partial shared entry", templates, object_templates, 0, -DEFAULT_ENTRY_SIZE); } static inline vm_config_t * configure_shared_entry_pairs(void) { /* * Four entries. The first and last are shared. The middle two are * also shared, independently. * The address range covers all four entries. */ vm_object_template_t object_templates[] = { vm_object_template(.fill_pattern = {Fill, 0x1111111111111111}), vm_object_template(.fill_pattern = {Fill, 0x2222222222222222}), END_OBJECTS }; vm_entry_template_t templates[] = { vm_entry_template(.share_mode = SM_SHARED, .object = &object_templates[0]), vm_entry_template(.share_mode = SM_SHARED, .object = &object_templates[1]), vm_entry_template(.share_mode = SM_SHARED, .object = &object_templates[1]), vm_entry_template(.share_mode = SM_SHARED, .object = &object_templates[0]), END_ENTRIES }; return make_vm_config("sharing > two pairs of shared entries", templates, object_templates); } static inline vm_config_t * configure_shared_entry_x1000(void) { /* * Many entries, all shared. * The address range covers all entries. */ vm_object_template_t object_templates[] = { vm_object_template(.size = PAGE_SIZE), END_OBJECTS }; const unsigned count = 1000; /* 1000 shared entries */ vm_entry_template_t *templates = calloc(sizeof(templates[0]), count + 1); /* ... plus 1 END_ENTRIES entry */ for (unsigned i = 0; i < count; i++) { templates[i] = vm_entry_template(.share_mode = SM_SHARED, .object = &object_templates[0], .size = PAGE_SIZE); } templates[count] = END_ENTRIES; vm_config_t *result = make_vm_config("sharing > 1000 shared entries", templates, object_templates); free(templates); return result; } static inline vm_config_t * configure_cow_entry(void) { /* * two entries that are COW copies of the same underlying object * Operating range includes only the first entry. */ vm_object_template_t object_templates[] = { /* fixme must use a fill pattern to get a non-null object to copy */ vm_object_template(.fill_pattern = {Fill, 0x1234567890abcdef}), END_OBJECTS }; vm_entry_template_t templates[] = { vm_entry_template(.share_mode = SM_COW, .object = &object_templates[0]), vm_entry_template(.share_mode = SM_COW, .object = &object_templates[0]), END_ENTRIES }; return make_vm_config("cow > one COW entry", templates, object_templates, 0, -DEFAULT_ENTRY_SIZE); } static inline vm_config_t * configure_cow_unreferenced(void) { /* * one COW entry but the memory being copied has no other references */ vm_object_template_t object_templates[] = { /* fixme must use a fill pattern to get a non-null object to copy */ vm_object_template(.fill_pattern = {Fill, 0x1234567890abcdef}), END_OBJECTS }; vm_entry_template_t templates[] = { vm_entry_template(.share_mode = SM_COW, .object = &object_templates[0]), END_ENTRIES }; return make_vm_config("cow > COW with no other references", templates, object_templates); } static inline vm_config_t * configure_cow_nocow(void) { /* * one entry that is COW, then one ordinary entry. * Additional out-of-range entry is a second reference to the COW memory. */ vm_object_template_t object_templates[] = { /* fixme must use a fill pattern to get a non-null object to copy */ vm_object_template(.fill_pattern = {Fill, 0x1234567890abcdef}), END_OBJECTS }; vm_entry_template_t templates[] = { vm_entry_template(.share_mode = SM_COW, .object = &object_templates[0]), vm_entry_template(.share_mode = SM_PRIVATE), vm_entry_template(.share_mode = SM_COW, .object = &object_templates[0]), END_ENTRIES }; return make_vm_config("cow > COW then not-COW", templates, object_templates, 0, -DEFAULT_ENTRY_SIZE); } static inline vm_config_t * configure_nocow_cow(void) { /* * one ordinary entry, then one entry that is COW. * Additional out-of-range entry is a second reference to the COW memory. */ vm_object_template_t object_templates[] = { /* fixme must use a fill pattern to get a non-null object to copy */ vm_object_template(.fill_pattern = {Fill, 0x1234567890abcdef}), END_OBJECTS }; vm_entry_template_t templates[] = { vm_entry_template(.share_mode = SM_PRIVATE), vm_entry_template(.share_mode = SM_COW, .object = &object_templates[0]), vm_entry_template(.share_mode = SM_COW, .object = &object_templates[0]), END_ENTRIES }; return make_vm_config("cow > not-COW then COW", templates, object_templates, 0, -DEFAULT_ENTRY_SIZE); } static inline vm_config_t * configure_cow_unreadable(void) { /* * COW entry that is unreadable. * Additional out-of-range entry is a second reference to the COW memory. */ vm_object_template_t object_templates[] = { /* fixme must use a fill pattern to get a non-null object to copy */ vm_object_template(.fill_pattern = {Fill, 0x1234567890abcdef}), END_OBJECTS }; vm_entry_template_t templates[] = { vm_entry_template(.share_mode = SM_COW, .object = &object_templates[0], .protection = VM_PROT_NONE), vm_entry_template(.share_mode = SM_COW, .object = &object_templates[0]), END_ENTRIES }; return make_vm_config("cow > COW but unreadable", templates, object_templates, 0, -DEFAULT_ENTRY_SIZE); } static inline vm_config_t * configure_cow_unwriteable(void) { /* * COW entry that is readable but unwriteable. * Additional out-of-range entry is a second reference to the COW memory. */ vm_object_template_t object_templates[] = { /* fixme must use a fill pattern to get a non-null object to copy */ vm_object_template(.fill_pattern = {Fill, 0x1234567890abcdef}), END_OBJECTS }; vm_entry_template_t templates[] = { vm_entry_template(.share_mode = SM_COW, .object = &object_templates[0], .protection = VM_PROT_READ), vm_entry_template(.share_mode = SM_COW, .object = &object_templates[0]), END_ENTRIES }; return make_vm_config("cow > COW but unwriteable", templates, object_templates, 0, -DEFAULT_ENTRY_SIZE); } static inline vm_config_t * configure_permanent_entry(void) { /* one permanent entry */ vm_object_template_t object_templates[] = { vm_object_template(.fill_pattern = {Fill, 0x1234567890abcdef}), END_OBJECTS }; vm_entry_template_t templates[] = { vm_entry_template(.permanent = true, .object = &object_templates[0]), END_ENTRIES }; return make_vm_config("permanent > one permanent entry", templates, object_templates); } static inline vm_config_t * configure_permanent_before_permanent(void) { /* two permanent entries, both in-range */ vm_object_template_t object_templates[] = { vm_object_template(.fill_pattern = {Fill, 0x1234567890abcdef}), END_OBJECTS }; vm_entry_template_t templates[] = { vm_entry_template(.permanent = true, .object = &object_templates[0]), vm_entry_template(.permanent = true, .share_mode = SM_EMPTY), END_ENTRIES }; return make_vm_config("permanent > two permanent entries", templates, object_templates); } static inline vm_config_t * configure_permanent_before_allocation(void) { /* * permanent entry followed by allocation * The third entry, outside the tested address range, * is an unallocated hole. This tests rdar://144128567 * along with test configure_permanent_before_allocation_2 */ vm_object_template_t object_templates[] = { vm_object_template(.fill_pattern = {Fill, 0x1234567890abcdef}), END_OBJECTS }; vm_entry_template_t templates[] = { vm_entry_template(.permanent = true, .object = &object_templates[0]), vm_entry_template(), hole_template, END_ENTRIES }; return make_vm_config("permanent > permanent entry before allocation, hole outside", templates, object_templates, 0, -DEFAULT_ENTRY_SIZE); } static inline vm_config_t * configure_permanent_before_allocation_2(void) { /* * permanent entry followed by allocation * The third entry, outside the tested address range, * is an allocation to provoke rdar://144128567. * Other than that bug the behavior should be * identical to configure_permanent_before_allocation. */ vm_object_template_t object_templates[] = { vm_object_template(.fill_pattern = {Fill, 0x1234567890abcdef}), END_OBJECTS }; vm_entry_template_t templates[] = { vm_entry_template(.permanent = true, .object = &object_templates[0]), vm_entry_template(), vm_entry_template(), END_ENTRIES }; return make_vm_config("permanent > permanent entry before allocation, allocation outside", templates, object_templates, 0, -DEFAULT_ENTRY_SIZE); } static inline vm_config_t * configure_permanent_before_hole(void) { /* permanent entry followed by a hole */ vm_object_template_t object_templates[] = { vm_object_template(.fill_pattern = {Fill, 0x1234567890abcdef}), END_OBJECTS }; vm_entry_template_t templates[] = { vm_entry_template(.permanent = true, .object = &object_templates[0]), hole_template, END_ENTRIES }; return make_vm_config("permanent > permanent entry before hole", templates, object_templates); } static inline vm_config_t * configure_permanent_after_allocation(void) { /* allocation followed by a permanent entry */ vm_object_template_t object_templates[] = { vm_object_template(.fill_pattern = {Fill, 0x1234567890abcdef}), END_OBJECTS }; vm_entry_template_t templates[] = { vm_entry_template(), vm_entry_template(.permanent = true, .object = &object_templates[0]), END_ENTRIES }; return make_vm_config("permanent > permanent entry after allocation", templates, object_templates); } static inline vm_config_t * configure_permanent_after_hole(void) { /* hole followed by a permanent entry */ vm_object_template_t object_templates[] = { vm_object_template(.fill_pattern = {Fill, 0x1234567890abcdef}), END_OBJECTS }; vm_entry_template_t templates[] = { hole_template, vm_entry_template(.permanent = true, .object = &object_templates[0]), END_ENTRIES }; return make_vm_config("permanent > permanent entry after hole", templates, object_templates); } static inline vm_config_t * configure_protection_single_common(vm_prot_t prot, vm_prot_t max) { vm_entry_template_t templates[] = { vm_entry_template(.protection = prot, .max_protection = max), END_ENTRIES }; TEMP_CSTRING(name, "protection > single entry prot/max %s/%s", name_for_prot(prot), name_for_prot(max)); return make_vm_config(name, templates); } static inline vm_config_t * configure_protection_pairs_common(vm_prot_t prot_left, vm_prot_t prot_right) { vm_prot_t max_prot = VM_PROT_READ | VM_PROT_WRITE; vm_entry_template_t templates[] = { vm_entry_template(.protection = prot_left, .max_protection = max_prot), vm_entry_template(.protection = prot_right, .max_protection = max_prot), END_ENTRIES }; TEMP_CSTRING(name, "protection > two entries prot/max %s/%s and %s/%s", name_for_prot(prot_left), name_for_prot(max_prot), name_for_prot(prot_right), name_for_prot(max_prot)); return make_vm_config(name, templates); } /* single entry with every prot/max combination (fixme no PROT_EXEC) */ /* prot/max ---/--- */ static inline vm_config_t * configure_protection_single_000_000(void) { return configure_protection_single_common(VM_PROT_NONE, VM_PROT_NONE); } /* prot/max r--/--- is disallowed */ /* prot/max -w-/--- is disallowed */ /* prot/max rw-/--- is disallowed */ /* prot/max ---/r-- */ static inline vm_config_t * configure_protection_single_000_r00(void) { return configure_protection_single_common(VM_PROT_NONE, VM_PROT_READ); } /* prot/max r--/r-- */ static inline vm_config_t * configure_protection_single_r00_r00(void) { return configure_protection_single_common(VM_PROT_READ, VM_PROT_READ); } /* prot/max -w-/r-- is disallowed */ /* prot/max rw-/r-- is disallowed */ /* prot/max ---/w-- */ static inline vm_config_t * configure_protection_single_000_0w0(void) { return configure_protection_single_common(VM_PROT_NONE, VM_PROT_WRITE); } /* prot/max r--/-w- is disallowed */ /* prot/max -w-/-w- */ static inline vm_config_t * configure_protection_single_0w0_0w0(void) { return configure_protection_single_common(VM_PROT_WRITE, VM_PROT_WRITE); } /* prot/max rw-/-w- is disallowed */ /* prot/max ---/rw- */ static inline vm_config_t * configure_protection_single_000_rw0(void) { return configure_protection_single_common(VM_PROT_NONE, VM_PROT_READ | VM_PROT_WRITE); } /* prot/max r--/rw- */ static inline vm_config_t * configure_protection_single_r00_rw0(void) { return configure_protection_single_common(VM_PROT_READ, VM_PROT_READ | VM_PROT_WRITE); } /* prot/max -w-/rw- */ static inline vm_config_t * configure_protection_single_0w0_rw0(void) { return configure_protection_single_common(VM_PROT_WRITE, VM_PROT_READ | VM_PROT_WRITE); } /* prot/max rw-/rw- */ static inline vm_config_t * configure_protection_single_rw0_rw0(void) { return configure_protection_single_common(VM_PROT_READ | VM_PROT_WRITE, VM_PROT_READ | VM_PROT_WRITE); } /* two entries with every pair of protections (fixme no PROT_EXEC) */ static inline vm_config_t * configure_protection_pairs_000_000(void) { return configure_protection_pairs_common(VM_PROT_NONE, VM_PROT_NONE); } static inline vm_config_t * configure_protection_pairs_000_r00(void) { return configure_protection_pairs_common(VM_PROT_NONE, VM_PROT_READ); } static inline vm_config_t * configure_protection_pairs_000_0w0(void) { return configure_protection_pairs_common(VM_PROT_NONE, VM_PROT_WRITE); } static inline vm_config_t * configure_protection_pairs_000_rw0(void) { return configure_protection_pairs_common(VM_PROT_NONE, VM_PROT_READ | VM_PROT_WRITE); } static inline vm_config_t * configure_protection_pairs_r00_000(void) { return configure_protection_pairs_common(VM_PROT_READ, VM_PROT_NONE); } static inline vm_config_t * configure_protection_pairs_r00_r00(void) { return configure_protection_pairs_common(VM_PROT_READ, VM_PROT_READ); } static inline vm_config_t * configure_protection_pairs_r00_0w0(void) { return configure_protection_pairs_common(VM_PROT_READ, VM_PROT_WRITE); } static inline vm_config_t * configure_protection_pairs_r00_rw0(void) { return configure_protection_pairs_common(VM_PROT_READ, VM_PROT_READ | VM_PROT_WRITE); } static inline vm_config_t * configure_protection_pairs_0w0_000(void) { return configure_protection_pairs_common(VM_PROT_WRITE, VM_PROT_NONE); } static inline vm_config_t * configure_protection_pairs_0w0_r00(void) { return configure_protection_pairs_common(VM_PROT_WRITE, VM_PROT_READ); } static inline vm_config_t * configure_protection_pairs_0w0_0w0(void) { return configure_protection_pairs_common(VM_PROT_WRITE, VM_PROT_WRITE); } static inline vm_config_t * configure_protection_pairs_0w0_rw0(void) { return configure_protection_pairs_common(VM_PROT_WRITE, VM_PROT_READ | VM_PROT_WRITE); } static inline vm_config_t * configure_protection_pairs_rw0_000(void) { return configure_protection_pairs_common(VM_PROT_READ | VM_PROT_WRITE, VM_PROT_NONE); } static inline vm_config_t * configure_protection_pairs_rw0_r00(void) { return configure_protection_pairs_common(VM_PROT_READ | VM_PROT_WRITE, VM_PROT_READ); } static inline vm_config_t * configure_protection_pairs_rw0_0w0(void) { return configure_protection_pairs_common(VM_PROT_READ | VM_PROT_WRITE, VM_PROT_WRITE); } static inline vm_config_t * configure_protection_pairs_rw0_rw0(void) { return configure_protection_pairs_common(VM_PROT_READ | VM_PROT_WRITE, VM_PROT_READ | VM_PROT_WRITE); } /* submaps */ /* * Common code for tests that are a single submap whose contents are a single entry * but test at different start and end offsets within that entry. */ static inline vm_config_t * configure_single_submap_single_entry_common( const char *testname, mach_vm_size_t start_offset, mach_vm_size_t end_offset) { vm_object_template_t submap_objects[] = { vm_object_template(.fill_pattern = {Fill, 0x1111111111111111}), END_OBJECTS }; vm_entry_template_t submap_entries[] = { vm_entry_template(.object = &submap_objects[0]), END_ENTRIES }; vm_object_template_t object_templates[] = { submap_object_template( .submap.entries = submap_entries, .submap.objects = submap_objects), END_OBJECTS }; vm_entry_template_t entry_templates[] = { submap_entry_template(.object = &object_templates[0]), END_ENTRIES }; return make_vm_config(testname, entry_templates, object_templates, submap_entries, submap_objects, start_offset, end_offset); } static inline vm_config_t * configure_single_submap_single_entry(void) { /* * test range consists of a single submap mapping * which in turn contains a single entry */ return configure_single_submap_single_entry_common( "submap > single entry > entire entry", 0, 0 /* start and end offsets */); } static inline vm_config_t * configure_single_submap_single_entry_first_pages(void) { /* * test range consists of a single submap mapping * which in turn contains a single entry * and the address range to be tested * excludes the end of that entry */ return configure_single_submap_single_entry_common( "submap > single entry > first pages", 0, -DEFAULT_PARTIAL_ENTRY_SIZE /* start and end offsets */); } static inline vm_config_t * configure_single_submap_single_entry_last_pages(void) { /* * test range consists of a single submap mapping * which in turn contains a single entry * and the address range to be tested * excludes the start of that entry */ return configure_single_submap_single_entry_common( "submap > single entry > last pages", DEFAULT_PARTIAL_ENTRY_SIZE, 0 /* start and end offsets */); } static inline vm_config_t * configure_single_submap_single_entry_middle_pages(void) { /* * test range consists of a single submap mapping * which in turn contains a single entry * and the address range to be tested * excludes the start and end of that entry */ return configure_single_submap_single_entry_common( "submap > single entry > middle pages", DEFAULT_PARTIAL_ENTRY_SIZE / 2, -(DEFAULT_PARTIAL_ENTRY_SIZE / 2) /* start and end offsets */); } static inline vm_config_t * configure_single_submap_oversize_entry_common( const char *testname, mach_vm_address_t parent_offset, mach_vm_size_t parent_size) { /* * submap contains a single entry of default size, * parent map's view of the submap excludes some part of that entry */ assert(parent_offset < DEFAULT_ENTRY_SIZE); assert(parent_offset + parent_size <= DEFAULT_ENTRY_SIZE); vm_object_template_t submap_objects[] = { vm_object_template(.fill_pattern = {Fill, 0x1111111111111111}), END_OBJECTS }; vm_entry_template_t submap_entries[] = { vm_entry_template(.object = &submap_objects[0]), END_ENTRIES }; vm_object_template_t object_templates[] = { submap_object_template( .submap.entries = submap_entries, .submap.objects = submap_objects), END_OBJECTS }; vm_entry_template_t entry_templates[] = { submap_entry_template( .object = &object_templates[0], .offset = parent_offset, .size = parent_size), END_ENTRIES }; return make_vm_config(testname, entry_templates, object_templates, submap_entries, submap_objects, 0, 0); } static inline vm_config_t * configure_single_submap_oversize_entry_at_start(void) { /* * submap contains a single entry, * parent map's view of the submap excludes the start of that entry */ return configure_single_submap_oversize_entry_common( "submap > oversize entry > oversize at start", DEFAULT_ENTRY_SIZE / 2 /* parent_offset */, DEFAULT_ENTRY_SIZE / 2 /* parent_size */); } static inline vm_config_t * configure_single_submap_oversize_entry_at_end(void) { /* * submap contains a single entry, * parent map's view of the submap excludes the end of that entry */ return configure_single_submap_oversize_entry_common( "submap > oversize entry > oversize at end", 0 /* parent_offset */, DEFAULT_ENTRY_SIZE / 2 /* parent_size */); } static inline vm_config_t * configure_single_submap_oversize_entry_at_both(void) { /* * submap contains a single entry, * parent map's view of the submap excludes the start and end of that entry */ return configure_single_submap_oversize_entry_common( "submap > oversize entry > oversize at both start and end", DEFAULT_ENTRY_SIZE / 4 /* parent_offset */, DEFAULT_ENTRY_SIZE / 2 /* parent_size */); } /* * Common code for tests of a submap before or after a hole or allocation. */ static inline vm_config_t * configure_submap_beafterfore_entry( const char *testname, vm_entry_template_kind_t first, vm_entry_template_kind_t second, int submap_protection) { vm_object_template_t submap_objects[] = { vm_object_template(.fill_pattern = {Fill, 0x1111111111111111}), END_OBJECTS }; vm_entry_template_t submap_entries[] = { vm_entry_template( .object = &submap_objects[0], .protection = submap_protection, .max_protection = submap_protection), END_ENTRIES }; vm_object_template_t object_templates[] = { submap_object_template( .submap.entries = submap_entries, .submap.objects = submap_objects), END_OBJECTS }; vm_entry_template_t template_options[] = { [Hole] = hole_template, [Allocation] = vm_entry_template(), [Submap] = submap_entry_template(.object = &object_templates[0]) }; /* entries must be Hole or Allocation or Submap */ assert(first == Hole || first == Allocation || first == Submap); assert(second == Hole || second == Allocation || second == Submap); /* exactly one entry must be Submap */ assert((first == Submap && second != Submap) || (first != Submap && second == Submap)); vm_entry_template_t entry_templates[] = { template_options[first], template_options[second], END_ENTRIES }; return make_vm_config(testname, entry_templates, object_templates, submap_entries, submap_objects, 0, 0); } static inline vm_config_t * configure_submap_before_allocation(void) { return configure_submap_beafterfore_entry( "submap > submap before allocation", Submap, Allocation, VM_PROT_READ | VM_PROT_WRITE); } static inline vm_config_t * configure_submap_before_allocation_ro(void) { return configure_submap_beafterfore_entry( "submap > submap before allocation, read-only", Submap, Allocation, VM_PROT_READ); } static inline vm_config_t * configure_submap_after_allocation(void) { return configure_submap_beafterfore_entry( "submap > submap after allocation", Allocation, Submap, VM_PROT_READ | VM_PROT_WRITE); } static inline vm_config_t * configure_submap_after_allocation_ro(void) { return configure_submap_beafterfore_entry( "submap > submap after allocation, read-only", Allocation, Submap, VM_PROT_READ); } static inline vm_config_t * configure_submap_before_hole(void) { return configure_submap_beafterfore_entry( "submap > submap before hole", Submap, Hole, VM_PROT_READ | VM_PROT_WRITE); } static inline vm_config_t * configure_submap_before_hole_ro(void) { return configure_submap_beafterfore_entry( "submap > submap before hole, read-only", Submap, Hole, VM_PROT_READ); } static inline vm_config_t * configure_submap_after_hole(void) { return configure_submap_beafterfore_entry( "submap > submap after hole", Hole, Submap, VM_PROT_READ | VM_PROT_WRITE); } static inline vm_config_t * configure_submap_after_hole_ro(void) { return configure_submap_beafterfore_entry( "submap > submap after hole, read-only", Hole, Submap, VM_PROT_READ); } static inline vm_config_t * configure_submap_allocation_submap_one_entry_common( const char *testname, int submap_protection) { /* * submap has a single entry, but parent map entries are * submap-allocation-submap, as if part of the submap mapping * had been deallocated or unnested */ vm_object_template_t submap_objects[] = { vm_object_template(.fill_pattern = {Fill, 0x1111111111111111}), END_OBJECTS }; vm_entry_template_t submap_entries[] = { vm_entry_template( .object = &submap_objects[0], .size = DEFAULT_ENTRY_SIZE * 3, .protection = submap_protection, .max_protection = submap_protection), END_ENTRIES }; vm_object_template_t object_templates[] = { submap_object_template( .submap.entries = submap_entries, .submap.objects = submap_objects), END_OBJECTS }; vm_entry_template_t entry_templates[] = { submap_entry_template( .object = &object_templates[0], .offset = 0), vm_entry_template(), submap_entry_template( .object = &object_templates[0], .offset = DEFAULT_ENTRY_SIZE * 2), END_ENTRIES }; return make_vm_config(testname, entry_templates, object_templates, submap_entries, submap_objects, 0, 0); } static inline vm_config_t * configure_submap_allocation_submap_one_entry(void) { return configure_submap_allocation_submap_one_entry_common( "submap > submap-allocation-submap, one entry in submap", VM_PROT_READ | VM_PROT_WRITE); } static inline vm_config_t * configure_submap_allocation_submap_one_entry_ro(void) { return configure_submap_allocation_submap_one_entry_common( "submap > submap-allocation-submap, one entry in submap, read-only", VM_PROT_READ); } static inline vm_config_t * configure_submap_allocation_submap_two_entries_common( const char *testname, int submap_protection) { /* * submap has two entries, but parent map entries are * submap-allocation-submap, as if part of the submap mapping * had been deallocated or unnested (not matching the submap * entry boundaries) */ const mach_vm_size_t parent_entry_size = DEFAULT_ENTRY_SIZE; const mach_vm_size_t total_size = parent_entry_size * 3; const mach_vm_size_t submap_entry_size = total_size / 2; assert(parent_entry_size * 3 == submap_entry_size * 2); vm_object_template_t submap_objects[] = { vm_object_template(.fill_pattern = {Fill, 0x1111111111111111}), vm_object_template(.fill_pattern = {Fill, 0x2222222222222222}), END_OBJECTS }; vm_entry_template_t submap_entries[] = { vm_entry_template( .object = &submap_objects[0], .size = submap_entry_size, .protection = submap_protection, .max_protection = submap_protection), vm_entry_template( .object = &submap_objects[1], .size = submap_entry_size, .protection = submap_protection, .max_protection = submap_protection), END_ENTRIES }; vm_object_template_t object_templates[] = { submap_object_template( .submap.entries = submap_entries, .submap.objects = submap_objects), END_OBJECTS }; vm_entry_template_t entry_templates[] = { submap_entry_template( .object = &object_templates[0], .offset = 0, .size = parent_entry_size), vm_entry_template(), submap_entry_template( .object = &object_templates[0], .offset = parent_entry_size * 2, .size = parent_entry_size), END_ENTRIES }; return make_vm_config(testname, entry_templates, object_templates, submap_entries, submap_objects, 0, 0); } static inline vm_config_t * configure_submap_allocation_submap_two_entries(void) { return configure_submap_allocation_submap_two_entries_common( "submap > submap-allocation-submap, two entries in submap", VM_PROT_READ | VM_PROT_WRITE); } static inline vm_config_t * configure_submap_allocation_submap_two_entries_ro(void) { return configure_submap_allocation_submap_two_entries_common( "submap > submap-allocation-submap, two entries in submap, read-only", VM_PROT_READ); } static inline vm_config_t * configure_submap_allocation_submap_three_entries_common( const char *testname, int submap_protection) { /* * submap has three entries, parent map entries are * submap-allocation-submap, as if part of the submap mapping * had been deallocated or unnested on the submap entry boundaries */ vm_object_template_t submap_objects[] = { vm_object_template(.fill_pattern = {Fill, 0x1111111111111111}), vm_object_template(.fill_pattern = {Fill, 0x2222222222222222}), vm_object_template(.fill_pattern = {Fill, 0x3333333333333333}), END_OBJECTS }; vm_entry_template_t submap_entries[] = { vm_entry_template( .object = &submap_objects[0], .protection = submap_protection, .max_protection = submap_protection), vm_entry_template( .object = &submap_objects[1], .protection = submap_protection, .max_protection = submap_protection), vm_entry_template( .object = &submap_objects[2], .protection = submap_protection, .max_protection = submap_protection), END_ENTRIES }; vm_object_template_t object_templates[] = { submap_object_template( .submap.entries = submap_entries, .submap.objects = submap_objects), END_OBJECTS }; vm_entry_template_t entry_templates[] = { submap_entry_template( .object = &object_templates[0], .offset = 0), vm_entry_template(), submap_entry_template( .object = &object_templates[0], .offset = DEFAULT_ENTRY_SIZE * 2), END_ENTRIES }; return make_vm_config(testname, entry_templates, object_templates, submap_entries, submap_objects, 0, 0); } static inline vm_config_t * configure_submap_allocation_submap_three_entries(void) { return configure_submap_allocation_submap_three_entries_common( "submap > submap-allocation-submap, three entries in submap", VM_PROT_READ | VM_PROT_WRITE); } static inline vm_config_t * configure_submap_allocation_submap_three_entries_ro(void) { return configure_submap_allocation_submap_three_entries_common( "submap > submap-allocation-submap, three entries in submap, read-only", VM_PROT_READ); } /* add new tests here (configure_ functions) */ typedef struct { test_fn_t single_entry_1; test_fn_t single_entry_2; test_fn_t single_entry_3; test_fn_t single_entry_4; test_fn_t multiple_entries_1; test_fn_t multiple_entries_2; test_fn_t multiple_entries_3; test_fn_t multiple_entries_4; test_fn_t multiple_entries_5; test_fn_t multiple_entries_6; test_fn_t some_holes_1; test_fn_t some_holes_2; test_fn_t some_holes_3; test_fn_t some_holes_4; test_fn_t some_holes_5; test_fn_t some_holes_6; test_fn_t some_holes_7; test_fn_t some_holes_8; test_fn_t some_holes_9; test_fn_t some_holes_10; test_fn_t some_holes_11; test_fn_t some_holes_12; test_fn_t all_holes_1; test_fn_t all_holes_2; test_fn_t all_holes_3; test_fn_t all_holes_4; test_fn_t null_entry; test_fn_t nonresident_entry; test_fn_t resident_entry; test_fn_t shared_entry; test_fn_t shared_entry_discontiguous; test_fn_t shared_entry_partial; test_fn_t shared_entry_pairs; test_fn_t shared_entry_x1000; test_fn_t cow_entry; test_fn_t cow_unreferenced; test_fn_t cow_nocow; test_fn_t nocow_cow; test_fn_t cow_unreadable; test_fn_t cow_unwriteable; test_fn_t permanent_entry; test_fn_t permanent_before_permanent; test_fn_t permanent_before_allocation; test_fn_t permanent_before_allocation_2; test_fn_t permanent_before_hole; test_fn_t permanent_after_allocation; test_fn_t permanent_after_hole; test_fn_t single_submap_single_entry; test_fn_t single_submap_single_entry_first_pages; test_fn_t single_submap_single_entry_last_pages; test_fn_t single_submap_single_entry_middle_pages; test_fn_t single_submap_oversize_entry_at_start; test_fn_t single_submap_oversize_entry_at_end; test_fn_t single_submap_oversize_entry_at_both; test_fn_t single_submap_single_entry_ro; test_fn_t single_submap_single_entry_first_pages_ro; test_fn_t single_submap_single_entry_last_pages_ro; test_fn_t single_submap_single_entry_middle_pages_ro; test_fn_t single_submap_oversize_entry_at_start_ro; test_fn_t single_submap_oversize_entry_at_end_ro; test_fn_t single_submap_oversize_entry_at_both_ro; test_fn_t submap_before_allocation; test_fn_t submap_after_allocation; test_fn_t submap_before_hole; test_fn_t submap_after_hole; test_fn_t submap_allocation_submap_one_entry; test_fn_t submap_allocation_submap_two_entries; test_fn_t submap_allocation_submap_three_entries; test_fn_t submap_before_allocation_ro; test_fn_t submap_after_allocation_ro; test_fn_t submap_before_hole_ro; test_fn_t submap_after_hole_ro; test_fn_t submap_allocation_submap_one_entry_ro; test_fn_t submap_allocation_submap_two_entries_ro; test_fn_t submap_allocation_submap_three_entries_ro; test_fn_t protection_single_000_000; test_fn_t protection_single_000_r00; test_fn_t protection_single_000_0w0; test_fn_t protection_single_000_rw0; test_fn_t protection_single_r00_r00; test_fn_t protection_single_r00_rw0; test_fn_t protection_single_0w0_0w0; test_fn_t protection_single_0w0_rw0; test_fn_t protection_single_rw0_rw0; test_fn_t protection_pairs_000_000; test_fn_t protection_pairs_000_r00; test_fn_t protection_pairs_000_0w0; test_fn_t protection_pairs_000_rw0; test_fn_t protection_pairs_r00_000; test_fn_t protection_pairs_r00_r00; test_fn_t protection_pairs_r00_0w0; test_fn_t protection_pairs_r00_rw0; test_fn_t protection_pairs_0w0_000; test_fn_t protection_pairs_0w0_r00; test_fn_t protection_pairs_0w0_0w0; test_fn_t protection_pairs_0w0_rw0; test_fn_t protection_pairs_rw0_000; test_fn_t protection_pairs_rw0_r00; test_fn_t protection_pairs_rw0_0w0; test_fn_t protection_pairs_rw0_rw0; /* add new tests here */ } vm_tests_t; /* * test_is_unimplemented is used by test files * as a value in struct vm_tests_t to indicate that * a particular test case is deliberately not implemented. */ extern test_result_t test_is_unimplemented( checker_list_t *checker_list, mach_vm_address_t start, mach_vm_size_t size); /* * Return true if the process is running under Rosetta translation * https://developer.apple.com/documentation/apple-silicon/about-the-rosetta-translation-environment#Determine-Whether-Your-App-Is-Running-as-a-Translated-Binary */ static bool isRosetta() { #if KERNEL return false; #else int out_value = 0; size_t io_size = sizeof(out_value); if (sysctlbyname("sysctl.proc_translated", &out_value, &io_size, NULL, 0) == 0) { assert(io_size >= sizeof(out_value)); return out_value; } return false; #endif } /* * Return true if the task map's page size is less than the VM page size. * (VM_MAP_PAGE_SHIFT(map) < PAGE_SHIFT) * for example, Rosetta Intel on ARM */ static inline bool task_page_size_less_than_vm_page_size(void) { size_t map_page_size = PAGE_SIZE; uint32_t vm_page_size = 0; size_t len = sizeof(vm_page_size); int err = sysctlbyname("vm.pagesize", &vm_page_size, &len, NULL, 0); T_QUIET; T_ASSERT_POSIX_SUCCESS(err, "sysctlbyname('vm.pagesize')"); T_QUIET; T_ASSERT_GE(len, sizeof(vm_page_size), "sysctl result size"); return map_page_size < vm_page_size; } extern void run_one_vm_test( const char *filename, const char *funcname, const char *testname, configure_fn_t configure_fn, test_fn_t test_fn); static inline void run_vm_tests( const char *funcname, const char *filename, vm_tests_t *tests, int argc, char * const *argv) { /* Allow naming a single test to run on the command line. */ const char *test_to_run = NULL; bool ran_a_test = false; if (argc == 1) { test_to_run = argv[0]; T_LOG("RUNNING ONLY ONE TEST: %s %s", funcname, test_to_run); } /* * rdar://138495830 tests fail on Rosetta because of allocation holes * We run tests that don't have holes and skip those that do. */ bool test_holes = true; if (isRosetta()) { T_LOG("SKIPPING TESTS of allocation holes on Rosetta (rdar://138495830)"); test_holes = false; } #define RUN_TEST(testname) \ ({ \ if (test_to_run == NULL || 0 == strcmp(#testname, test_to_run)) { \ ran_a_test = true; \ run_one_vm_test(filename, funcname, #testname, \ configure_##testname, tests->testname); \ } \ }) /* single vm map entry and parts thereof, no holes */ RUN_TEST(single_entry_1); RUN_TEST(single_entry_2); RUN_TEST(single_entry_3); RUN_TEST(single_entry_4); /* multiple map entries and parts thereof, no holes */ RUN_TEST(multiple_entries_1); RUN_TEST(multiple_entries_2); RUN_TEST(multiple_entries_3); RUN_TEST(multiple_entries_4); RUN_TEST(multiple_entries_5); RUN_TEST(multiple_entries_6); /* ranges with holes */ if (test_holes) { RUN_TEST(some_holes_1); RUN_TEST(some_holes_2); RUN_TEST(some_holes_3); RUN_TEST(some_holes_4); RUN_TEST(some_holes_5); RUN_TEST(some_holes_6); RUN_TEST(some_holes_7); RUN_TEST(some_holes_8); RUN_TEST(some_holes_9); RUN_TEST(some_holes_10); RUN_TEST(some_holes_11); RUN_TEST(some_holes_12); } /* ranges that are nothing but holes */ if (test_holes) { RUN_TEST(all_holes_1); RUN_TEST(all_holes_2); RUN_TEST(all_holes_3); RUN_TEST(all_holes_4); } /* residency */ RUN_TEST(null_entry); RUN_TEST(nonresident_entry); // fixme broken in create_vm_state RUN_TEST(resident_entry); /* sharing */ RUN_TEST(shared_entry); RUN_TEST(shared_entry_discontiguous); RUN_TEST(shared_entry_partial); RUN_TEST(shared_entry_pairs); RUN_TEST(shared_entry_x1000); /* cow */ RUN_TEST(cow_entry); RUN_TEST(cow_unreferenced); RUN_TEST(cow_nocow); RUN_TEST(nocow_cow); RUN_TEST(cow_unreadable); RUN_TEST(cow_unwriteable); /* permanent */ RUN_TEST(permanent_entry); RUN_TEST(permanent_before_permanent); if (test_holes) { /* this test does have a required hole, after the other allocations */ RUN_TEST(permanent_before_allocation); } RUN_TEST(permanent_before_allocation_2); if (test_holes) { RUN_TEST(permanent_before_hole); } RUN_TEST(permanent_after_allocation); if (test_holes) { RUN_TEST(permanent_after_hole); } /* submaps */ RUN_TEST(single_submap_single_entry); RUN_TEST(single_submap_single_entry_first_pages); RUN_TEST(single_submap_single_entry_last_pages); RUN_TEST(single_submap_single_entry_middle_pages); RUN_TEST(single_submap_oversize_entry_at_start); RUN_TEST(single_submap_oversize_entry_at_end); RUN_TEST(single_submap_oversize_entry_at_both); RUN_TEST(submap_before_allocation); RUN_TEST(submap_before_allocation_ro); RUN_TEST(submap_after_allocation); RUN_TEST(submap_after_allocation_ro); if (test_holes) { RUN_TEST(submap_before_hole); RUN_TEST(submap_before_hole_ro); RUN_TEST(submap_after_hole); RUN_TEST(submap_after_hole_ro); } RUN_TEST(submap_allocation_submap_one_entry); RUN_TEST(submap_allocation_submap_one_entry_ro); RUN_TEST(submap_allocation_submap_two_entries); RUN_TEST(submap_allocation_submap_two_entries_ro); RUN_TEST(submap_allocation_submap_three_entries); RUN_TEST(submap_allocation_submap_three_entries_ro); /* protection */ RUN_TEST(protection_single_000_000); RUN_TEST(protection_single_000_r00); RUN_TEST(protection_single_r00_r00); RUN_TEST(protection_single_000_0w0); RUN_TEST(protection_single_0w0_0w0); RUN_TEST(protection_single_000_rw0); RUN_TEST(protection_single_r00_rw0); RUN_TEST(protection_single_0w0_rw0); RUN_TEST(protection_single_rw0_rw0); RUN_TEST(protection_pairs_000_000); RUN_TEST(protection_pairs_000_r00); RUN_TEST(protection_pairs_000_0w0); RUN_TEST(protection_pairs_000_rw0); RUN_TEST(protection_pairs_r00_000); RUN_TEST(protection_pairs_r00_r00); RUN_TEST(protection_pairs_r00_0w0); RUN_TEST(protection_pairs_r00_rw0); RUN_TEST(protection_pairs_0w0_000); RUN_TEST(protection_pairs_0w0_r00); RUN_TEST(protection_pairs_0w0_0w0); RUN_TEST(protection_pairs_0w0_rw0); RUN_TEST(protection_pairs_rw0_000); RUN_TEST(protection_pairs_rw0_r00); RUN_TEST(protection_pairs_rw0_0w0); RUN_TEST(protection_pairs_rw0_rw0); /* add new tests here */ #undef RUN_TEST if (test_to_run != NULL && !ran_a_test) { T_FAIL("no test named '%s'", test_to_run); } } #endif /* VM_CONFIGURATOR_TESTS_H */