Skip to content

Commit

Permalink
[libc] Gracefully handle allocation failures around BlockStore.
Browse files Browse the repository at this point in the history
Reviewed By: lntue

Differential Revision: https://reviews.llvm.org/D140459
  • Loading branch information
Siva Chandra Reddy committed Dec 21, 2022
1 parent c2f17bf commit eb9cc25
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 17 deletions.
2 changes: 2 additions & 0 deletions libc/src/__support/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ add_header_library(
blockstore
HDRS
blockstore.h
DEPENDS
libc.src.__support.CPP.new
)

add_header_library(
Expand Down
19 changes: 13 additions & 6 deletions libc/src/__support/blockstore.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@
#ifndef LLVM_LIBC_SUPPORT_BLOCKSTORE_H
#define LLVM_LIBC_SUPPORT_BLOCKSTORE_H

#include <src/__support/CPP/new.h>

#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>

// TODO: fix our assert.h to make it useable
#define assert(x) \
Expand Down Expand Up @@ -114,7 +115,10 @@ class BlockStore {

T *new_obj() {
if (fill_count == BLOCK_SIZE) {
auto new_block = reinterpret_cast<Block *>(::malloc(sizeof(Block)));
AllocChecker ac;
auto new_block = new (ac) Block();
if (!ac)
return nullptr;
if (REVERSE_ORDER) {
new_block->next = current;
} else {
Expand All @@ -129,9 +133,12 @@ class BlockStore {
return obj;
}

void push_back(const T &value) {
[[nodiscard]] bool push_back(const T &value) {
T *ptr = new_obj();
if (ptr == nullptr)
return false;
*ptr = value;
return true;
}

T &back() {
Expand All @@ -153,7 +160,7 @@ class BlockStore {
current->next = nullptr;
}
if (last != &first)
::free(last);
delete last;
fill_count = BLOCK_SIZE;
}

Expand Down Expand Up @@ -182,14 +189,14 @@ void BlockStore<T, BLOCK_SIZE, REVERSE_ORDER>::destroy(
while (current->next != nullptr) {
auto temp = current;
current = current->next;
free(temp);
delete temp;
}
} else {
auto current = block_store->first.next;
while (current != nullptr) {
auto temp = current;
current = current->next;
free(temp);
delete temp;
}
}
block_store->current = nullptr;
Expand Down
10 changes: 3 additions & 7 deletions libc/src/stdlib/atexit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,9 @@ void call_exit_callbacks() {
} // namespace internal

static int add_atexit_unit(const AtExitUnit &unit) {
// TODO: Use the return value of push_back and bubble it to the public
// function as error return value. Note that a BlockStore push_back can
// fail because of allocation failure. Likewise, a FixedVector push_back
// can fail when it is full.
handler_list_mtx.lock();
exit_callbacks.push_back(unit);
handler_list_mtx.unlock();
MutexLock lock(&handler_list_mtx);
if (!exit_callbacks.push_back(unit))
return -1;
return 0;
}

Expand Down
10 changes: 6 additions & 4 deletions libc/test/src/__support/blockstore_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class LlvmLibcBlockStoreTest : public __llvm_libc::testing::Test {
void populate_and_iterate() {
__llvm_libc::cpp::BlockStore<Element, BLOCK_SIZE, REVERSE> block_store;
for (int i = 0; i < int(ELEMENT_COUNT); ++i)
block_store.push_back({i, 2 * i, 3 * unsigned(i)});
ASSERT_TRUE(block_store.push_back({i, 2 * i, 3 * unsigned(i)}));
auto end = block_store.end();
int i = 0;
for (auto iter = block_store.begin(); iter != end; ++iter, ++i) {
Expand All @@ -46,7 +46,7 @@ class LlvmLibcBlockStoreTest : public __llvm_libc::testing::Test {
using __llvm_libc::cpp::BlockStore;
BlockStore<int, 4, REVERSE> block_store;
for (int i = 0; i < 20; i++)
block_store.push_back(i);
ASSERT_TRUE(block_store.push_back(i));
for (int i = 19; i >= 0; i--, block_store.pop_back())
ASSERT_EQ(block_store.back(), i);
block_store.destroy(&block_store);
Expand All @@ -57,9 +57,11 @@ class LlvmLibcBlockStoreTest : public __llvm_libc::testing::Test {
BlockStore<int, 2, REVERSE> block_store;

ASSERT_TRUE(block_store.empty());
block_store.push_back(1);
for (int i = 0; i < 10; i++, block_store.push_back(1))
ASSERT_TRUE(block_store.push_back(1));
for (int i = 0; i < 10; i++) {
ASSERT_FALSE(block_store.empty());
ASSERT_TRUE(block_store.push_back(1));
}
block_store.destroy(&block_store);
}
};
Expand Down

0 comments on commit eb9cc25

Please sign in to comment.