Skip to content

Commit d04aff4

Browse files
qinkunbaopcc
authored andcommitted
Implement a simple e2e test for PFP.
Pull Request: llvm#151655
1 parent 9753ce0 commit d04aff4

File tree

8 files changed

+186
-0
lines changed

8 files changed

+186
-0
lines changed

compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,3 +123,7 @@ endif()
123123
if (WIN32)
124124
set(ALL_ORC_SUPPORTED_ARCH ${X86_64})
125125
endif()
126+
127+
if (OS_NAME MATCHES "Linux")
128+
set(ALL_PFP_SUPPORTED_ARCH ${X86_64} ${ARM64})
129+
endif()

compiler-rt/cmake/config-ix.cmake

Lines changed: 4 additions & 0 deletions
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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ 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+
add_subdirectory(pfp)
109110
endif()
110111

111112
# Now that we've traversed all the directories and know all the lit testsuites,
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
set(PFP_TESTSUITES)
2+
set(PFP_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS} unwind compiler-rt)
3+
if(COMPILER_RT_HAS_LLD AND TARGET lld)
4+
list(APPEND PFP_TEST_DEPS lld)
5+
endif()
6+
7+
macro(add_pfp_testsuite arch thinlto)
8+
set(PFP_TEST_TARGET_ARCH ${arch})
9+
get_test_cc_for_arch(${arch} PFP_TEST_TARGET_CC PFP_TEST_TARGET_CFLAGS)
10+
11+
string(TOUPPER ${arch} CONFIG_NAME)
12+
13+
if (${thinlto})
14+
set(PFP_TEST_USE_THINLTO ${thinlto})
15+
set(CONFIG_NAME "thinlto-${CONFIG_NAME}")
16+
list(APPEND PFP_TEST_DEPS LTO)
17+
endif()
18+
set(PFP_TEST_USE_THINLTO ${thinlto})
19+
20+
configure_lit_site_cfg(
21+
${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in
22+
${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg.py)
23+
list(APPEND PFP_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME})
24+
endmacro()
25+
26+
set(PFP_TEST_ARCH ${PFP_SUPPORTED_ARCH})
27+
28+
foreach(arch ${PFP_TEST_ARCH})
29+
add_pfp_testsuite(${arch} False)
30+
add_pfp_testsuite(${arch} True)
31+
endforeach()
32+
33+
add_lit_testsuite(check-pfp "Running the PointerFieldProtection tests"
34+
${PFP_TESTSUITES}
35+
DEPENDS ${PFP_TEST_DEPS})
36+

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

Lines changed: 37 additions & 0 deletions
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+
# Setup source root.
15+
config.test_source_root = os.path.dirname(__file__)
16+
# Setup default compiler flags used with -fsanitize=memory option.
17+
clang_cflags = [config.target_cflags] + config.debug_info_flags
18+
clang_cxxflags = config.cxx_mode_flags + clang_cflags
19+
clang_pfp_tagged_common_cflags = clang_cflags + [
20+
"-fexperimental-pointer-field-protection=tagged"
21+
]
22+
23+
24+
clang_pfp_cxxflags = config.cxx_mode_flags + clang_pfp_tagged_common_cflags
25+
clang_pfp_cxxflags = clang_pfp_cxxflags + ["-fuse-ld=lld --rtlib=compiler-rt --unwindlib=libunwind -static-libgcc"]
26+
27+
28+
def build_invocation(compile_flags, with_lto=False):
29+
lto_flags = []
30+
if with_lto and config.lto_supported:
31+
lto_flags += config.lto_flags
32+
33+
return " " + " ".join([config.clang] + lto_flags + compile_flags) + " "
34+
35+
36+
config.substitutions.append(("%clangxx ", build_invocation(clang_cxxflags)))
37+
config.substitutions.append(("%clangxx_pfp ", build_invocation(clang_pfp_cxxflags, config.use_thinlto)))
Lines changed: 16 additions & 0 deletions
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 = True
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")
Lines changed: 43 additions & 0 deletions
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+
}
Lines changed: 45 additions & 0 deletions
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)