Skip to content

Commit

Permalink
Roll forward poisoned pointer API and fix portability issues.
Browse files Browse the repository at this point in the history
Also, return the middle of the poisoned block.

PiperOrigin-RevId: 651119057
Change-Id: Iae0fc3dcb40e32cd449f469d9b8d62c37f3773f4
  • Loading branch information
ezbr authored and copybara-github committed Jul 10, 2024
1 parent bb50cad commit 5b6285e
Show file tree
Hide file tree
Showing 6 changed files with 249 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CMake/AbseilDll.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ set(ABSL_INTERNAL_DLL_FILES
"base/internal/low_level_scheduling.h"
"base/internal/nullability_impl.h"
"base/internal/per_thread_tls.h"
"base/internal/poison.cc"
"base/internal/poison.h"
"base/prefetch.h"
"base/internal/pretty_function.h"
"base/internal/raw_logging.cc"
Expand Down
35 changes: 35 additions & 0 deletions absl/base/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -866,6 +866,41 @@ cc_test(
],
)

cc_library(
name = "poison",
srcs = [
"internal/poison.cc",
],
hdrs = ["internal/poison.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = [
"//absl:__subpackages__",
],
deps = [
":config",
":core_headers",
":malloc_internal",
],
)

cc_test(
name = "poison_test",
size = "small",
timeout = "short",
srcs = [
"internal/poison_test.cc",
],
copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":config",
":poison",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
],
)

cc_test(
name = "unique_small_name_test",
size = "small",
Expand Down
30 changes: 30 additions & 0 deletions absl/base/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -739,3 +739,33 @@ absl_cc_test(
absl::optional
GTest::gtest_main
)

absl_cc_library(
NAME
poison
SRCS
"internal/poison.cc"
HDRS
"internal/poison.h"
COPTS
${ABSL_DEFAULT_COPTS}
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
DEPS
absl::config
absl::core_headers
absl::malloc_internal
)

absl_cc_test(
NAME
poison_test
SRCS
"internal/poison_test.cc"
COPTS
${ABSL_TEST_COPTS}
DEPS
absl::config
absl::poison
GTest::gtest_main
)
82 changes: 82 additions & 0 deletions absl/base/internal/poison.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// Copyright 2024 The Abseil Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "absl/base/internal/poison.h"

#include <cstdlib>

#include "absl/base/config.h"
#include "absl/base/internal/direct_mmap.h"

#ifndef _WIN32
#include <unistd.h>
#endif

#if defined(ABSL_HAVE_ADDRESS_SANITIZER)
#include <sanitizer/asan_interface.h>
#elif defined(ABSL_HAVE_MEMORY_SANITIZER)
#include <sanitizer/msan_interface.h>
#elif defined(ABSL_HAVE_MMAP)
#include <sys/mman.h>
#elif defined(_WIN32)
#include <windows.h>
#endif

namespace absl {
ABSL_NAMESPACE_BEGIN
namespace base_internal {

namespace {

size_t GetPageSize() {
#ifdef _WIN32
SYSTEM_INFO system_info;
GetSystemInfo(&system_info);
return system_info.dwPageSize;
#elif defined(__wasm__) || defined(__asmjs__) || defined(__hexagon__)
return getpagesize();
#else
return static_cast<size_t>(sysconf(_SC_PAGESIZE));
#endif
}

} // namespace

void* InitializePoisonedPointerInternal() {
const size_t block_size = GetPageSize();
#if defined(ABSL_HAVE_ADDRESS_SANITIZER)
void* data = malloc(block_size);
ASAN_POISON_MEMORY_REGION(data, block_size);
#elif defined(ABSL_HAVE_MEMORY_SANITIZER)
void* data = malloc(block_size);
__msan_poison(data, block_size);
#elif defined(ABSL_HAVE_MMAP)
void* data = DirectMmap(nullptr, block_size, PROT_NONE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (data == MAP_FAILED) return GetBadPointerInternal();
#elif defined(_WIN32)
void* data = VirtualAlloc(nullptr, block_size, MEM_RESERVE | MEM_COMMIT,
PAGE_NOACCESS);
if (data == nullptr) return GetBadPointerInternal();
#else
return GetBadPointerInternal();
#endif
// Return the middle of the block so that dereferences before and after the
// pointer will both crash.
return static_cast<char*>(data) + block_size / 2;
}

} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl
59 changes: 59 additions & 0 deletions absl/base/internal/poison.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright 2024 The Abseil Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef ABSL_BASE_INTERNAL_POISON_H_
#define ABSL_BASE_INTERNAL_POISON_H_

#include <cstdint>

#include "absl/base/config.h"

namespace absl {
ABSL_NAMESPACE_BEGIN
namespace base_internal {

inline void* GetBadPointerInternal() {
// A likely bad pointer. Pointers are required to have high bits that are all
// zero or all one for certain 64-bit CPUs. This pointer value will hopefully
// cause a crash on dereference and also be clearly recognizable as invalid.
constexpr uint64_t kBadPtr = 0xBAD0BAD0BAD0BAD0;
auto ret = reinterpret_cast<void*>(static_cast<uintptr_t>(kBadPtr));
#ifndef _MSC_VER // MSVC doesn't support inline asm with `volatile`.
// Try to prevent the compiler from optimizing out the undefined behavior.
asm volatile("" : : "r"(ret) :); // NOLINT
#endif
return ret;
}

void* InitializePoisonedPointerInternal();

inline void* get_poisoned_pointer() {
#if defined(NDEBUG) && !defined(ABSL_HAVE_ADDRESS_SANITIZER) && \
!defined(ABSL_HAVE_MEMORY_SANITIZER)
// In optimized non-sanitized builds, avoid the function-local static because
// of the codegen and runtime cost.
return GetBadPointerInternal();
#else
// Non-optimized builds may use more robust implementation. Note that we can't
// use a static global because Chromium doesn't allow non-constinit globals.
static void* ptr = InitializePoisonedPointerInternal();
return ptr;
#endif
}

} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_BASE_INTERNAL_POISON_H_
41 changes: 41 additions & 0 deletions absl/base/internal/poison_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright 2024 The Abseil Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "absl/base/internal/poison.h"

#include <iostream>

#include "gtest/gtest.h"
#include "absl/base/config.h"

namespace absl {
ABSL_NAMESPACE_BEGIN
namespace base_internal {
namespace {

TEST(PoisonTest, CrashesOnDereference) {
#ifdef __ANDROID__
GTEST_SKIP() << "On Android, poisoned pointer dereference times out instead "
"of crashing.";
#endif
int* poisoned_ptr = static_cast<int*>(get_poisoned_pointer());
EXPECT_DEATH_IF_SUPPORTED(std::cout << *poisoned_ptr, "");
EXPECT_DEATH_IF_SUPPORTED(std::cout << *(poisoned_ptr - 10), "");
EXPECT_DEATH_IF_SUPPORTED(std::cout << *(poisoned_ptr + 10), "");
}

} // namespace
} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl

0 comments on commit 5b6285e

Please sign in to comment.