Add tensor name to some of the error messages produced by tflite::Verify.
PiperOrigin-RevId: 233640378
This commit is contained in:
parent
ba941c212d
commit
5f5088767d
@ -54,7 +54,7 @@ const uint32_t kMaxNumString = UINT_MAX / sizeof(int32_t) - 2;
|
|||||||
|
|
||||||
// Verifies string tensor has legit buffer contents that follow the schema
|
// Verifies string tensor has legit buffer contents that follow the schema
|
||||||
// defined in lite/string_util.h
|
// defined in lite/string_util.h
|
||||||
bool VerifyStringTensorBuffer(const Buffer& buffer,
|
bool VerifyStringTensorBuffer(const Tensor& tensor, const Buffer& buffer,
|
||||||
ErrorReporter* error_reporter) {
|
ErrorReporter* error_reporter) {
|
||||||
uint32_t buffer_size = buffer.data()->size();
|
uint32_t buffer_size = buffer.data()->size();
|
||||||
const char* buffer_ptr = reinterpret_cast<const char*>(buffer.data()->data());
|
const char* buffer_ptr = reinterpret_cast<const char*>(buffer.data()->data());
|
||||||
@ -62,7 +62,8 @@ bool VerifyStringTensorBuffer(const Buffer& buffer,
|
|||||||
uint32_t num_strings = *GetIntPtr(buffer_ptr);
|
uint32_t num_strings = *GetIntPtr(buffer_ptr);
|
||||||
if (num_strings > kMaxNumString) {
|
if (num_strings > kMaxNumString) {
|
||||||
ReportError(error_reporter,
|
ReportError(error_reporter,
|
||||||
"String tensor has invalid num of string set: %d", num_strings);
|
"String tensor %s has invalid num of string set: %d",
|
||||||
|
tensor.name()->c_str(), num_strings);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
uint32_t header_offsets =
|
uint32_t header_offsets =
|
||||||
@ -70,9 +71,9 @@ bool VerifyStringTensorBuffer(const Buffer& buffer,
|
|||||||
|
|
||||||
if (buffer_size < header_offsets) {
|
if (buffer_size < header_offsets) {
|
||||||
ReportError(error_reporter,
|
ReportError(error_reporter,
|
||||||
"String tensor buffer requires at least %d bytes, but is "
|
"String tensor %s buffer requires at least %d bytes, but is "
|
||||||
"allocated with %d bytes",
|
"allocated with %d bytes",
|
||||||
header_offsets, buffer_size);
|
tensor.name()->c_str(), header_offsets, buffer_size);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,22 +82,24 @@ bool VerifyStringTensorBuffer(const Buffer& buffer,
|
|||||||
|
|
||||||
if (*GetIntPtr(buffer_ptr + offset) != header_offsets) {
|
if (*GetIntPtr(buffer_ptr + offset) != header_offsets) {
|
||||||
ReportError(error_reporter,
|
ReportError(error_reporter,
|
||||||
"String tensor buffer initial offset must be: %d",
|
"String tensor %s buffer initial offset must be: %d",
|
||||||
header_offsets);
|
tensor.name()->c_str(), header_offsets);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
offset += sizeof(int32_t);
|
offset += sizeof(int32_t);
|
||||||
for (int i = 1; i <= num_strings; i++, offset += sizeof(int32_t)) {
|
for (int i = 1; i <= num_strings; i++, offset += sizeof(int32_t)) {
|
||||||
int string_offset = *GetIntPtr(buffer_ptr + offset);
|
int string_offset = *GetIntPtr(buffer_ptr + offset);
|
||||||
if (string_offset < prev_ptr || string_offset > buffer_size) {
|
if (string_offset < prev_ptr || string_offset > buffer_size) {
|
||||||
ReportError(error_reporter, "String tensor buffer is invalid: index %d",
|
ReportError(error_reporter,
|
||||||
i);
|
"String tensor %s buffer is invalid: index %d",
|
||||||
|
tensor.name()->c_str(), i);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (*GetIntPtr(buffer_ptr + offset - sizeof(int32_t)) != buffer_size) {
|
if (*GetIntPtr(buffer_ptr + offset - sizeof(int32_t)) != buffer_size) {
|
||||||
ReportError(error_reporter, "String tensor buffer last offset must be %d",
|
ReportError(error_reporter,
|
||||||
buffer_size);
|
"String tensor %s buffer last offset must be %d",
|
||||||
|
tensor.name()->c_str(), buffer_size);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -107,13 +110,15 @@ bool VerifyNumericTensorBuffer(const Tensor& tensor, const Buffer& buffer,
|
|||||||
ErrorReporter* error_reporter) {
|
ErrorReporter* error_reporter) {
|
||||||
uint64_t bytes_required = 1;
|
uint64_t bytes_required = 1;
|
||||||
if (!tensor.shape()) {
|
if (!tensor.shape()) {
|
||||||
ReportError(error_reporter, "Tensor shape is empty");
|
ReportError(error_reporter, "Tensor %s shape is empty",
|
||||||
|
tensor.name()->c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (int dim : *tensor.shape()) {
|
for (int dim : *tensor.shape()) {
|
||||||
bytes_required *= dim;
|
bytes_required *= dim;
|
||||||
if (bytes_required > UINT_MAX) {
|
if (bytes_required > UINT_MAX) {
|
||||||
ReportError(error_reporter, "Tensor dimension overflow");
|
ReportError(error_reporter, "Tensor %s dimension overflow",
|
||||||
|
tensor.name()->c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -133,19 +138,21 @@ bool VerifyNumericTensorBuffer(const Tensor& tensor, const Buffer& buffer,
|
|||||||
case TensorType_FLOAT16:
|
case TensorType_FLOAT16:
|
||||||
// FALLTHROUGH_INTENDED;
|
// FALLTHROUGH_INTENDED;
|
||||||
default:
|
default:
|
||||||
ReportError(error_reporter, "Invalid tensor type: %d", tensor.type());
|
ReportError(error_reporter, "Tensor %s invalid type: %d",
|
||||||
|
tensor.name()->c_str(), tensor.type());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (bytes_required > UINT_MAX) {
|
if (bytes_required > UINT_MAX) {
|
||||||
ReportError(error_reporter, "Tensor dimension overflow");
|
ReportError(error_reporter, "Tensor %s dimension overflow",
|
||||||
|
tensor.name()->c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bytes_required != buffer.data()->size()) {
|
if (bytes_required != buffer.data()->size()) {
|
||||||
ReportError(
|
ReportError(
|
||||||
error_reporter,
|
error_reporter,
|
||||||
"Tensor requires %d bytes, but is allocated with %d bytes buffer",
|
"Tensor %s requires %d bytes, but is allocated with %d bytes buffer",
|
||||||
bytes_required, buffer.data()->size());
|
tensor.name()->c_str(), bytes_required, buffer.data()->size());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -299,14 +306,14 @@ bool VerifyTensors(const Model& model, ErrorReporter* error_reporter) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (tensor->buffer() >= model.buffers()->size()) {
|
if (tensor->buffer() >= model.buffers()->size()) {
|
||||||
ReportError(error_reporter, "Invalid tensor buffer index: %d",
|
ReportError(error_reporter, "Tensor %s invalid buffer index: %d",
|
||||||
tensor->buffer());
|
tensor->name(), tensor->buffer());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto* buffer = model.buffers()->Get(tensor->buffer());
|
auto* buffer = model.buffers()->Get(tensor->buffer());
|
||||||
if (!buffer) {
|
if (!buffer) {
|
||||||
ReportError(error_reporter, "Tensor buffer %d not set",
|
ReportError(error_reporter, "Tensor %s buffer %d not set",
|
||||||
tensor->buffer());
|
tensor->name(), tensor->buffer());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -314,7 +321,7 @@ bool VerifyTensors(const Model& model, ErrorReporter* error_reporter) {
|
|||||||
// buffers will be allocated by the interpreter at run-time.
|
// buffers will be allocated by the interpreter at run-time.
|
||||||
if (buffer->data()) {
|
if (buffer->data()) {
|
||||||
if (tensor->type() == TensorType_STRING) {
|
if (tensor->type() == TensorType_STRING) {
|
||||||
if (!VerifyStringTensorBuffer(*buffer, error_reporter)) {
|
if (!VerifyStringTensorBuffer(*tensor, *buffer, error_reporter)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -161,7 +161,7 @@ TEST(VerifyModel, TestEmptyShape) {
|
|||||||
builder.FinishModel({0, 1}, {3});
|
builder.FinishModel({0, 1}, {3});
|
||||||
ASSERT_FALSE(builder.Verify());
|
ASSERT_FALSE(builder.Verify());
|
||||||
EXPECT_THAT(builder.GetErrorString(),
|
EXPECT_THAT(builder.GetErrorString(),
|
||||||
::testing::ContainsRegex("Tensor shape is empty"));
|
::testing::ContainsRegex("Tensor inputtwo shape is empty"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(VerifyModel, TestSimpleModel) {
|
TEST(VerifyModel, TestSimpleModel) {
|
||||||
@ -221,10 +221,9 @@ TEST(VerifyModel, TestIntTensorShapeIsGreaterThanBuffer) {
|
|||||||
builder.AddTensor({2, 3}, TensorType_UINT8, {1, 2, 3, 4}, "input");
|
builder.AddTensor({2, 3}, TensorType_UINT8, {1, 2, 3, 4}, "input");
|
||||||
builder.FinishModel({}, {});
|
builder.FinishModel({}, {});
|
||||||
ASSERT_FALSE(builder.Verify());
|
ASSERT_FALSE(builder.Verify());
|
||||||
EXPECT_THAT(
|
EXPECT_THAT(builder.GetErrorString(),
|
||||||
builder.GetErrorString(),
|
::testing::ContainsRegex("Tensor input requires 6 bytes, but is "
|
||||||
::testing::ContainsRegex(
|
"allocated with 4 bytes buffer"));
|
||||||
"Tensor requires 6 bytes, but is allocated with 4 bytes buffer"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(VerifyModel, TestIntTensorShapeIsSmallerThanBuffer) {
|
TEST(VerifyModel, TestIntTensorShapeIsSmallerThanBuffer) {
|
||||||
@ -232,10 +231,9 @@ TEST(VerifyModel, TestIntTensorShapeIsSmallerThanBuffer) {
|
|||||||
builder.AddTensor({2, 1}, TensorType_UINT8, {1, 2, 3, 4}, "input");
|
builder.AddTensor({2, 1}, TensorType_UINT8, {1, 2, 3, 4}, "input");
|
||||||
builder.FinishModel({}, {});
|
builder.FinishModel({}, {});
|
||||||
ASSERT_FALSE(builder.Verify());
|
ASSERT_FALSE(builder.Verify());
|
||||||
EXPECT_THAT(
|
EXPECT_THAT(builder.GetErrorString(),
|
||||||
builder.GetErrorString(),
|
::testing::ContainsRegex("Tensor input requires 2 bytes, but is "
|
||||||
::testing::ContainsRegex(
|
"allocated with 4 bytes buffer"));
|
||||||
"Tensor requires 2 bytes, but is allocated with 4 bytes buffer"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(VerifyModel, TestIntTensorShapeOverflow) {
|
TEST(VerifyModel, TestIntTensorShapeOverflow) {
|
||||||
@ -245,7 +243,7 @@ TEST(VerifyModel, TestIntTensorShapeOverflow) {
|
|||||||
builder.FinishModel({}, {});
|
builder.FinishModel({}, {});
|
||||||
ASSERT_FALSE(builder.Verify());
|
ASSERT_FALSE(builder.Verify());
|
||||||
EXPECT_THAT(builder.GetErrorString(),
|
EXPECT_THAT(builder.GetErrorString(),
|
||||||
::testing::ContainsRegex("Tensor dimension overflow"));
|
::testing::ContainsRegex("Tensor input dimension overflow"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(VerifyModel, TensorBufferIsNotValid) {
|
TEST(VerifyModel, TensorBufferIsNotValid) {
|
||||||
@ -284,9 +282,10 @@ TEST(VerifyModel, StringTensorHasInvalidNumString) {
|
|||||||
"input");
|
"input");
|
||||||
builder.FinishModel({}, {});
|
builder.FinishModel({}, {});
|
||||||
ASSERT_FALSE(builder.Verify());
|
ASSERT_FALSE(builder.Verify());
|
||||||
EXPECT_THAT(builder.GetErrorString(),
|
EXPECT_THAT(
|
||||||
|
builder.GetErrorString(),
|
||||||
::testing::ContainsRegex(
|
::testing::ContainsRegex(
|
||||||
"String tensor buffer requires at least -2147483640 bytes, "
|
"String tensor input buffer requires at least -2147483640 bytes, "
|
||||||
"but is allocated with 18 bytes"));
|
"but is allocated with 18 bytes"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -299,7 +298,7 @@ TEST(VerifyModel, StringTensorOffsetTooSmall) {
|
|||||||
ASSERT_FALSE(builder.Verify());
|
ASSERT_FALSE(builder.Verify());
|
||||||
EXPECT_THAT(builder.GetErrorString(),
|
EXPECT_THAT(builder.GetErrorString(),
|
||||||
::testing::ContainsRegex(
|
::testing::ContainsRegex(
|
||||||
"String tensor buffer initial offset must be: 16"));
|
"String tensor input buffer initial offset must be: 16"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(VerifyModel, StringTensorOffsetOutOfRange) {
|
TEST(VerifyModel, StringTensorOffsetOutOfRange) {
|
||||||
@ -309,9 +308,9 @@ TEST(VerifyModel, StringTensorOffsetOutOfRange) {
|
|||||||
{2, 0, 0, 0, 16, 0, 0, 0, 17, 0, 0, 0, 22, 0, 0, 0, 'A', 'B'}, "input");
|
{2, 0, 0, 0, 16, 0, 0, 0, 17, 0, 0, 0, 22, 0, 0, 0, 'A', 'B'}, "input");
|
||||||
builder.FinishModel({}, {});
|
builder.FinishModel({}, {});
|
||||||
ASSERT_FALSE(builder.Verify());
|
ASSERT_FALSE(builder.Verify());
|
||||||
EXPECT_THAT(
|
EXPECT_THAT(builder.GetErrorString(),
|
||||||
builder.GetErrorString(),
|
::testing::ContainsRegex(
|
||||||
::testing::ContainsRegex("String tensor buffer is invalid: index 2"));
|
"String tensor input buffer is invalid: index 2"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(VerifyModel, StringTensorIsLargerThanRequired) {
|
TEST(VerifyModel, StringTensorIsLargerThanRequired) {
|
||||||
@ -322,9 +321,9 @@ TEST(VerifyModel, StringTensorIsLargerThanRequired) {
|
|||||||
"input");
|
"input");
|
||||||
builder.FinishModel({}, {});
|
builder.FinishModel({}, {});
|
||||||
ASSERT_FALSE(builder.Verify());
|
ASSERT_FALSE(builder.Verify());
|
||||||
EXPECT_THAT(
|
EXPECT_THAT(builder.GetErrorString(),
|
||||||
builder.GetErrorString(),
|
::testing::ContainsRegex(
|
||||||
::testing::ContainsRegex("String tensor buffer last offset must be 19"));
|
"String tensor input buffer last offset must be 19"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(VerifyModel, AllOpsAreSupported) {
|
TEST(VerifyModel, AllOpsAreSupported) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user