Skip to content

Commit 725376b

Browse files
committed
Implement a simple e2e test for PFP.
1 parent 7fd12b3 commit 725376b

8 files changed

+207
-0
lines changed

compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake

+4
Original file line numberDiff line numberDiff line change
@@ -119,3 +119,7 @@ endif()
119119
if (WIN32)
120120
set(ALL_ORC_SUPPORTED_ARCH ${X86_64})
121121
endif()
122+
123+
if (UNIX)
124+
set(ALL_PFP_SUPPORTED_ARCH ${X86_64} ${ARM64})
125+
endif()

compiler-rt/cmake/config-ix.cmake

+4
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,9 @@ if(APPLE)
686686
list_intersect(ORC_SUPPORTED_ARCH
687687
ALL_ORC_SUPPORTED_ARCH
688688
SANITIZER_COMMON_SUPPORTED_ARCH)
689+
list_intersect(PFP_SUPPORTED_ARCH
690+
ALL_PFP_SUPPORTED_ARCH
691+
SANITIZER_COMMON_SUPPORTED_ARCH)
689692

690693
else()
691694
# Architectures supported by compiler-rt libraries.
@@ -721,6 +724,7 @@ else()
721724
filter_available_targets(GWP_ASAN_SUPPORTED_ARCH ${ALL_GWP_ASAN_SUPPORTED_ARCH})
722725
filter_available_targets(NSAN_SUPPORTED_ARCH ${ALL_NSAN_SUPPORTED_ARCH})
723726
filter_available_targets(ORC_SUPPORTED_ARCH ${ALL_ORC_SUPPORTED_ARCH})
727+
filter_available_targets(PFP_SUPPORTED_ARCH ${ALL_PFP_SUPPORTED_ARCH})
724728
endif()
725729

726730
if (MSVC)

compiler-rt/test/CMakeLists.txt

+3
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS)
106106
# ShadowCallStack does not yet provide a runtime with compiler-rt, the tests
107107
# include their own minimal runtime
108108
add_subdirectory(shadowcallstack)
109+
# PointerFieldProtection does not yet provide a runtime with compiler-rt, the tests
110+
# include their own minimal runtime
111+
add_subdirectory(pfp)
109112
endif()
110113

111114
# Now that we've traversed all the directories and know all the lit testsuites,

compiler-rt/test/pfp/CMakeLists.txt

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
set(PFP_TESTSUITES)
2+
set(PFP_TEST_DEPS
3+
${SANITIZER_COMMON_LIT_TEST_DEPS})
4+
5+
6+
macro(add_pfp_testsuite arch lld thinlto compilerrt libunwind)
7+
set(PFP_TEST_TARGET_ARCH ${arch})
8+
get_test_cc_for_arch(${arch} PFP_TEST_TARGET_CC PFP_TEST_TARGET_CFLAGS)
9+
10+
string(TOUPPER ${arch} CONFIG_NAME)
11+
12+
if (${thinlto})
13+
set(CONFIG_NAME "thinlto-${CONFIG_NAME}")
14+
list(APPEND PFP_TEST_DEPS LTO)
15+
endif()
16+
if (${libunwind})
17+
set(CONFIG_NAME "libunwind-${CONFIG_NAME}")
18+
list(APPEND PFP_TEST_DEPS unwind)
19+
endif()
20+
if (${lld})
21+
set(CONFIG_NAME "lld-${CONFIG_NAME}")
22+
if (TARGET lld)
23+
list(APPEND PFP_TEST_DEPS lld)
24+
endif()
25+
endif()
26+
if (${compilerrt})
27+
set(CONFIG_NAME "compiler-rt-${CONFIG_NAME}")
28+
list(APPEND PFP_TEST_DEPS compiler-rt)
29+
endif()
30+
set(PFP_TEST_USE_THINLTO ${thinlto})
31+
set(PFP_TEST_USE_LLD ${lld})
32+
33+
configure_lit_site_cfg(
34+
${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in
35+
${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg.py)
36+
list(APPEND PFP_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME})
37+
endmacro()
38+
39+
set(PFP_TEST_ARCH ${PFP_SUPPORTED_ARCH})
40+
41+
42+
foreach(arch ${PFP_TEST_ARCH})
43+
if (arch STREQUAL ${X86_64})
44+
add_pfp_testsuite(${arch} False False False False)
45+
endif()
46+
if (arch STREQUAL ${ARM64})
47+
add_pfp_testsuite(${arch} True True True True)
48+
endif()
49+
endforeach()
50+
51+
message(STATUS "PFP tests. " "Arch: ${PFP_TEST_ARCH} Deps: ${PFP_TEST_DEPS}")
52+
add_lit_testsuite(check-pfp "Running the PointerFieldProtection tests"
53+
${PFP_TESTSUITES}
54+
DEPENDS ${PFP_TEST_DEPS})
55+

compiler-rt/test/pfp/lit.cfg.py

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# -*- Python -*-
2+
3+
import os
4+
5+
from lit.llvm import llvm_config
6+
from lit.llvm.subst import ToolSubst, FindTool
7+
8+
# Setup config name.
9+
config.name = "pfp" + config.name_suffix
10+
11+
# Default test suffixes.
12+
config.suffixes = [".c", ".cpp"]
13+
14+
if config.host_os not in ["Linux"]:
15+
config.unsupported = True
16+
17+
# Setup source root.
18+
config.test_source_root = os.path.dirname(__file__)
19+
# Setup default compiler flags used with -fsanitize=memory option.
20+
clang_cflags = [config.target_cflags] + config.debug_info_flags
21+
clang_cxxflags = config.cxx_mode_flags + clang_cflags
22+
clang_pfp_tagged_common_cflags = clang_cflags + [
23+
"-fexperimental-pointer-field-protection=tagged"
24+
]
25+
26+
27+
clang_pfp_cxxflags = config.cxx_mode_flags + clang_pfp_tagged_common_cflags
28+
if config.target_arch == 'aarch64':
29+
clang_pfp_cxxflags = clang_pfp_cxxflags + ["-fuse-ld=lld --rtlib=compiler-rt --unwindlib=libunwind -static-libgcc"]
30+
31+
32+
def build_invocation(compile_flags):
33+
return " " + " ".join([config.clang] + compile_flags) + " "
34+
35+
36+
config.substitutions.append(("%clangxx ", build_invocation(clang_cxxflags)))
37+
config.substitutions.append(("%clangxx_pfp ", build_invocation(clang_pfp_cxxflags)))
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
@LIT_SITE_CFG_IN_HEADER@
2+
3+
# Tool-specific config options.
4+
config.name_suffix = "@PFP_TEST_CONFIG_SUFFIX@"
5+
config.target_cflags = "@PFP_TEST_TARGET_CFLAGS@"
6+
config.target_arch = "@PFP_TEST_TARGET_ARCH@"
7+
config.use_lld = @PFP_TEST_USE_LLD@
8+
config.use_thinlto = @PFP_TEST_USE_THINLTO@
9+
config.libunwind_shared = "@LIBUNWIND_ENABLE_SHARED@"
10+
config.libunwind_install_dir = "@LLVM_BINARY_DIR@/@LIBUNWIND_INSTALL_LIBRARY_DIR@"
11+
12+
# Load common config for all compiler-rt lit tests.
13+
lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured")
14+
15+
# Load tool-specific config that would do the real work.
16+
lit_config.load_config(config, "@CMAKE_CURRENT_SOURCE_DIR@/lit.cfg.py")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// RUN: %clangxx_pfp %s -o %t1
2+
// RUN: %run %t1 2>&1
3+
// RUN: %clangxx %s -o %t2
4+
// RUN: %run %t2 2>&1
5+
6+
#include <iostream>
7+
8+
// Struct1.ptr and Struct2.ptr have different locks.
9+
struct Struct1 {
10+
int *ptr;
11+
Struct1() : num(1), ptr(&num) {}
12+
13+
private:
14+
int num;
15+
};
16+
17+
struct Struct2 {
18+
int *ptr;
19+
Struct2() : num(2), ptr(&num) {}
20+
21+
private:
22+
int num;
23+
};
24+
25+
Struct1 *new_object1() {
26+
Struct1 *ptr = new Struct1;
27+
return ptr;
28+
}
29+
30+
Struct2 *new_object2() {
31+
Struct2 *ptr = new Struct2;
32+
return ptr;
33+
}
34+
35+
int main() {
36+
Struct1 *obj1 = new_object1();
37+
Struct2 *obj2 = new_object2();
38+
std::cout << "Struct2: " << *(obj2->ptr) << "\n";
39+
std::cout << "Struct1: " << *(obj1->ptr) << "\n";
40+
delete obj1;
41+
delete obj2;
42+
return 0;
43+
}
+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// RUN: %clangxx_pfp %s -o %t1
2+
// RUN: %expect_crash %run %t1 2>&1
3+
// RUN: %clangxx %s -o %t2
4+
// RUN: %run %t2 2>&1
5+
6+
#include <iostream>
7+
8+
// Struct1.ptr and Struct2.ptr have different locks.
9+
struct Struct1 {
10+
int *ptr;
11+
Struct1() : num(1), ptr(&num) {}
12+
13+
private:
14+
int num;
15+
};
16+
17+
struct Struct2 {
18+
int *ptr;
19+
Struct2() : num(2), ptr(&num) {}
20+
21+
private:
22+
int num;
23+
};
24+
25+
Struct1 *new_object1() {
26+
Struct1 *ptr = new Struct1;
27+
return ptr;
28+
}
29+
30+
Struct2 *new_object2() {
31+
Struct2 *ptr = new Struct2;
32+
return ptr;
33+
}
34+
35+
int main() {
36+
Struct1 *obj1 = new_object1();
37+
delete obj1;
38+
// obj1's memory will be reused.
39+
Struct2 *obj2 = new_object2();
40+
std::cout << "Struct2: " << *(obj2->ptr) << "\n";
41+
// Uses a wrong lock. The Program should crash when "-fexperimental-pointer-field-protection=tagged".
42+
std::cout << "Struct1: " << *(obj1->ptr) << "\n";
43+
delete obj2;
44+
return 0;
45+
}

0 commit comments

Comments
 (0)