mirror of
https://github.com/clearlinux/folly.git
synced 2026-09-01 02:34:43 +00:00
IOBuf::reserve would return less tailroom than requested under certain circumstances
Test Plan: test added Reviewed By: lxiong@fb.com Subscribers: lxiong, net-systems@, folly-diffs@, yfeldblum, chalfant, pamelavagata, kma FB internal diff: D2036967 Tasks: 6925950 Signature: t1:2036967:1430431606:3e115f7ed76b207572db26d352bebefe7a3d306d
This commit is contained in:
committed by
Praveen Kumar Ramakrishnan
parent
e602963840
commit
fe381c8b35
+4
-2
@@ -698,7 +698,7 @@ void IOBuf::reserveSlow(uint64_t minHeadroom, uint64_t minTailroom) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t newAllocatedCapacity = goodExtBufferSize(newCapacity);
|
||||
size_t newAllocatedCapacity = 0;
|
||||
uint8_t* newBuffer = nullptr;
|
||||
uint64_t newHeadroom = 0;
|
||||
uint64_t oldHeadroom = headroom();
|
||||
@@ -708,8 +708,9 @@ void IOBuf::reserveSlow(uint64_t minHeadroom, uint64_t minTailroom) {
|
||||
SharedInfo* info = sharedInfo();
|
||||
if (info && (info->freeFn == nullptr) && length_ != 0 &&
|
||||
oldHeadroom >= minHeadroom) {
|
||||
size_t headSlack = oldHeadroom - minHeadroom;
|
||||
newAllocatedCapacity = goodExtBufferSize(newCapacity + headSlack);
|
||||
if (usingJEMalloc()) {
|
||||
size_t headSlack = oldHeadroom - minHeadroom;
|
||||
// We assume that tailroom is more useful and more important than
|
||||
// headroom (not least because realloc / xallocx allow us to grow the
|
||||
// buffer at the tail, but not at the head) So, if we have more headroom
|
||||
@@ -743,6 +744,7 @@ void IOBuf::reserveSlow(uint64_t minHeadroom, uint64_t minTailroom) {
|
||||
// None of the previous reallocation strategies worked (or we're using
|
||||
// an internal buffer). malloc/copy/free.
|
||||
if (newBuffer == nullptr) {
|
||||
newAllocatedCapacity = goodExtBufferSize(newCapacity);
|
||||
void* p = malloc(newAllocatedCapacity);
|
||||
if (UNLIKELY(p == nullptr)) {
|
||||
throw std::bad_alloc();
|
||||
|
||||
@@ -1081,6 +1081,33 @@ TEST(IOBuf, HashAndEqual) {
|
||||
EXPECT_EQ(hash(e), hash(f));
|
||||
}
|
||||
|
||||
// reserveSlow() had a bug when reallocating the buffer in place. It would
|
||||
// preserve old headroom if it's not too much (heuristically) but wouldn't
|
||||
// adjust the requested amount of memory to account for that; the end result
|
||||
// would be that reserve() would return with less tailroom than requested.
|
||||
TEST(IOBuf, ReserveWithHeadroom) {
|
||||
// This is assuming jemalloc, where we know that 4096 and 8192 bytes are
|
||||
// valid (and consecutive) allocation sizes. We're hoping that our
|
||||
// 4096-byte buffer can be expanded in place to 8192 (in practice, this
|
||||
// usually happens).
|
||||
const char data[] = "Lorem ipsum dolor sit amet, consectetur adipiscing elit";
|
||||
constexpr size_t reservedSize = 24; // sizeof(SharedInfo)
|
||||
// chosen carefully so that the buffer is exactly 4096 bytes
|
||||
IOBuf buf(IOBuf::CREATE, 4096 - reservedSize);
|
||||
buf.advance(10);
|
||||
memcpy(buf.writableData(), data, sizeof(data));
|
||||
buf.append(sizeof(data));
|
||||
EXPECT_EQ(sizeof(data), buf.length());
|
||||
|
||||
// Grow the buffer (hopefully in place); this would incorrectly reserve
|
||||
// the 10 bytes of headroom, giving us 10 bytes less than requested.
|
||||
size_t tailroom = 8192 - reservedSize - sizeof(data);
|
||||
buf.reserve(0, tailroom);
|
||||
EXPECT_LE(tailroom, buf.tailroom());
|
||||
EXPECT_EQ(sizeof(data), buf.length());
|
||||
EXPECT_EQ(0, memcmp(data, buf.data(), sizeof(data)));
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
|
||||
Reference in New Issue
Block a user