xref: /llvm-project/compiler-rt/lib/interception/tests/interception_linux_foreign_test.cpp (revision 37445e96d867f4266993085e821fbd4c4d8fa401)
1 //===-- interception_linux_foreign_test.cpp -------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file is a part of ThreadSanitizer/AddressSanitizer runtime.
10 //
11 // Tests that foreign interceptors work.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 // Do not declare functions in ctype.h.
16 #define __NO_CTYPE
17 
18 #include "gtest/gtest.h"
19 #include "sanitizer_common/sanitizer_asm.h"
20 #include "sanitizer_common/sanitizer_internal_defs.h"
21 
22 #if SANITIZER_LINUX
23 
24 extern "C" int isalnum(int d);
25 extern "C" int __interceptor_isalpha(int d);
26 extern "C" int ___interceptor_isalnum(int d);  // the sanitizer interceptor
27 extern "C" int ___interceptor_islower(int d);  // the sanitizer interceptor
28 
29 namespace __interception {
30 extern int isalpha_called;
31 extern int isalnum_called;
32 extern int islower_called;
33 }  // namespace __interception
34 using namespace __interception;
35 
36 // Direct foreign interceptor. This is the "normal" protocol that other
37 // interceptors should follow.
isalpha(int d)38 extern "C" int isalpha(int d) {
39   // Use non-commutative arithmetic to verify order of calls.
40   isalpha_called = isalpha_called * 10 + 1;
41   return __interceptor_isalpha(d);
42 }
43 
44 #if ASM_INTERCEPTOR_TRAMPOLINE_SUPPORT
45 // Indirect foreign interceptor. This pattern should only be used to co-exist
46 // with direct foreign interceptors and sanitizer interceptors.
__interceptor_isalnum(int d)47 extern "C" int __interceptor_isalnum(int d) {
48   isalnum_called = isalnum_called * 10 + 1;
49   return ___interceptor_isalnum(d);
50 }
51 
__interceptor_islower(int d)52 extern "C" int __interceptor_islower(int d) {
53   islower_called = islower_called * 10 + 2;
54   return ___interceptor_islower(d);
55 }
56 
islower(int d)57 extern "C" int islower(int d) {
58   islower_called = islower_called * 10 + 1;
59   return __interceptor_islower(d);
60 }
61 #endif  // ASM_INTERCEPTOR_TRAMPOLINE_SUPPORT
62 
63 namespace __interception {
64 
TEST(ForeignInterception,ForeignOverrideDirect)65 TEST(ForeignInterception, ForeignOverrideDirect) {
66   isalpha_called = 0;
67   EXPECT_NE(0, isalpha('a'));
68   EXPECT_EQ(13, isalpha_called);
69   isalpha_called = 0;
70   EXPECT_EQ(0, isalpha('_'));
71   EXPECT_EQ(13, isalpha_called);
72 }
73 
74 #if ASM_INTERCEPTOR_TRAMPOLINE_SUPPORT
TEST(ForeignInterception,ForeignOverrideIndirect)75 TEST(ForeignInterception, ForeignOverrideIndirect) {
76   isalnum_called = 0;
77   EXPECT_NE(0, isalnum('a'));
78   EXPECT_EQ(13, isalnum_called);
79   isalnum_called = 0;
80   EXPECT_EQ(0, isalnum('_'));
81   EXPECT_EQ(13, isalnum_called);
82 }
83 
TEST(ForeignInterception,ForeignOverrideThree)84 TEST(ForeignInterception, ForeignOverrideThree) {
85   islower_called = 0;
86   EXPECT_NE(0, islower('a'));
87   EXPECT_EQ(123, islower_called);
88   islower_called = 0;
89   EXPECT_EQ(0, islower('_'));
90   EXPECT_EQ(123, islower_called);
91 }
92 #endif  // ASM_INTERCEPTOR_TRAMPOLINE_SUPPORT
93 
94 }  // namespace __interception
95 
96 #endif  // SANITIZER_LINUX
97