diff --git a/libraries/abi_generator/abi_generator.cpp b/libraries/abi_generator/abi_generator.cpp index c6a084007c9769e20f3dedd4437edd2c123299bf..44a0a6f5216c2a77c798f8036144e947213fd782 100644 --- a/libraries/abi_generator/abi_generator.cpp +++ b/libraries/abi_generator/abi_generator.cpp @@ -124,7 +124,7 @@ bool abi_generator::inspect_type_methods_for_actions(const Decl* decl) { try { qt.setLocalFastQualifiers(0); string field_name = p->getNameAsString(); - string field_type_name = add_type(qt); + string field_type_name = add_type(qt, 0); field_def struct_field{field_name, field_type_name}; ABI_ASSERT(is_builtin_type(get_vector_element_type(struct_field.type)) @@ -236,7 +236,7 @@ void abi_generator::handle_decl(const Decl* decl) { try { auto qt = action_decl->getTypeForDecl()->getCanonicalTypeInternal(); - auto type_name = add_struct(qt); + auto type_name = add_struct(qt, "", 0); ABI_ASSERT(!is_builtin_type(type_name), "A built-in type with the same name exists, try using another name: ${type_name}", ("type_name",type_name)); @@ -259,7 +259,7 @@ void abi_generator::handle_decl(const Decl* decl) { try { ABI_ASSERT(table_decl != nullptr); auto qt = table_decl->getTypeForDecl()->getCanonicalTypeInternal(); - auto type_name = add_struct(qt); + auto type_name = add_struct(qt, "", 0); ABI_ASSERT(!is_builtin_type(type_name), "A built-in type with the same name exists, try using another name: ${type_name}", ("type_name",type_name)); @@ -433,7 +433,11 @@ const struct_def* abi_generator::find_struct(const type_name& name) { type_name abi_generator::resolve_type(const type_name& type){ const auto* td = find_type(type); if( td ) { - return resolve_type(td->type); + for( auto i = output->types.size(); i > 0; --i ) { // avoid infinite recursion + const type_name& t = td->type; + td = find_type(t); + if( td == nullptr ) return t; + } } return type; } @@ -505,7 +509,9 @@ string abi_generator::get_type_name(const clang::QualType& qt, bool with_namespa return name; } -clang::QualType abi_generator::add_typedef(const clang::QualType& tqt) { +clang::QualType abi_generator::add_typedef(const clang::QualType& tqt, size_t recursion_depth) { + + ABI_ASSERT( ++recursion_depth < max_recursion_depth, "recursive definition, max_recursion_depth" ); clang::QualType qt(get_named_type_if_elaborated(tqt)); @@ -516,7 +522,7 @@ clang::QualType abi_generator::add_typedef(const clang::QualType& tqt) { auto underlying_type_name = get_type_name(underlying_type); if ( is_vector(underlying_type) ) { - underlying_type_name = add_vector(underlying_type); + underlying_type_name = add_vector(underlying_type, recursion_depth); } type_def abi_typedef; @@ -531,7 +537,7 @@ clang::QualType abi_generator::add_typedef(const clang::QualType& tqt) { } if( is_typedef(underlying_type) && !is_builtin_type(get_type_name(underlying_type)) ) - return add_typedef(underlying_type); + return add_typedef(underlying_type, recursion_depth); return underlying_type; } @@ -568,14 +574,16 @@ const clang::RecordDecl::field_range abi_generator::get_struct_fields(const clan return record_type->getDecl()->fields(); } -string abi_generator::add_vector(const clang::QualType& vqt) { +string abi_generator::add_vector(const clang::QualType& vqt, size_t recursion_depth) { + + ABI_ASSERT( ++recursion_depth < max_recursion_depth, "recursive definition, max_recursion_depth" ); clang::QualType qt(get_named_type_if_elaborated(vqt)); auto vector_element_type = get_vector_element_type(qt); ABI_ASSERT(!is_vector(vector_element_type), "Only one-dimensional arrays are supported"); - add_type(vector_element_type); + add_type(vector_element_type, recursion_depth); auto vector_element_type_str = translate_type(get_type_name(vector_element_type)); vector_element_type_str += "[]"; @@ -583,7 +591,9 @@ string abi_generator::add_vector(const clang::QualType& vqt) { return vector_element_type_str; } -string abi_generator::add_type(const clang::QualType& tqt) { +string abi_generator::add_type(const clang::QualType& tqt, size_t recursion_depth) { + + ABI_ASSERT( ++recursion_depth < max_recursion_depth, "recursive definition, max_recursion_depth" ); clang::QualType qt(get_named_type_if_elaborated(tqt)); @@ -596,7 +606,7 @@ string abi_generator::add_type(const clang::QualType& tqt) { } if( is_typedef(qt) ) { - qt = add_typedef(qt); + qt = add_typedef(qt, recursion_depth); if( is_builtin_type(translate_type(get_type_name(qt))) ) { return type_name; } @@ -604,12 +614,12 @@ string abi_generator::add_type(const clang::QualType& tqt) { } if( is_vector(qt) ) { - auto vector_type_name = add_vector(qt); + auto vector_type_name = add_vector(qt, recursion_depth); return is_type_def ? type_name : vector_type_name; } if( is_struct(qt) ) { - return add_struct(qt, full_type_name); + return add_struct(qt, full_type_name, recursion_depth); } ABI_ASSERT(false, "types can only be: vector, struct, class or a built-in type. (${type}) ", ("type",get_type_name(qt))); @@ -623,7 +633,9 @@ clang::QualType abi_generator::get_named_type_if_elaborated(const clang::QualTyp return qt; } -string abi_generator::add_struct(const clang::QualType& sqt, string full_name) { +string abi_generator::add_struct(const clang::QualType& sqt, string full_name, size_t recursion_depth) { + + ABI_ASSERT( ++recursion_depth < max_recursion_depth, "recursive definition, max_recursion_depth" ); clang::QualType qt(get_named_type_if_elaborated(sqt)); @@ -653,7 +665,7 @@ string abi_generator::add_struct(const clang::QualType& sqt, string full_name) { const auto* record_type = base_qt->getAs(); if( record_type && is_struct(base_qt) && !record_type->getDecl()->field_empty() ) { ABI_ASSERT(total_bases == 0, "Multiple inheritance not supported - ${type}", ("type",full_name)); - base_name = add_type(base_qt); + base_name = add_type(base_qt, recursion_depth); ++total_bases; } ++bitr; @@ -664,7 +676,7 @@ string abi_generator::add_struct(const clang::QualType& sqt, string full_name) { clang::QualType qt = field->getType(); string field_name = field->getNameAsString(); - string field_type_name = add_type(qt); + string field_type_name = add_type(qt, recursion_depth); field_def struct_field{field_name, field_type_name}; ABI_ASSERT(is_builtin_type(get_vector_element_type(struct_field.type)) diff --git a/libraries/abi_generator/include/eosio/abi_generator/abi_generator.hpp b/libraries/abi_generator/include/eosio/abi_generator/abi_generator.hpp index 093409d22ba2547e4356f5421bccc106708b3663..cdb5d0ffe3e2fef01f9bf85b853ed1ce404116e9 100644 --- a/libraries/abi_generator/include/eosio/abi_generator/abi_generator.hpp +++ b/libraries/abi_generator/include/eosio/abi_generator/abi_generator.hpp @@ -159,7 +159,8 @@ namespace eosio { * @brief Generates eosio::abi_def struct handling events from ASTConsumer */ class abi_generator { - private: + private: + static constexpr size_t max_recursion_depth = 25; // arbitrary depth to prevent infinite recursion bool verbose; int optimizations; abi_def* output; @@ -171,6 +172,7 @@ namespace eosio { string target_contract; vector target_actions; ricardian_contracts rc; + public: enum optimization { @@ -178,7 +180,8 @@ namespace eosio { }; abi_generator() - :optimizations(0) + : verbose(false) + , optimizations(0) , output(nullptr) , compiler_instance(nullptr) , ast_context(nullptr) @@ -283,17 +286,17 @@ namespace eosio { string decl_to_string(clang::Decl* d); bool is_typedef(const clang::QualType& qt); - QualType add_typedef(const clang::QualType& qt); + QualType add_typedef(const clang::QualType& qt, size_t recursion_depth); bool is_vector(const clang::QualType& qt); bool is_vector(const string& type_name); - string add_vector(const clang::QualType& qt); + string add_vector(const clang::QualType& qt, size_t recursion_depth); bool is_struct(const clang::QualType& qt); - string add_struct(const clang::QualType& qt, string full_type_name=""); + string add_struct(const clang::QualType& qt, string full_type_name, size_t recursion_depth); string get_type_name(const clang::QualType& qt, bool no_namespace); - string add_type(const clang::QualType& tqt); + string add_type(const clang::QualType& tqt, size_t recursion_depth); bool is_elaborated(const clang::QualType& qt); bool is_struct_specialization(const clang::QualType& qt); diff --git a/unittests/abi_tests.cpp b/unittests/abi_tests.cpp index bbfaa15072a039df75d0967251a412450a1797a0..e4c7b5ea5c2c72d01537ec7b85f7c71b283e0a69 100644 --- a/unittests/abi_tests.cpp +++ b/unittests/abi_tests.cpp @@ -3297,6 +3297,31 @@ BOOST_AUTO_TEST_CASE(abi_type_redefine_to_name) } FC_LOG_AND_RETHROW() } +BOOST_AUTO_TEST_CASE(abi_type_nested_in_vector) +{ try { + // inifinite loop in types + const char* repeat_abi = R"=====( + { + "types": [], + "structs": [{ + "name": "store_t", + "base": "", + "fields": [{ + "name": "id", + "type": "uint64" + },{ + "name": "childs", + "type": "store_t[]" + }], + "actions": [], + "tables": [] + } + )====="; + + BOOST_CHECK_THROW( abi_serializer abis(fc::json::from_string(repeat_abi).as()), fc::exception ); + +} FC_LOG_AND_RETHROW() } + BOOST_AUTO_TEST_CASE(abi_account_name_in_eosio_abi) { try { // inifinite loop in types