Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/react-native/ReactCommon/jsi/jsi/decorator.h
Original file line number Diff line number Diff line change
Expand Up @@ -996,6 +996,7 @@ class WithRuntimeDecorator : public RuntimeDecorator<Plain, Base> {
}
ArrayBuffer createArrayBuffer(
std::shared_ptr<MutableBuffer> buffer) override {
Around around{with_};
return RD::createArrayBuffer(std::move(buffer));
}
size_t size(const Array& a) override {
Expand Down
66 changes: 66 additions & 0 deletions packages/react-native/ReactCommon/jsi/jsi/test/testlib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2465,6 +2465,72 @@ TEST_P(JSITest, ArrayBufferDetachedTest) {
EXPECT_TRUE(ab.detached(rd));
}

struct ArrayBufferGuardState {
void before() { ++entries; ++depth; }
void after() { ++exits; --depth; }
int entries = 0;
int exits = 0;
int depth = 0;
int allocationDepth = 0;
};

class GuardTestBuffer final : public MutableBuffer {
public:
size_t size() const override { return bytes_.size(); }
uint8_t* data() override { return bytes_.data(); }
private:
std::vector<uint8_t> bytes_{7, 8, 9};
};

class GuardTestAllocator final : public RuntimeDecorator<Runtime, Runtime> {
public:
GuardTestAllocator(ArrayBufferGuardState& state, bool throws)
: RuntimeDecorator(*this), state_(state), throws_(throws) {}
ArrayBuffer createArrayBuffer(std::shared_ptr<MutableBuffer> buffer) override {
state_.allocationDepth = state_.depth;
if (throws_) { throw std::runtime_error("allocation failed"); }
return make<ArrayBuffer>(new BufferValue(std::move(buffer)));
}
size_t size(const ArrayBuffer& buffer) override {
return static_cast<const BufferValue*>(getPointerValue(buffer))->buffer->size();
}
uint8_t* data(const ArrayBuffer& buffer) override {
return static_cast<const BufferValue*>(getPointerValue(buffer))->buffer->data();
}
private:
struct BufferValue final : PointerValue {
explicit BufferValue(std::shared_ptr<MutableBuffer> value) : buffer(std::move(value)) {}
void invalidate() noexcept override { delete this; }
std::shared_ptr<MutableBuffer> buffer;
};
ArrayBufferGuardState& state_;
bool throws_;
};

TEST(RuntimeDecoratorTest, ArrayBufferEntersGuardDuringAllocation) {
ArrayBufferGuardState state;
GuardTestAllocator allocator(state, false);
WithRuntimeDecorator<ArrayBufferGuardState> runtime(allocator, state);
ArrayBuffer buffer(runtime, std::make_shared<GuardTestBuffer>());
EXPECT_EQ(state.allocationDepth, 1);
EXPECT_EQ(state.entries, 1);
EXPECT_EQ(state.exits, 1);
EXPECT_EQ(state.depth, 0);
EXPECT_EQ(buffer.size(runtime), 3);
EXPECT_EQ(buffer.data(runtime)[0], 7);
}

TEST(RuntimeDecoratorTest, ArrayBufferExitsGuardWhenAllocationThrows) {
ArrayBufferGuardState state;
GuardTestAllocator allocator(state, true);
WithRuntimeDecorator<ArrayBufferGuardState> runtime(allocator, state);
EXPECT_THROW(ArrayBuffer(runtime, std::make_shared<GuardTestBuffer>()), std::runtime_error);
EXPECT_EQ(state.allocationDepth, 1);
EXPECT_EQ(state.entries, 1);
EXPECT_EQ(state.exits, 1);
EXPECT_EQ(state.depth, 0);
}

INSTANTIATE_TEST_CASE_P(
Runtimes,
JSITest,
Expand Down
Loading