Skip to content
Merged
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
25 changes: 16 additions & 9 deletions runtime/core/evalue.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,20 @@ class BoxedEvalueList {
*/
executorch::aten::ArrayRef<T> get() const;

/**
* Destroys the unwrapped elements without re-dereferencing wrapped_vals_.
* This is safe to call during EValue destruction because it does not
* dereference wrapped_vals_, which may point to EValues mutated by
* MoveCall instructions.
*/
void destroy_elements() {
for (typename executorch::aten::ArrayRef<T>::size_type i = 0;
i < wrapped_vals_.size();
i++) {
unwrapped_vals_[i].~T();
}
}

private:
static EValue** checkWrappedVals(EValue** wrapped_vals, int size) {
ET_CHECK_MSG(wrapped_vals != nullptr, "wrapped_vals cannot be null");
Expand Down Expand Up @@ -491,18 +505,11 @@ struct EValue {
} else if (
isTensorList() &&
payload.copyable_union.as_tensor_list_ptr != nullptr) {
// for (auto& tensor : toTensorList()) {
for (auto& tensor : payload.copyable_union.as_tensor_list_ptr->get()) {
tensor.~Tensor();
}
payload.copyable_union.as_tensor_list_ptr->destroy_elements();
} else if (
Comment on lines 505 to 509
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding a regression test for the reported MoveCall/type-confusion scenario: construct an EValue TensorList, call toTensorList()/get() to populate unwrapped_vals_, then mutate one of the underlying wrapped EValues to a non-tensor (e.g., Int) and ensure destroying the list EValue does not crash. This would lock in the security fix and prevent reintroducing the destructor-time dereference path.

Copilot uses AI. Check for mistakes.
isListOptionalTensor() &&
payload.copyable_union.as_list_optional_tensor_ptr != nullptr) {
// for (auto& optional_tensor : toListOptionalTensor()) {
for (auto& optional_tensor :
payload.copyable_union.as_list_optional_tensor_ptr->get()) {
optional_tensor.~optional();
}
payload.copyable_union.as_list_optional_tensor_ptr->destroy_elements();
}
}

Expand Down
Loading