Skip to content

Commit 95fba2d

Browse files
authored
fix: prevent integer overflow in memory size calculation for tensors (#16481)
* fix: prevent integer overflow in memory size calculation for tensors This commit addresses potential integer overflow issues in memory size calculations by: - Changing num_elements type from int32_t to int64_t - Adding overflow checks before size calculations - Using large_num_elements() instead of num_elements() - Casting final size to size_t after overflow validation The changes affect BuddyMemoryManager and several kernel implementations (ExpandDims, If, Reshape, TransposeConv) to ensure safe memory operations with large tensors. ONE-DCO-1.0-Signed-off-by: Chunseok Lee <chunseok.lee@samsung.com>
1 parent 093fca8 commit 95fba2d

9 files changed

Lines changed: 94 additions & 13 deletions

File tree

compiler/luci-interpreter/src/BuddyMemoryManager.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,16 @@ BuddyMemoryManager::BuddyMemoryManager(uint8_t *memory_start, int32_t memSize)
4343
void BuddyMemoryManager::allocate_memory(luci_interpreter::Tensor &tensor)
4444
{
4545
const size_t element_size = getDataTypeSize(tensor.element_type());
46-
const int32_t num_elements = tensor.shape().num_elements();
47-
auto size = num_elements * element_size;
46+
const int64_t num_elements = tensor.shape().large_num_elements();
47+
48+
// Check for integer overflow in size calculation
49+
if (num_elements < 0 || static_cast<uint64_t>(num_elements) > SIZE_MAX / element_size)
50+
{
51+
throw std::runtime_error("Integer overflow in size calculation");
52+
}
53+
54+
const int64_t total_size = num_elements * element_size;
55+
auto size = static_cast<size_t>(total_size);
4856
auto footprint = size + sizeof(Block);
4957
auto l = (footprint & (footprint - 1)) == 0
5058
? lowerLog2(footprint)

compiler/luci-interpreter/src/kernels/ExpandDims.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,16 @@ void ExpandDims::execute() const
8080
auto *output_data = output()->data<void>();
8181

8282
const size_t element_size = getDataTypeSize(input()->element_type());
83-
const int32_t num_elements = input()->shape().num_elements();
84-
std::memcpy(output_data, input_data, num_elements * element_size);
83+
const int64_t num_elements = input()->shape().large_num_elements();
84+
85+
// Check for integer overflow in size calculation
86+
if (num_elements < 0 || static_cast<uint64_t>(num_elements) > SIZE_MAX / element_size)
87+
{
88+
throw std::runtime_error("Integer overflow in size calculation");
89+
}
90+
91+
const int64_t total_size = num_elements * element_size;
92+
std::memcpy(output_data, input_data, static_cast<size_t>(total_size));
8593
}
8694

8795
} // namespace kernels

compiler/luci-interpreter/src/kernels/If.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,18 @@ void If::execute() const
8383
// TODO: Think about how allocate memory for output in main graph
8484
active_graph->configureAllocations(output(i));
8585

86-
const int32_t num_elements = output(i)->shape().num_elements();
86+
const int64_t num_elements = output(i)->shape().large_num_elements();
8787
const std::size_t element_size = getDataTypeSize(output(i)->element_type());
88+
89+
// Check for integer overflow in size calculation
90+
if (num_elements < 0 || static_cast<uint64_t>(num_elements) > SIZE_MAX / element_size)
91+
{
92+
throw std::runtime_error("Integer overflow in size calculation");
93+
}
94+
95+
const int64_t total_size = num_elements * element_size;
8896
std::memcpy(output(i)->data<void>(), graph_outputs[i]->data<void>(),
89-
num_elements * element_size);
97+
static_cast<size_t>(total_size));
9098
}
9199
}
92100

compiler/luci-interpreter/src/kernels/Reshape.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,16 @@ void Reshape::execute() const
101101
auto *output_data = output()->data<void>();
102102

103103
const size_t element_size = getDataTypeSize(input()->element_type());
104-
const int32_t num_elements = input()->shape().num_elements();
105-
std::memcpy(output_data, input_data, num_elements * element_size);
104+
const int64_t num_elements = input()->shape().large_num_elements();
105+
106+
// Check for integer overflow in size calculation
107+
if (num_elements < 0 || static_cast<uint64_t>(num_elements) > SIZE_MAX / element_size)
108+
{
109+
throw std::runtime_error("Integer overflow in size calculation");
110+
}
111+
112+
const int64_t total_size = num_elements * element_size;
113+
std::memcpy(output_data, input_data, static_cast<size_t>(total_size));
106114
}
107115

108116
} // namespace kernels

compiler/luci-interpreter/src/kernels/TransposeConv.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,17 @@ void TransposeConv::evalQuantizedS16() const
296296
int32_t activation_max{};
297297
calculateActivationRangeQuantized(Activation::NONE, output(), &activation_min, &activation_max);
298298

299-
std::memset(scratch_data, 0, scratch_tensor->shape().num_elements() * sizeof(int64_t));
299+
const int64_t num_elements = scratch_tensor->shape().large_num_elements();
300+
const size_t element_size = sizeof(int64_t);
301+
302+
// Check for integer overflow in size calculation
303+
if (num_elements < 0 || static_cast<uint64_t>(num_elements) > SIZE_MAX / element_size)
304+
{
305+
throw std::runtime_error("Integer overflow in size calculation");
306+
}
307+
308+
const int64_t total_size = num_elements * element_size;
309+
std::memset(scratch_data, 0, static_cast<size_t>(total_size));
300310

301311
BroadcastableWrapper<ChannelQuantMultipliers> output_multipliers(_quant_multipliers);
302312
for (int32_t batch = 0; batch < batches; ++batch)

compiler/luci-interpreter/src/kernels/While.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,17 @@ void copy(const std::vector<const Tensor *> &src, const std::vector<Tensor *> &d
3535
LUCI_INTERPRETER_CHECK(dst[i]->element_type() == src[i]->element_type());
3636
dst[i]->resize(src[i]->shape());
3737

38-
const int32_t num_elements = src[i]->shape().num_elements();
38+
const int64_t num_elements = src[i]->shape().large_num_elements();
3939
const std::size_t element_size = getDataTypeSize(src[i]->element_type());
40-
std::memcpy(dst[i]->data<void>(), src[i]->data<void>(), num_elements * element_size);
40+
41+
// Check for integer overflow in size calculation
42+
if (num_elements < 0 || static_cast<uint64_t>(num_elements) > SIZE_MAX / element_size)
43+
{
44+
throw std::runtime_error("Integer overflow in size calculation");
45+
}
46+
47+
const int64_t total_size = num_elements * element_size;
48+
std::memcpy(dst[i]->data<void>(), src[i]->data<void>(), static_cast<size_t>(total_size));
4149
}
4250
}
4351

compiler/luci-interpreter/src/loader/GraphLoader.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,16 @@ template <typename NodeT> Shape getNodeShape(const NodeT *node)
3939
template <DataType DT> const void *getNodeDataImpl(const luci::CircleConst *node, size_t *data_size)
4040
{
4141
const size_t element_size = getDataTypeSize(DT);
42-
const int32_t num_elements = node->size<DT>();
42+
const int64_t num_elements = node->size<DT>(); // Assuming size<DT>() uses large_num_elements()
4343

44-
*data_size = num_elements * element_size;
44+
// Check for integer overflow in size calculation
45+
if (num_elements < 0 || static_cast<uint64_t>(num_elements) > SIZE_MAX / element_size)
46+
{
47+
throw std::runtime_error("Integer overflow in size calculation");
48+
}
49+
50+
const int64_t total_size = num_elements * element_size;
51+
*data_size = static_cast<size_t>(total_size);
4552
if (*data_size > 0)
4653
{
4754
// FIXME There is no good way to get the pointer to the data currently.

compiler/luci/import/src/Nodes/CircleConst.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,23 @@ void copy_data<loco::DataType::STRING>(const VectorWrapper<uint8_t> &raw_data,
9696
}
9797
assert(offsets.size() == num_elements + 1);
9898

99+
// Validate STRING offsets as non-negative, monotonic, and bounded within data buffer
100+
for (uint32_t i = 0; i < offsets.size(); ++i)
101+
{
102+
if (offsets[i] < 0)
103+
{
104+
throw std::runtime_error("String offset is negative");
105+
}
106+
if (i > 0 && offsets[i] < offsets[i - 1])
107+
{
108+
throw std::runtime_error("String offsets are not monotonic");
109+
}
110+
if (offsets[i] > static_cast<int32_t>(raw_data.size()))
111+
{
112+
throw std::runtime_error("String offset is out of bounds");
113+
}
114+
}
115+
99116
const_node->size<loco::DataType::STRING>(num_elements);
100117
for (uint32_t i = 0; i < num_elements; ++i)
101118
{

runtime/onert/core/src/loader/BaseLoader.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,13 @@ template <typename LoaderDomain> class BaseLoader
113113
// Get BuiltinOperator
114114
BuiltinOperator getBuiltinOperator(const Operator *op)
115115
{
116+
// Enforce explicit bounds validation for opcode_index before every operator-code lookup
117+
if (op->opcode_index() < 0 ||
118+
static_cast<size_t>(op->opcode_index()) >= _domain_model->operator_codes()->size())
119+
{
120+
throw std::runtime_error("Invalid opcode_index: " + std::to_string(op->opcode_index()));
121+
}
122+
116123
auto const builtin_opcode = _domain_model->operator_codes()->Get(op->opcode_index());
117124
auto builtin_op = builtin_opcode->builtin_code();
118125
if (builtin_op < BuiltinOperator::BuiltinOperator_PLACEHOLDER_FOR_GREATER_OP_CODES)

0 commit comments

Comments
 (0)