[ubsan][compiler] Avoid OOB array accesses in Node::inputs_
Since we allocate raw zone memory for its inputs right behind the Node object anyway, drop the previously OOB-accessed 1-element array within the Node and use address computation to get to the inputs storage. Note that this saves one pointer per Node, except for Nodes with zero inputs, where it uses 1*sizeof(Use) more memory than before. Bug: v8:3770 Change-Id: I7f5965c6f1b49013eb7f5a447b685d47decaa8fb Reviewed-on: https://chromium-review.googlesource.com/c/1436218 Reviewed-by: Tobias Tebbi <tebbi@chromium.org> Commit-Queue: Jakob Kummerow <jkummerow@chromium.org> Cr-Commit-Position: refs/heads/master@{#59141}
This commit is contained in:
parent
c640296e5a
commit
e8faf62ca0
@ -25,7 +25,7 @@ void Node::OutOfLineInputs::ExtractFrom(Use* old_use_ptr, Node** old_input_ptr,
|
||||
// Extract the inputs from the old use and input pointers and copy them
|
||||
// to this out-of-line-storage.
|
||||
Use* new_use_ptr = reinterpret_cast<Use*>(this) - 1;
|
||||
Node** new_input_ptr = inputs_;
|
||||
Node** new_input_ptr = inputs();
|
||||
for (int current = 0; current < count; current++) {
|
||||
new_use_ptr->bit_field_ =
|
||||
Use::InputIndexField::encode(current) | Use::InlineField::encode(false);
|
||||
@ -72,20 +72,21 @@ Node* Node::New(Zone* zone, NodeId id, const Operator* op, int input_count,
|
||||
has_extensible_inputs ? input_count + kMaxInlineCapacity : input_count;
|
||||
OutOfLineInputs* outline = OutOfLineInputs::New(zone, capacity);
|
||||
|
||||
// Allocate node.
|
||||
void* node_buffer = zone->New(sizeof(Node));
|
||||
// Allocate node, with space for OutOfLineInputs pointer.
|
||||
void* node_buffer = zone->New(sizeof(Node) + sizeof(OutOfLineInputs*));
|
||||
node = new (node_buffer) Node(id, op, kOutlineMarker, 0);
|
||||
node->inputs_.outline_ = outline;
|
||||
node->set_outline_inputs(outline);
|
||||
|
||||
outline->node_ = node;
|
||||
outline->count_ = input_count;
|
||||
|
||||
input_ptr = outline->inputs_;
|
||||
input_ptr = outline->inputs();
|
||||
use_ptr = reinterpret_cast<Use*>(outline);
|
||||
is_inline = false;
|
||||
} else {
|
||||
// Allocate node with inline inputs.
|
||||
int capacity = input_count;
|
||||
// Allocate node with inline inputs. Capacity must be at least 1 so that
|
||||
// an OutOfLineInputs pointer can be stored when inputs are added later.
|
||||
int capacity = std::max(1, input_count);
|
||||
if (has_extensible_inputs) {
|
||||
const int max = kMaxInlineCapacity;
|
||||
capacity = std::min(input_count + 3, max);
|
||||
@ -97,7 +98,7 @@ Node* Node::New(Zone* zone, NodeId id, const Operator* op, int input_count,
|
||||
reinterpret_cast<void*>(raw_buffer + capacity * sizeof(Use));
|
||||
|
||||
node = new (node_buffer) Node(id, op, input_count, capacity);
|
||||
input_ptr = node->inputs_.inline_;
|
||||
input_ptr = node->inline_inputs();
|
||||
use_ptr = reinterpret_cast<Use*>(node);
|
||||
is_inline = true;
|
||||
}
|
||||
@ -119,8 +120,8 @@ Node* Node::New(Zone* zone, NodeId id, const Operator* op, int input_count,
|
||||
Node* Node::Clone(Zone* zone, NodeId id, const Node* node) {
|
||||
int const input_count = node->InputCount();
|
||||
Node* const* const inputs = node->has_inline_inputs()
|
||||
? node->inputs_.inline_
|
||||
: node->inputs_.outline_->inputs_;
|
||||
? node->inline_inputs()
|
||||
: node->outline_inputs()->inputs();
|
||||
Node* const clone = New(zone, id, node->op(), input_count, inputs, false);
|
||||
clone->set_type(node->type());
|
||||
return clone;
|
||||
@ -158,16 +159,16 @@ void Node::AppendInput(Zone* zone, Node* new_to) {
|
||||
outline->node_ = this;
|
||||
outline->ExtractFrom(GetUsePtr(0), GetInputPtr(0), input_count);
|
||||
bit_field_ = InlineCountField::update(bit_field_, kOutlineMarker);
|
||||
inputs_.outline_ = outline;
|
||||
set_outline_inputs(outline);
|
||||
} else {
|
||||
// use current out of line inputs.
|
||||
outline = inputs_.outline_;
|
||||
outline = outline_inputs();
|
||||
if (input_count >= outline->capacity_) {
|
||||
// out of space in out-of-line inputs.
|
||||
outline = OutOfLineInputs::New(zone, input_count * 2 + 3);
|
||||
outline->node_ = this;
|
||||
outline->ExtractFrom(GetUsePtr(0), GetInputPtr(0), input_count);
|
||||
inputs_.outline_ = outline;
|
||||
set_outline_inputs(outline);
|
||||
}
|
||||
}
|
||||
outline->count_++;
|
||||
@ -247,7 +248,7 @@ void Node::TrimInputCount(int new_input_count) {
|
||||
if (has_inline_inputs()) {
|
||||
bit_field_ = InlineCountField::update(bit_field_, new_input_count);
|
||||
} else {
|
||||
inputs_.outline_->count_ = new_input_count;
|
||||
outline_inputs()->count_ = new_input_count;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,7 +60,7 @@ class V8_EXPORT_PRIVATE Node final {
|
||||
|
||||
int InputCount() const {
|
||||
return has_inline_inputs() ? InlineCountField::decode(bit_field_)
|
||||
: inputs_.outline_->count_;
|
||||
: outline_inputs()->count_;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
@ -170,7 +170,9 @@ class V8_EXPORT_PRIVATE Node final {
|
||||
Node* node_;
|
||||
int count_;
|
||||
int capacity_;
|
||||
Node* inputs_[1];
|
||||
|
||||
// Inputs are allocated right behind the OutOfLineInputs instance.
|
||||
inline Node** inputs();
|
||||
|
||||
static OutOfLineInputs* New(Zone* zone, int capacity);
|
||||
void ExtractFrom(Use* use_ptr, Node** input_ptr, int count);
|
||||
@ -189,8 +191,8 @@ class V8_EXPORT_PRIVATE Node final {
|
||||
int index = input_index();
|
||||
Use* start = this + 1 + index;
|
||||
Node** inputs = is_inline_use()
|
||||
? reinterpret_cast<Node*>(start)->inputs_.inline_
|
||||
: reinterpret_cast<OutOfLineInputs*>(start)->inputs_;
|
||||
? reinterpret_cast<Node*>(start)->inline_inputs()
|
||||
: reinterpret_cast<OutOfLineInputs*>(start)->inputs();
|
||||
return &inputs[index];
|
||||
}
|
||||
|
||||
@ -239,17 +241,29 @@ class V8_EXPORT_PRIVATE Node final {
|
||||
|
||||
Node(NodeId id, const Operator* op, int inline_count, int inline_capacity);
|
||||
|
||||
inline Address inputs_location() const;
|
||||
|
||||
Node** inline_inputs() const {
|
||||
return reinterpret_cast<Node**>(inputs_location());
|
||||
}
|
||||
OutOfLineInputs* outline_inputs() const {
|
||||
return *reinterpret_cast<OutOfLineInputs**>(inputs_location());
|
||||
}
|
||||
void set_outline_inputs(OutOfLineInputs* outline) {
|
||||
*reinterpret_cast<OutOfLineInputs**>(inputs_location()) = outline;
|
||||
}
|
||||
|
||||
Node* const* GetInputPtrConst(int input_index) const {
|
||||
return has_inline_inputs() ? &(inputs_.inline_[input_index])
|
||||
: &inputs_.outline_->inputs_[input_index];
|
||||
return has_inline_inputs() ? &(inline_inputs()[input_index])
|
||||
: &(outline_inputs()->inputs()[input_index]);
|
||||
}
|
||||
Node** GetInputPtr(int input_index) {
|
||||
return has_inline_inputs() ? &(inputs_.inline_[input_index])
|
||||
: &inputs_.outline_->inputs_[input_index];
|
||||
return has_inline_inputs() ? &(inline_inputs()[input_index])
|
||||
: &(outline_inputs()->inputs()[input_index]);
|
||||
}
|
||||
Use* GetUsePtr(int input_index) {
|
||||
Use* ptr = has_inline_inputs() ? reinterpret_cast<Use*>(this)
|
||||
: reinterpret_cast<Use*>(inputs_.outline_);
|
||||
: reinterpret_cast<Use*>(outline_inputs());
|
||||
return &ptr[-1 - input_index];
|
||||
}
|
||||
|
||||
@ -287,11 +301,6 @@ class V8_EXPORT_PRIVATE Node final {
|
||||
Mark mark_;
|
||||
uint32_t bit_field_;
|
||||
Use* first_use_;
|
||||
union {
|
||||
// Inline storage for inputs or out-of-line storage.
|
||||
Node* inline_[1];
|
||||
OutOfLineInputs* outline_;
|
||||
} inputs_;
|
||||
|
||||
friend class Edge;
|
||||
friend class NodeMarkerBase;
|
||||
@ -300,6 +309,14 @@ class V8_EXPORT_PRIVATE Node final {
|
||||
DISALLOW_COPY_AND_ASSIGN(Node);
|
||||
};
|
||||
|
||||
Address Node::inputs_location() const {
|
||||
return reinterpret_cast<Address>(this) + sizeof(Node);
|
||||
}
|
||||
|
||||
Node** Node::OutOfLineInputs::inputs() {
|
||||
return reinterpret_cast<Node**>(reinterpret_cast<Address>(this) +
|
||||
sizeof(Node::OutOfLineInputs));
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const Node& n);
|
||||
|
||||
@ -402,21 +419,21 @@ bool Node::IsDead() const {
|
||||
Node::InputEdges Node::input_edges() {
|
||||
int inline_count = InlineCountField::decode(bit_field_);
|
||||
if (inline_count != kOutlineMarker) {
|
||||
return InputEdges(inputs_.inline_, reinterpret_cast<Use*>(this) - 1,
|
||||
return InputEdges(inline_inputs(), reinterpret_cast<Use*>(this) - 1,
|
||||
inline_count);
|
||||
} else {
|
||||
return InputEdges(inputs_.outline_->inputs_,
|
||||
reinterpret_cast<Use*>(inputs_.outline_) - 1,
|
||||
inputs_.outline_->count_);
|
||||
return InputEdges(outline_inputs()->inputs(),
|
||||
reinterpret_cast<Use*>(outline_inputs()) - 1,
|
||||
outline_inputs()->count_);
|
||||
}
|
||||
}
|
||||
|
||||
Node::Inputs Node::inputs() const {
|
||||
int inline_count = InlineCountField::decode(bit_field_);
|
||||
if (inline_count != kOutlineMarker) {
|
||||
return Inputs(inputs_.inline_, inline_count);
|
||||
return Inputs(inline_inputs(), inline_count);
|
||||
} else {
|
||||
return Inputs(inputs_.outline_->inputs_, inputs_.outline_->count_);
|
||||
return Inputs(outline_inputs()->inputs(), outline_inputs()->count_);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user