Skip to content

[compiler-rt] Work around incompatible Windows definitions of (S)SIZE_T #106311

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

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is unrelated, but IMO we should check these static asserts everywhere possible.


#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
Loading