|
| 1 | +/* |
| 2 | + * Copyright 2026, Datadog, Inc. |
| 3 | + * SPDX-License-Identifier: Apache-2.0 |
| 4 | + */ |
| 5 | + |
1 | 6 | #include <gmock/gmock.h> |
2 | 7 | #include <gtest/gtest.h> |
3 | 8 | #include <climits> |
@@ -281,6 +286,40 @@ TEST_F(SafeFetchTest, safeCopy_requestedRangeCrossesUnmappedPage_returnsFalse) { |
281 | 286 | munmap(region, page_size); |
282 | 287 | } |
283 | 288 |
|
| 289 | +TEST_F(SafeFetchTest, safeCopy_partialPrefixCopiedBeforeFault) { |
| 290 | + // When the requested range straddles the boundary into an unmapped page, |
| 291 | + // safeCopy returns false but the byte-granular copy still writes every |
| 292 | + // readable byte before the fault. Verify the readable prefix landed in dst. |
| 293 | + long page_size = sysconf(_SC_PAGESIZE); |
| 294 | + ASSERT_GT(page_size, 0); |
| 295 | + |
| 296 | + void* region = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE, |
| 297 | + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); |
| 298 | + ASSERT_NE(region, MAP_FAILED); |
| 299 | + ASSERT_EQ(0, munmap((char*)region + page_size, page_size)); |
| 300 | + |
| 301 | + char* mapped_end = (char*)region + page_size; |
| 302 | + // Place src so exactly `prefix` bytes are readable and the rest fall in |
| 303 | + // the unmapped page. |
| 304 | + const size_t prefix = 5; |
| 305 | + char* src = mapped_end - prefix; |
| 306 | + static const char kPrefix[] = "HELLO"; // 5 known readable bytes |
| 307 | + memcpy(src, kPrefix, prefix); |
| 308 | + |
| 309 | + // Request more than the readable prefix so the copy faults partway. |
| 310 | + const size_t requested = prefix + 4; |
| 311 | + char dst[16]; |
| 312 | + memset(dst, 0x5A, sizeof(dst)); |
| 313 | + EXPECT_FALSE(SafeAccess::safeCopy(dst, src, requested)); |
| 314 | + |
| 315 | + // The readable prefix must have been copied faithfully before the fault. |
| 316 | + EXPECT_EQ(0, memcmp(dst, kPrefix, prefix)); |
| 317 | + // Bytes past the prefix were never written (fault stopped the copy). |
| 318 | + EXPECT_EQ((char)0x5A, dst[prefix]); |
| 319 | + |
| 320 | + munmap(region, page_size); |
| 321 | +} |
| 322 | + |
284 | 323 | TEST_F(SafeFetchTest, safeCopy_unalignedSource_allMisalignments) { |
285 | 324 | // The front fixup must correctly extract leading bytes from the |
286 | 325 | // previous-aligned-word fetch for every misalignment k ∈ {1, 2, 3}. |
|
0 commit comments