Summary: Create an artificial limit on an arena to start throwing bad_alloc before running out of system memory
Test Plan: adjust unit test
Reviewed By: marcelo.juchem@fb.com
FB internal diff:
D762695
void* Arena<Alloc>::allocateSlow(size_t size) {
std::pair<Block*, size_t> p;
char* start;
+
+
+ size_t allocSize = std::max(size, minBlockSize()) + sizeof(Block);
+ if(sizeLimit_ && allocSize > sizeLimit_ - totalAllocatedSize_) {
+ throw std::bad_alloc();
+ }
+
if (size > minBlockSize()) {
// Allocate a large block for this chunk only, put it at the back of the
// list so it doesn't get used for small allocations; don't change ptr_
class Arena {
public:
explicit Arena(const Alloc& alloc,
- size_t minBlockSize = kDefaultMinBlockSize)
+ size_t minBlockSize = kDefaultMinBlockSize,
+ size_t sizeLimit = 0)
: allocAndSize_(alloc, minBlockSize)
, ptr_(nullptr)
, end_(nullptr)
, totalAllocatedSize_(0)
- , bytesUsed_(0) {
+ , bytesUsed_(0)
+ , sizeLimit_(sizeLimit) {
}
~Arena();
char* end_;
size_t totalAllocatedSize_;
size_t bytesUsed_;
+ size_t sizeLimit_;
};
/**
*/
class SysArena : public Arena<SysAlloc> {
public:
- explicit SysArena(size_t minBlockSize = kDefaultMinBlockSize)
- : Arena<SysAlloc>(SysAlloc(), minBlockSize) {
+ explicit SysArena(
+ size_t minBlockSize = kDefaultMinBlockSize,
+ size_t sizeLimit = 0)
+ : Arena<SysAlloc>(SysAlloc(), minBlockSize, sizeLimit) {
}
};
}
}
+TEST(Arena, SizeLimit) {
+ static const size_t requestedBlockSize = sizeof(size_t);
+ static const size_t maxSize = 10 * requestedBlockSize;
+
+ SysArena arena(requestedBlockSize, maxSize);
+
+ void* a = arena.allocate(sizeof(size_t));
+ EXPECT_TRUE(a != nullptr);
+ EXPECT_THROW(arena.allocate(maxSize + 1), std::bad_alloc);
+}
+
int main(int argc, char *argv[]) {
testing::InitGoogleTest(&argc, argv);
google::ParseCommandLineFlags(&argc, &argv, true);