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