|
4 | 4 | #include <gtest/gtest.h> |
5 | 5 |
|
6 | 6 | #include <cstdlib> |
| 7 | +#include <cstring> |
7 | 8 | #include <memory> |
8 | 9 |
|
9 | 10 | #include "comms/ctran/backends/ib/CtranIbSingleton.h" |
@@ -1365,6 +1366,26 @@ TEST_F(RegCacheTest, ImportMemWithExtraSegments) { |
1365 | 1366 | COMMCHECK_TEST(ctran::commMemFreeDisjoint(buf, segSizes)); |
1366 | 1367 | } |
1367 | 1368 |
|
| 1369 | +// Verify IpcRemHandle is trivially destructible and survives heap corruption. |
| 1370 | +// Simulates the scenario from the IB double-completion bug: construct a valid |
| 1371 | +// IpcRemHandle, corrupt its memory, then destroy it. With std::string peerId, |
| 1372 | +// the destructor tries to free a corrupted pointer and segfaults. With a |
| 1373 | +// fixed-size char[], the destructor is trivial and this is safe. |
| 1374 | +TEST(IpcRemHandleTest, CorruptedDestroyDoesNotCrash) { |
| 1375 | + alignas(ctran::regcache::IpcRemHandle) char |
| 1376 | + buf[sizeof(ctran::regcache::IpcRemHandle)]; |
| 1377 | + auto* handle = new (buf) ctran::regcache::IpcRemHandle(); |
| 1378 | + |
| 1379 | + // Corrupt the entire struct — simulates heap corruption |
| 1380 | + std::memset(buf, 0xAB, sizeof(ctran::regcache::IpcRemHandle)); |
| 1381 | + // Prevent the compiler from optimizing away the corruption or destructor |
| 1382 | + asm volatile("" ::: "memory"); |
| 1383 | + |
| 1384 | + // Destructor must not crash. With std::string this segfaults; |
| 1385 | + // with char[] this is a no-op. |
| 1386 | + handle->~IpcRemHandle(); |
| 1387 | +} |
| 1388 | + |
1368 | 1389 | int main(int argc, char* argv[]) { |
1369 | 1390 | ::testing::InitGoogleTest(&argc, argv); |
1370 | 1391 | return RUN_ALL_TESTS(); |
|
0 commit comments