From 6350d27286114dfdae5f65ae1823ba1150087efb Mon Sep 17 00:00:00 2001 From: Colm Donelan Date: Tue, 9 Jun 2020 16:56:25 +0100 Subject: IVGCVSW-4968 Fix exception handling in TfLiteParser. * The function TfLiteParser::CreateNetworkFromModel was continuing to parse the input file even after a fatal exception was encountered. restructure catch exceptions outside the for loop. * Add simple unit tests to test some exception handling. Signed-off-by: Colm Donelan Change-Id: I202ca6819d40a47159b4ac8f2847958f945666c2 --- src/armnnTfLiteParser/TfLiteParser.cpp | 66 +++++++++++------------------ src/armnnTfLiteParser/test/TfLiteParser.cpp | 41 ++++++++++++++++++ 2 files changed, 66 insertions(+), 41 deletions(-) create mode 100644 src/armnnTfLiteParser/test/TfLiteParser.cpp (limited to 'src') diff --git a/src/armnnTfLiteParser/TfLiteParser.cpp b/src/armnnTfLiteParser/TfLiteParser.cpp index c695caa280..1737da8616 100644 --- a/src/armnnTfLiteParser/TfLiteParser.cpp +++ b/src/armnnTfLiteParser/TfLiteParser.cpp @@ -619,9 +619,6 @@ INetworkPtr TfLiteParser::CreateNetworkFromModel() m_Network = INetwork::Create(); ARMNN_ASSERT(m_Model.get() != nullptr); - bool failedToCreate = false; - std::stringstream errors; - if (m_Model->subgraphs.size() != 1) { throw ParseException( @@ -632,65 +629,52 @@ INetworkPtr TfLiteParser::CreateNetworkFromModel() } size_t subgraphIndex = 0; - for (SubgraphPtr const & subgraph : m_Model->subgraphs) + size_t operatorIndex = 0; + try { - m_SubgraphConnections.emplace_back(subgraph->tensors.size()); - - size_t operatorIndex = 0; - for (OperatorPtr const & op : subgraph->operators) + for (SubgraphPtr const& subgraph : m_Model->subgraphs) { - try + m_SubgraphConnections.emplace_back(subgraph->tensors.size()); + for (OperatorPtr const& op : subgraph->operators) { - auto const & opCodePtr = m_Model->operator_codes[op->opcode_index]; + auto const& opCodePtr = m_Model->operator_codes[op->opcode_index]; auto builtinCode = opCodePtr->builtin_code; if (builtinCode > tflite::BuiltinOperator_MAX) { - throw ParseException( - boost::str( - boost::format("Operator code %1% is out of range 0-%2%. " - "subgraph:%3% operator idx:%4%. %5%") % - builtinCode % - tflite::BuiltinOperator_MAX % - subgraphIndex % - operatorIndex % - CHECK_LOCATION().AsString())); + throw ParseException(boost::str(boost::format("Operator code %1% is out of range 0-%2%. " + "subgraph:%3% operator idx:%4%. %5%") % + builtinCode % tflite::BuiltinOperator_MAX % subgraphIndex % + operatorIndex % CHECK_LOCATION().AsString())); } // lookup and call the parser function - auto & parserFunction = m_ParserFunctions[builtinCode]; + auto& parserFunction = m_ParserFunctions[builtinCode]; (this->*parserFunction)(subgraphIndex, operatorIndex); + ++operatorIndex; } - catch (const ParseException& e) - { - failedToCreate = true; - std::stringstream errorString; - errorString << "Failed to parse operator #" << operatorIndex - << " within subgraph #" << subgraphIndex - << " error: " << e.what(); - ARMNN_LOG(error) << errorString.str(); + SetupInputLayers(subgraphIndex); + SetupOutputLayers(subgraphIndex); + SetupConstantLayers(subgraphIndex); - errors << errorString.str() << "\n"; - } - ++operatorIndex; + ++subgraphIndex; + operatorIndex = 0; } - - SetupInputLayers(subgraphIndex); - SetupOutputLayers(subgraphIndex); - SetupConstantLayers(subgraphIndex); - - ++subgraphIndex; } - - if (failedToCreate) + catch (const ParseException& e) { - // we can skip everything and let the outer exception handler deal with the error + std::stringstream errorString; + errorString << "Failed to parse operator #" << operatorIndex << " within subgraph #" + << subgraphIndex << " error: " << e.what(); + ARMNN_LOG(error) << errorString.str(); + std::stringstream errors; + errors << errorString.str() << "\n"; throw ParseException(errors.str()); } // establish the connections from the layer outputs to the inputs of the subsequent layers - for (size_t subgraphIndex = 0; subgraphIndex < m_SubgraphConnections.size(); ++subgraphIndex) + for (subgraphIndex = 0; subgraphIndex < m_SubgraphConnections.size(); ++subgraphIndex) { for (size_t tensorIndex = 0; tensorIndex < m_SubgraphConnections[subgraphIndex].size(); ++tensorIndex) { diff --git a/src/armnnTfLiteParser/test/TfLiteParser.cpp b/src/armnnTfLiteParser/test/TfLiteParser.cpp new file mode 100644 index 0000000000..36827c0586 --- /dev/null +++ b/src/armnnTfLiteParser/test/TfLiteParser.cpp @@ -0,0 +1,41 @@ +// +// Copyright © 2020 Arm Ltd. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include +#include "ParserFlatbuffersFixture.hpp" +#include "../TfLiteParser.hpp" + +BOOST_AUTO_TEST_SUITE(TensorflowLiteParser) + +BOOST_AUTO_TEST_CASE(ParseEmptyBinaryData) +{ + ITfLiteParser::TfLiteParserOptions options; + ITfLiteParserPtr m_Parser(ITfLiteParser::Create(armnn::Optional(options))); + // Should throw armnn::ParseException: Buffer doesn't conform to the expected Tensorflow Lite flatbuffers format. + BOOST_CHECK_THROW(m_Parser->CreateNetworkFromBinary({0}), armnn::ParseException); +} + +struct NoInputBindingsFixture : public ParserFlatbuffersFixture +{ + explicit NoInputBindingsFixture() + { + m_JsonString = R"( + { + "version": 3, + "operator_codes": [ { "builtin_code": "CONV_2D" } ], + "subgraphs": [ { } ] + } + )"; + SetupSingleInputSingleOutput("inputTensor", "outputTensor"); + } +}; + +BOOST_FIXTURE_TEST_CASE( ParseBadInputBindings, NoInputBindingsFixture ) +{ + // Should throw armnn::ParseException: No input binding found for subgraph:0 and name:inputTensor. + BOOST_CHECK_THROW( (RunTest<4, armnn::DataType::QAsymmU8>(0, { }, { 0 })), armnn::ParseException); +} + +BOOST_AUTO_TEST_SUITE_END() -- cgit v1.2.1