Skip to content

Commit

Permalink
[compiler-rt] Work around incompatible Windows definitions of (S)SIZE_T
Browse files Browse the repository at this point in the history
The interceptor types are supposed to match size_t (and the non-Windows
ssize_t) exactly, but on 32-bit Windows `size_t` uses `unsigned int`
whereas `SIZE_T` is `unsigned long`. The current definition results in
`uptr` not matching `uintptr_t` since we otherwise get typedef
redefinition errors. Work around this by using a #define instead of
a typedef when defining SIZE_T.

It would probably be cleaner to stop using these uppercase types, but
that is a rather invasive change and this one is the minimal change to
allow uptr to match uintptr_t on Windows.

To ensure this compiles on Windows, we also remove the interceptor.h
defines of uptr (that do not always match __sanitizer::uptr) and rely
on __sanitizer::uptr instead. The interceptor types most likely predate
those other types so clean up the unnecessary definition while here.

This also reverts commit 18e06e3 and
commit bb27dd8.

Reviewed By: mstorsjo, vitalybuka

Pull Request: #106311
  • Loading branch information
arichardson authored Aug 29, 2024
1 parent dac1f7b commit ec68dc1
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 33 deletions.
25 changes: 14 additions & 11 deletions compiler-rt/lib/interception/interception.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,19 @@

// These typedefs should be used only in the interceptor definitions to replace
// the standard system types (e.g. SSIZE_T instead of ssize_t)
typedef __sanitizer::uptr SIZE_T;
typedef __sanitizer::sptr SSIZE_T;
// On Windows the system headers (basetsd.h) provide a conflicting definition
// of SIZE_T/SSIZE_T that do not match the real size_t/ssize_t for 32-bit
// systems (using long instead of the expected int). Work around the typedef
// redefinition by #defining SIZE_T instead of using a typedef.
// TODO: We should be using __sanitizer::usize (and a new ssize) instead of
// these new macros as long as we ensure they match the real system definitions.
#if SANITIZER_WINDOWS
// Ensure that (S)SIZE_T were already defined as we are about to override them.
# include <basetsd.h>
#endif

#define SIZE_T __sanitizer::usize
#define SSIZE_T __sanitizer::sptr
typedef __sanitizer::sptr PTRDIFF_T;
typedef __sanitizer::s64 INTMAX_T;
typedef __sanitizer::u64 UINTMAX_T;
Expand Down Expand Up @@ -338,16 +349,8 @@ const interpose_substitution substitution_##func_name[] \
#endif

// ISO C++ forbids casting between pointer-to-function and pointer-to-object,
// so we use casting via an integral type __interception::uptr,
// assuming that system is POSIX-compliant. Using other hacks seem
// challenging, as we don't even pass function type to
// INTERCEPT_FUNCTION macro, only its name.
// so we use casts via uintptr_t (the local __sanitizer::uptr equivalent).
namespace __interception {
#if defined(_WIN64)
typedef unsigned long long uptr;
#else
typedef unsigned long uptr;
#endif // _WIN64

#if defined(__ELF__) && !SANITIZER_FUCHSIA
// The use of interceptors makes many sanitizers unusable for static linking.
Expand Down
31 changes: 19 additions & 12 deletions compiler-rt/lib/interception/interception_type_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,28 +12,35 @@
//===----------------------------------------------------------------------===//

#include "interception.h"
#include "sanitizer_common/sanitizer_type_traits.h"

#if SANITIZER_LINUX || SANITIZER_APPLE

#include <sys/types.h>
#if __has_include(<sys/types.h>)
# include <sys/types.h>
#endif
#include <stddef.h>
#include <stdint.h>

COMPILER_CHECK(sizeof(::SIZE_T) == sizeof(size_t));
COMPILER_CHECK(sizeof(::SSIZE_T) == sizeof(ssize_t));
COMPILER_CHECK(sizeof(::PTRDIFF_T) == sizeof(ptrdiff_t));
COMPILER_CHECK((__sanitizer::is_same<__sanitizer::uptr, ::uintptr_t>::value));
COMPILER_CHECK((__sanitizer::is_same<__sanitizer::sptr, ::intptr_t>::value));
COMPILER_CHECK((__sanitizer::is_same<__sanitizer::usize, ::size_t>::value));
COMPILER_CHECK((__sanitizer::is_same<::PTRDIFF_T, ::ptrdiff_t>::value));
COMPILER_CHECK((__sanitizer::is_same<::SIZE_T, ::size_t>::value));
#if !SANITIZER_WINDOWS
// No ssize_t on Windows.
COMPILER_CHECK((__sanitizer::is_same<::SSIZE_T, ::ssize_t>::value));
#endif
// TODO: These are not actually the same type on Linux (long vs long long)
COMPILER_CHECK(sizeof(::INTMAX_T) == sizeof(intmax_t));
COMPILER_CHECK(sizeof(::UINTMAX_T) == sizeof(uintmax_t));

# if SANITIZER_GLIBC || SANITIZER_ANDROID
#if SANITIZER_GLIBC || SANITIZER_ANDROID
COMPILER_CHECK(sizeof(::OFF64_T) == sizeof(off64_t));
# endif
#endif

// The following are the cases when pread (and friends) is used instead of
// pread64. In those cases we need OFF_T to match off_t. We don't care about the
// rest (they depend on _FILE_OFFSET_BITS setting when building an application).
# if SANITIZER_ANDROID || !defined _FILE_OFFSET_BITS || \
_FILE_OFFSET_BITS != 64
#if !SANITIZER_WINDOWS && (SANITIZER_ANDROID || !defined _FILE_OFFSET_BITS || \
_FILE_OFFSET_BITS != 64)
COMPILER_CHECK(sizeof(::OFF_T) == sizeof(off_t));
# endif

#endif
11 changes: 1 addition & 10 deletions compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ namespace __sanitizer {
typedef unsigned long long uptr;
typedef signed long long sptr;
#else
# if (SANITIZER_WORDSIZE == 64) || SANITIZER_APPLE || SANITIZER_WINDOWS
# if (SANITIZER_WORDSIZE == 64) || SANITIZER_APPLE
typedef unsigned long uptr;
typedef signed long sptr;
# else
Expand Down Expand Up @@ -194,16 +194,7 @@ typedef u64 OFF64_T;
#ifdef __SIZE_TYPE__
typedef __SIZE_TYPE__ usize;
#else
// Since we use this for operator new, usize must match the real size_t, but on
// 32-bit Windows the definition of uptr does not actually match uintptr_t or
// size_t because we are working around typedef mismatches for the (S)SIZE_T
// types used in interception.h.
// Until the definition of uptr has been fixed we have to special case Win32.
# if SANITIZER_WINDOWS && SANITIZER_WORDSIZE == 32
typedef unsigned int usize;
# else
typedef uptr usize;
# endif
#endif

typedef u64 tid_t;
Expand Down

0 comments on commit ec68dc1

Please sign in to comment.