xref: /llvm-project/compiler-rt/lib/interception/tests/interception_linux_foreign_test.cpp (revision 74b0ac571b5facee3c8038d21ed71d7a29ee1098)
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_internal_defs.h"
20 
21 #if SANITIZER_LINUX
22 
23 extern "C" int isalnum(int d);
24 extern "C" int __interceptor_isalpha(int d);
25 extern "C" int ___interceptor_isalnum(int d);  // the sanitizer interceptor
26 extern "C" int ___interceptor_islower(int d);  // the sanitizer interceptor
27 
28 namespace __interception {
29 extern int isalpha_called;
30 extern int isalnum_called;
31 extern int islower_called;
32 }  // namespace __interception
33 using namespace __interception;
34 
35 // Direct foreign interceptor. This is the "normal" protocol that other
36 // interceptors should follow.
37 extern "C" int isalpha(int d) {
38   // Use non-commutative arithmetic to verify order of calls.
39   isalpha_called = isalpha_called * 10 + 1;
40   return __interceptor_isalpha(d);
41 }
42 
43 // Indirect foreign interceptor. This pattern should only be used to co-exist
44 // with direct foreign interceptors and sanitizer interceptors.
45 extern "C" int __interceptor_isalnum(int d) {
46   isalnum_called = isalnum_called * 10 + 1;
47   return ___interceptor_isalnum(d);
48 }
49 
50 extern "C" int __interceptor_islower(int d) {
51   islower_called = islower_called * 10 + 2;
52   return ___interceptor_islower(d);
53 }
54 
55 extern "C" int islower(int d) {
56   islower_called = islower_called * 10 + 1;
57   return __interceptor_islower(d);
58 }
59 
60 namespace __interception {
61 
62 TEST(ForeignInterception, ForeignOverrideDirect) {
63   isalpha_called = 0;
64   EXPECT_NE(0, isalpha('a'));
65   EXPECT_EQ(13, isalpha_called);
66   isalpha_called = 0;
67   EXPECT_EQ(0, isalpha('_'));
68   EXPECT_EQ(13, isalpha_called);
69 }
70 
71 TEST(ForeignInterception, ForeignOverrideIndirect) {
72   isalnum_called = 0;
73   EXPECT_NE(0, isalnum('a'));
74   EXPECT_EQ(13, isalnum_called);
75   isalnum_called = 0;
76   EXPECT_EQ(0, isalnum('_'));
77   EXPECT_EQ(13, isalnum_called);
78 }
79 
80 TEST(ForeignInterception, ForeignOverrideThree) {
81   islower_called = 0;
82   EXPECT_NE(0, islower('a'));
83   EXPECT_EQ(123, islower_called);
84   islower_called = 0;
85   EXPECT_EQ(0, islower('_'));
86   EXPECT_EQ(123, islower_called);
87 }
88 
89 }  // namespace __interception
90 
91 #endif  // SANITIZER_LINUX
92