Skip to content

Commit 5b6285e

Browse files
ezbrcopybara-github
authored andcommitted
Roll forward poisoned pointer API and fix portability issues.
Also, return the middle of the poisoned block. PiperOrigin-RevId: 651119057 Change-Id: Iae0fc3dcb40e32cd449f469d9b8d62c37f3773f4
1 parent bb50cad commit 5b6285e

File tree

6 files changed

+249
-0
lines changed

6 files changed

+249
-0
lines changed

CMake/AbseilDll.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ set(ABSL_INTERNAL_DLL_FILES
2828
"base/internal/low_level_scheduling.h"
2929
"base/internal/nullability_impl.h"
3030
"base/internal/per_thread_tls.h"
31+
"base/internal/poison.cc"
32+
"base/internal/poison.h"
3133
"base/prefetch.h"
3234
"base/internal/pretty_function.h"
3335
"base/internal/raw_logging.cc"

absl/base/BUILD.bazel

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -866,6 +866,41 @@ cc_test(
866866
],
867867
)
868868

869+
cc_library(
870+
name = "poison",
871+
srcs = [
872+
"internal/poison.cc",
873+
],
874+
hdrs = ["internal/poison.h"],
875+
copts = ABSL_DEFAULT_COPTS,
876+
linkopts = ABSL_DEFAULT_LINKOPTS,
877+
visibility = [
878+
"//absl:__subpackages__",
879+
],
880+
deps = [
881+
":config",
882+
":core_headers",
883+
":malloc_internal",
884+
],
885+
)
886+
887+
cc_test(
888+
name = "poison_test",
889+
size = "small",
890+
timeout = "short",
891+
srcs = [
892+
"internal/poison_test.cc",
893+
],
894+
copts = ABSL_TEST_COPTS,
895+
linkopts = ABSL_DEFAULT_LINKOPTS,
896+
deps = [
897+
":config",
898+
":poison",
899+
"@com_google_googletest//:gtest",
900+
"@com_google_googletest//:gtest_main",
901+
],
902+
)
903+
869904
cc_test(
870905
name = "unique_small_name_test",
871906
size = "small",

absl/base/CMakeLists.txt

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -739,3 +739,33 @@ absl_cc_test(
739739
absl::optional
740740
GTest::gtest_main
741741
)
742+
743+
absl_cc_library(
744+
NAME
745+
poison
746+
SRCS
747+
"internal/poison.cc"
748+
HDRS
749+
"internal/poison.h"
750+
COPTS
751+
${ABSL_DEFAULT_COPTS}
752+
LINKOPTS
753+
${ABSL_DEFAULT_LINKOPTS}
754+
DEPS
755+
absl::config
756+
absl::core_headers
757+
absl::malloc_internal
758+
)
759+
760+
absl_cc_test(
761+
NAME
762+
poison_test
763+
SRCS
764+
"internal/poison_test.cc"
765+
COPTS
766+
${ABSL_TEST_COPTS}
767+
DEPS
768+
absl::config
769+
absl::poison
770+
GTest::gtest_main
771+
)

absl/base/internal/poison.cc

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// Copyright 2024 The Abseil Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include "absl/base/internal/poison.h"
16+
17+
#include <cstdlib>
18+
19+
#include "absl/base/config.h"
20+
#include "absl/base/internal/direct_mmap.h"
21+
22+
#ifndef _WIN32
23+
#include <unistd.h>
24+
#endif
25+
26+
#if defined(ABSL_HAVE_ADDRESS_SANITIZER)
27+
#include <sanitizer/asan_interface.h>
28+
#elif defined(ABSL_HAVE_MEMORY_SANITIZER)
29+
#include <sanitizer/msan_interface.h>
30+
#elif defined(ABSL_HAVE_MMAP)
31+
#include <sys/mman.h>
32+
#elif defined(_WIN32)
33+
#include <windows.h>
34+
#endif
35+
36+
namespace absl {
37+
ABSL_NAMESPACE_BEGIN
38+
namespace base_internal {
39+
40+
namespace {
41+
42+
size_t GetPageSize() {
43+
#ifdef _WIN32
44+
SYSTEM_INFO system_info;
45+
GetSystemInfo(&system_info);
46+
return system_info.dwPageSize;
47+
#elif defined(__wasm__) || defined(__asmjs__) || defined(__hexagon__)
48+
return getpagesize();
49+
#else
50+
return static_cast<size_t>(sysconf(_SC_PAGESIZE));
51+
#endif
52+
}
53+
54+
} // namespace
55+
56+
void* InitializePoisonedPointerInternal() {
57+
const size_t block_size = GetPageSize();
58+
#if defined(ABSL_HAVE_ADDRESS_SANITIZER)
59+
void* data = malloc(block_size);
60+
ASAN_POISON_MEMORY_REGION(data, block_size);
61+
#elif defined(ABSL_HAVE_MEMORY_SANITIZER)
62+
void* data = malloc(block_size);
63+
__msan_poison(data, block_size);
64+
#elif defined(ABSL_HAVE_MMAP)
65+
void* data = DirectMmap(nullptr, block_size, PROT_NONE,
66+
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
67+
if (data == MAP_FAILED) return GetBadPointerInternal();
68+
#elif defined(_WIN32)
69+
void* data = VirtualAlloc(nullptr, block_size, MEM_RESERVE | MEM_COMMIT,
70+
PAGE_NOACCESS);
71+
if (data == nullptr) return GetBadPointerInternal();
72+
#else
73+
return GetBadPointerInternal();
74+
#endif
75+
// Return the middle of the block so that dereferences before and after the
76+
// pointer will both crash.
77+
return static_cast<char*>(data) + block_size / 2;
78+
}
79+
80+
} // namespace base_internal
81+
ABSL_NAMESPACE_END
82+
} // namespace absl

absl/base/internal/poison.h

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Copyright 2024 The Abseil Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#ifndef ABSL_BASE_INTERNAL_POISON_H_
16+
#define ABSL_BASE_INTERNAL_POISON_H_
17+
18+
#include <cstdint>
19+
20+
#include "absl/base/config.h"
21+
22+
namespace absl {
23+
ABSL_NAMESPACE_BEGIN
24+
namespace base_internal {
25+
26+
inline void* GetBadPointerInternal() {
27+
// A likely bad pointer. Pointers are required to have high bits that are all
28+
// zero or all one for certain 64-bit CPUs. This pointer value will hopefully
29+
// cause a crash on dereference and also be clearly recognizable as invalid.
30+
constexpr uint64_t kBadPtr = 0xBAD0BAD0BAD0BAD0;
31+
auto ret = reinterpret_cast<void*>(static_cast<uintptr_t>(kBadPtr));
32+
#ifndef _MSC_VER // MSVC doesn't support inline asm with `volatile`.
33+
// Try to prevent the compiler from optimizing out the undefined behavior.
34+
asm volatile("" : : "r"(ret) :); // NOLINT
35+
#endif
36+
return ret;
37+
}
38+
39+
void* InitializePoisonedPointerInternal();
40+
41+
inline void* get_poisoned_pointer() {
42+
#if defined(NDEBUG) && !defined(ABSL_HAVE_ADDRESS_SANITIZER) && \
43+
!defined(ABSL_HAVE_MEMORY_SANITIZER)
44+
// In optimized non-sanitized builds, avoid the function-local static because
45+
// of the codegen and runtime cost.
46+
return GetBadPointerInternal();
47+
#else
48+
// Non-optimized builds may use more robust implementation. Note that we can't
49+
// use a static global because Chromium doesn't allow non-constinit globals.
50+
static void* ptr = InitializePoisonedPointerInternal();
51+
return ptr;
52+
#endif
53+
}
54+
55+
} // namespace base_internal
56+
ABSL_NAMESPACE_END
57+
} // namespace absl
58+
59+
#endif // ABSL_BASE_INTERNAL_POISON_H_

absl/base/internal/poison_test.cc

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright 2024 The Abseil Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include "absl/base/internal/poison.h"
16+
17+
#include <iostream>
18+
19+
#include "gtest/gtest.h"
20+
#include "absl/base/config.h"
21+
22+
namespace absl {
23+
ABSL_NAMESPACE_BEGIN
24+
namespace base_internal {
25+
namespace {
26+
27+
TEST(PoisonTest, CrashesOnDereference) {
28+
#ifdef __ANDROID__
29+
GTEST_SKIP() << "On Android, poisoned pointer dereference times out instead "
30+
"of crashing.";
31+
#endif
32+
int* poisoned_ptr = static_cast<int*>(get_poisoned_pointer());
33+
EXPECT_DEATH_IF_SUPPORTED(std::cout << *poisoned_ptr, "");
34+
EXPECT_DEATH_IF_SUPPORTED(std::cout << *(poisoned_ptr - 10), "");
35+
EXPECT_DEATH_IF_SUPPORTED(std::cout << *(poisoned_ptr + 10), "");
36+
}
37+
38+
} // namespace
39+
} // namespace base_internal
40+
ABSL_NAMESPACE_END
41+
} // namespace absl

0 commit comments

Comments
 (0)