Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Sanitizers] Avoid overload ambiguity for interceptors #100986

Merged
merged 1 commit into from
Jul 30, 2024

Conversation

nikic
Copy link
Contributor

@nikic nikic commented Jul 29, 2024

Since glibc 2.40 some functions like openat make use of overloads when built with -D_FORTIFY_SOURCE=2, see:
https://github.com/bminor/glibc/blob/master/io/bits/fcntl2.h

This means that doing something like (uintptr_t) openat or (void *) openat is now ambiguous, breaking the compiler-rt build on new glibc versions.

Fix this by explicitly casting the symbol to the expected function type before casting it to an intptr. The expected type is obtained as decltype(REAL(func)) so we don't have to repeat the signature from INTERCEPTOR in the INTERCEPT_FUNTION macro.

Fixes #100754.

Since glibc 2.40 some functions like openat make use of overloads
when built with `-D_FORTIFY_SOURCE=2`, see:
https://github.com/bminor/glibc/blob/master/io/bits/fcntl2.h

This means that doing something like `(uintptr_t) openat` or
`(void *) openat` is now ambiguous, breaking the compiler-rt
build on new glibc versions.

Fix this by explicitly casting the symbol to the expected
function type before casting it to an intptr. The expected type
is obtained as `decltype(REAL(func))` so we don't have to
repeat the signature from INTERCEPTOR in the INTERCEPT_FUNTION
macro.
@llvmbot
Copy link
Member

llvmbot commented Jul 29, 2024

@llvm/pr-subscribers-compiler-rt-sanitizer

Author: Nikita Popov (nikic)

Changes

Since glibc 2.40 some functions like openat make use of overloads when built with -D_FORTIFY_SOURCE=2, see:
https://github.com/bminor/glibc/blob/master/io/bits/fcntl2.h

This means that doing something like (uintptr_t) openat or (void *) openat is now ambiguous, breaking the compiler-rt build on new glibc versions.

Fix this by explicitly casting the symbol to the expected function type before casting it to an intptr. The expected type is obtained as decltype(REAL(func)) so we don't have to repeat the signature from INTERCEPTOR in the INTERCEPT_FUNTION macro.

Fixes #100754.


Full diff: https://github.com/llvm/llvm-project/pull/100986.diff

1 Files Affected:

  • (modified) compiler-rt/lib/interception/interception_linux.h (+9-7)
diff --git a/compiler-rt/lib/interception/interception_linux.h b/compiler-rt/lib/interception/interception_linux.h
index 433a3d9bd7fa7..2e01ff44578c3 100644
--- a/compiler-rt/lib/interception/interception_linux.h
+++ b/compiler-rt/lib/interception/interception_linux.h
@@ -28,12 +28,14 @@ bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real,
                        uptr func, uptr trampoline);
 }  // namespace __interception
 
-#define INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func) \
-  ::__interception::InterceptFunction(            \
-      #func,                                      \
-      (::__interception::uptr *)&REAL(func),      \
-      (::__interception::uptr)&(func),            \
-      (::__interception::uptr)&TRAMPOLINE(func))
+// Cast func to type of REAL(func) before casting to uptr in case it is an
+// overloaded function, which is the case for some glibc functions when
+// _FORTIFY_SOURCE is used. This disambiguates which overload to use.
+#define INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func)            \
+  ::__interception::InterceptFunction(                       \
+      #func, (::__interception::uptr *)&REAL(func),          \
+      (::__interception::uptr)(decltype(REAL(func)))&(func), \
+      (::__interception::uptr) &TRAMPOLINE(func))
 
 // dlvsym is a GNU extension supported by some other platforms.
 #if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
@@ -41,7 +43,7 @@ bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real,
   ::__interception::InterceptFunction(                        \
       #func, symver,                                          \
       (::__interception::uptr *)&REAL(func),                  \
-      (::__interception::uptr)&(func),                        \
+      (::__interception::uptr)(decltype(REAL(func)))&(func),  \
       (::__interception::uptr)&TRAMPOLINE(func))
 #else
 #define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \

Copy link

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️

You can test this locally with the following command:
git-clang-format --diff 73c72f2c6505d5bc8b47bb0420f6cba5b24270fe 256149db05b803f22e7baadbccb8c0c097c7ee27 --extensions h -- compiler-rt/lib/interception/interception_linux.h
View the diff from clang-format here.
diff --git a/compiler-rt/lib/interception/interception_linux.h b/compiler-rt/lib/interception/interception_linux.h
index 2e01ff4457..0f0724419a 100644
--- a/compiler-rt/lib/interception/interception_linux.h
+++ b/compiler-rt/lib/interception/interception_linux.h
@@ -31,20 +31,19 @@ bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real,
 // Cast func to type of REAL(func) before casting to uptr in case it is an
 // overloaded function, which is the case for some glibc functions when
 // _FORTIFY_SOURCE is used. This disambiguates which overload to use.
-#define INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func)            \
-  ::__interception::InterceptFunction(                       \
-      #func, (::__interception::uptr *)&REAL(func),          \
-      (::__interception::uptr)(decltype(REAL(func)))&(func), \
-      (::__interception::uptr) &TRAMPOLINE(func))
+#    define INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func)            \
+      ::__interception::InterceptFunction(                       \
+          #func, (::__interception::uptr *)&REAL(func),          \
+          (::__interception::uptr)(decltype(REAL(func)))&(func), \
+          (::__interception::uptr) & TRAMPOLINE(func))
 
 // dlvsym is a GNU extension supported by some other platforms.
 #if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
-#define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \
-  ::__interception::InterceptFunction(                        \
-      #func, symver,                                          \
-      (::__interception::uptr *)&REAL(func),                  \
-      (::__interception::uptr)(decltype(REAL(func)))&(func),  \
-      (::__interception::uptr)&TRAMPOLINE(func))
+#      define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \
+        ::__interception::InterceptFunction(                        \
+            #func, symver, (::__interception::uptr *)&REAL(func),   \
+            (::__interception::uptr)(decltype(REAL(func)))&(func),  \
+            (::__interception::uptr) & TRAMPOLINE(func))
 #else
 #define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \
   INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func)

@mgorny
Copy link
Member

mgorny commented Jul 29, 2024

I can confirm that this fixes the build failure on Gentoo.

@cjappl
Copy link
Contributor

cjappl commented Jul 30, 2024

Excellent. Thank you from the rtsan team @nikic!

@nikic nikic merged commit 155b7a1 into llvm:main Jul 30, 2024
8 of 9 checks passed
@nikic nikic deleted the rtsan-openat-fix branch July 30, 2024 07:25
@nikic nikic added this to the LLVM 19.X Release milestone Jul 30, 2024
@nikic
Copy link
Contributor Author

nikic commented Jul 30, 2024

/cherry-pick 155b7a1

llvmbot pushed a commit to llvmbot/llvm-project that referenced this pull request Jul 30, 2024
Since glibc 2.40 some functions like openat make use of overloads when
built with `-D_FORTIFY_SOURCE=2`, see:
https://github.com/bminor/glibc/blob/master/io/bits/fcntl2.h

This means that doing something like `(uintptr_t) openat` or `(void *)
openat` is now ambiguous, breaking the compiler-rt build on new glibc
versions.

Fix this by explicitly casting the symbol to the expected function type
before casting it to an intptr. The expected type is obtained as
`decltype(REAL(func))` so we don't have to repeat the signature from
INTERCEPTOR in the INTERCEPT_FUNTION macro.

Fixes llvm#100754.

(cherry picked from commit 155b7a1)
@llvmbot
Copy link
Member

llvmbot commented Jul 30, 2024

/pull-request #101150

tru pushed a commit to llvmbot/llvm-project that referenced this pull request Aug 1, 2024
Since glibc 2.40 some functions like openat make use of overloads when
built with `-D_FORTIFY_SOURCE=2`, see:
https://github.com/bminor/glibc/blob/master/io/bits/fcntl2.h

This means that doing something like `(uintptr_t) openat` or `(void *)
openat` is now ambiguous, breaking the compiler-rt build on new glibc
versions.

Fix this by explicitly casting the symbol to the expected function type
before casting it to an intptr. The expected type is obtained as
`decltype(REAL(func))` so we don't have to repeat the signature from
INTERCEPTOR in the INTERCEPT_FUNTION macro.

Fixes llvm#100754.

(cherry picked from commit 155b7a1)
banach-space pushed a commit to banach-space/llvm-project that referenced this pull request Aug 7, 2024
Since glibc 2.40 some functions like openat make use of overloads when
built with `-D_FORTIFY_SOURCE=2`, see:
https://github.com/bminor/glibc/blob/master/io/bits/fcntl2.h

This means that doing something like `(uintptr_t) openat` or `(void *)
openat` is now ambiguous, breaking the compiler-rt build on new glibc
versions.

Fix this by explicitly casting the symbol to the expected function type
before casting it to an intptr. The expected type is obtained as
`decltype(REAL(func))` so we don't have to repeat the signature from
INTERCEPTOR in the INTERCEPT_FUNTION macro.

Fixes llvm#100754.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Development

Successfully merging this pull request may close these issues.

[rtsan] Error while building rtsan_interceptors.cpp
5 participants