From e77c10f563574945e061b212211106055131af61 Mon Sep 17 00:00:00 2001 From: Hsin-Yi Chen Date: Fri, 2 Dec 2022 20:33:27 +0800 Subject: [PATCH] Allow extending qualifiers of function parameters and return values `header-abi-diff --allow-extensions` allows function parameters to be more qualified, and return types to be less qualified. The ABI tools follows the qualifier conversion rules in C++. The ABI tool only allows extending the qualifiers of the functions that have corresponding symbols. The qualifiers of the other types, such as function pointers, class members, and global variables, must be identical between the old and new ABIs. Test: ./test.py Bug: 259148872 Change-Id: I227f6ed774cc88009713acce955e35f1c3cff1ca --- .../src/diff/abi_diff_wrappers.cpp | 3 +- .../src/repr/abi_diff_helpers.cpp | 221 ++++++++++++--- .../src/repr/abi_diff_helpers.h | 40 +-- .../src/repr/ir_diff_representation.h | 11 +- .../src/repr/protobuf/ir_diff_dumper.cpp | 6 +- .../src/repr/protobuf/proto/abi_diff.proto | 1 + .../function_extensions/include/base.h | 11 + .../function_extensions/include/extensions.h | 11 + .../integration/function_extensions/map.txt | 9 + vndk/tools/header-checker/tests/module.py | 18 ++ .../liballowed_function_extensions.so.lsdump | 254 ++++++++++++++++++ .../arm64/libfunction_extensions.so.lsdump | 244 +++++++++++++++++ vndk/tools/header-checker/tests/test.py | 15 ++ 13 files changed, 781 insertions(+), 63 deletions(-) create mode 100644 vndk/tools/header-checker/tests/integration/function_extensions/include/base.h create mode 100644 vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h create mode 100644 vndk/tools/header-checker/tests/integration/function_extensions/map.txt create mode 100644 vndk/tools/header-checker/tests/reference_dumps/arm64/liballowed_function_extensions.so.lsdump create mode 100644 vndk/tools/header-checker/tests/reference_dumps/arm64/libfunction_extensions.so.lsdump diff --git a/vndk/tools/header-checker/src/diff/abi_diff_wrappers.cpp b/vndk/tools/header-checker/src/diff/abi_diff_wrappers.cpp index a58d6a248..eeaa8819f 100644 --- a/vndk/tools/header-checker/src/diff/abi_diff_wrappers.cpp +++ b/vndk/tools/header-checker/src/diff/abi_diff_wrappers.cpp @@ -93,7 +93,8 @@ bool DiffWrapper::DumpDiff( repr::FunctionIR new_function = *newp_; ReplaceTypeIdsWithTypeNames(old_types_, &old_function); ReplaceTypeIdsWithTypeNames(new_types_, &new_function); - repr::FunctionDiffIR function_diff_ir(&old_function, &new_function); + repr::FunctionDiffIR function_diff_ir(&old_function, &new_function, + function_type_diff.IsExtension()); function_diff_ir.SetName(oldp_->GetName()); return ir_diff_dumper_->AddDiffMessageIR(&function_diff_ir, Unwind(&type_queue), diff_kind); diff --git a/vndk/tools/header-checker/src/repr/abi_diff_helpers.cpp b/vndk/tools/header-checker/src/repr/abi_diff_helpers.cpp index 425bc9ba0..53f539516 100644 --- a/vndk/tools/header-checker/src/repr/abi_diff_helpers.cpp +++ b/vndk/tools/header-checker/src/repr/abi_diff_helpers.cpp @@ -281,20 +281,6 @@ static bool CompareSizeAndAlignment(const TypeIR *old_type, old_type->GetAlignment() == new_type->GetAlignment(); } -bool AbiDiffHelper::AreTypeSizeAndAlignmentEqual( - const std::string &old_type_id, const std::string &new_type_id) const { - AbiElementMap::const_iterator old_it = - old_types_.find(old_type_id); - AbiElementMap::const_iterator new_it = - new_types_.find(new_type_id); - - if (old_it == old_types_.end() || new_it == new_types_.end()) { - return AreOpaqueTypesEqual(old_type_id, new_type_id); - } - - return CompareSizeAndAlignment(old_it->second, new_it->second); -} - DiffStatusPair> AbiDiffHelper::CompareCommonRecordFields( const RecordFieldIR *old_field, @@ -522,14 +508,13 @@ AbiDiffHelper::FixupDiffedFieldTypeIds( DiffStatus AbiDiffHelper::CompareFunctionTypes( const CFunctionLikeIR *old_type, const CFunctionLikeIR *new_type, std::deque *type_queue, DiffMessageIR::DiffKind diff_kind) { - DiffStatus param_diffs = CompareFunctionParameters(old_type->GetParameters(), - new_type->GetParameters(), - type_queue, diff_kind); - DiffStatus return_type_diff = CompareParameterOrReturnType( - old_type->GetReturnType(), new_type->GetReturnType(), type_queue, - diff_kind); - - return param_diffs.CombineWith(return_type_diff); + DiffStatus status = CompareFunctionParameters(old_type->GetParameters(), + new_type->GetParameters(), + type_queue, diff_kind); + status.CombineWith(CompareReturnTypes(old_type->GetReturnType(), + new_type->GetReturnType(), type_queue, + diff_kind)); + return status; } DiffStatus AbiDiffHelper::CompareRecordTypes( @@ -696,36 +681,186 @@ DiffStatus AbiDiffHelper::CompareBuiltinTypes( DiffStatus AbiDiffHelper::CompareFunctionParameters( const std::vector &old_parameters, const std::vector &new_parameters, - std::deque *type_queue, - DiffMessageIR::DiffKind diff_kind) { + std::deque *type_queue, DiffMessageIR::DiffKind diff_kind) { size_t old_parameters_size = old_parameters.size(); if (old_parameters_size != new_parameters.size()) { return DiffStatus::kDirectDiff; } - uint64_t i = 0; - while (i < old_parameters_size) { + DiffStatus result = DiffStatus::kNoDiff; + for (uint64_t i = 0; i < old_parameters_size; i++) { const ParamIR &old_parameter = old_parameters.at(i); const ParamIR &new_parameter = new_parameters.at(i); - if (CompareParameterOrReturnType(old_parameter.GetReferencedType(), - new_parameter.GetReferencedType(), - type_queue, diff_kind) - .IsDirectDiff() || - (old_parameter.GetIsDefault() != new_parameter.GetIsDefault())) { - return DiffStatus::kDirectDiff; + result.CombineWith(CompareParameterTypes(old_parameter.GetReferencedType(), + new_parameter.GetReferencedType(), + type_queue, diff_kind)); + if (old_parameter.GetIsDefault() != new_parameter.GetIsDefault()) { + result.CombineWith(DiffStatus::kDirectDiff); } - i++; } - return DiffStatus::kNoDiff; + return result; } -DiffStatus AbiDiffHelper::CompareParameterOrReturnType( +static const TypeIR *FindTypeById( + const AbiElementMap &type_graph, + const std::string &type_id) { + auto it = type_graph.find(type_id); + return it == type_graph.end() ? nullptr : it->second; +} + +struct Qualifiers { + bool is_const = false; + bool is_restricted = false; + bool is_volatile = false; + + bool operator==(const Qualifiers &other) const { + return (is_const == other.is_const && + is_restricted == other.is_restricted && + is_volatile == other.is_volatile); + } + + bool operator!=(const Qualifiers &other) const { return !(*this == other); } +}; + +// This function returns the qualifiers and sets type_id to the unqalified or +// opaque type. +static Qualifiers ResolveQualifiers(const AbiElementMap &types, + std::string &type_id) { + Qualifiers qual; + while (true) { + const TypeIR *type_ir = FindTypeById(types, type_id); + if (type_ir == nullptr || + type_ir->GetKind() != LinkableMessageKind::QualifiedTypeKind) { + return qual; + } + const QualifiedTypeIR *qualified_type_ir = + static_cast(type_ir); + qual.is_const |= qualified_type_ir->IsConst(); + qual.is_restricted |= qualified_type_ir->IsRestricted(); + qual.is_volatile |= qualified_type_ir->IsVolatile(); + type_id = qualified_type_ir->GetReferencedType(); + } +} + +// This function returns whether the old_type can be implicitly casted to +// new_type. It resolves qualified pointers and references until it reaches a +// type that does not reference other types. It does not compare the final +// referenced types. +// +// If this function returns true, old_type_id and new_type_id are set to the +// final referenced types. are_qualifiers_equal represents whether the +// qualifiers are exactly the same. +// +// If this function returns false, old_type_id, new_type_id, and +// are_qualifiers_equal do not have valid values. +// +// This function follows C++ standard to determine whether qualifiers can be +// casted. The rules are described in +// Section 7.5 Qualification conversions [conv.qual] in C++17 standard +// and +// https://en.cppreference.com/w/cpp/language/implicit_conversion#Qualification_conversions +// Additionally, __restrict__ follows the same rules as const and volatile. +static bool ResolveImplicitlyConvertibleQualifiedReferences( + const AbiElementMap &old_types, + const AbiElementMap &new_types, std::string &old_type_id, + std::string &new_type_id, bool &are_qualifiers_equal) { + are_qualifiers_equal = true; + bool is_first_level = true; + bool is_const_since_second_level = true; + while (true) { + // Check qualifiers. + const Qualifiers old_qual = ResolveQualifiers(old_types, old_type_id); + const Qualifiers new_qual = ResolveQualifiers(new_types, new_type_id); + are_qualifiers_equal &= (old_qual == new_qual); + if (is_first_level) { + is_first_level = false; + } else { + if ((old_qual.is_const && !new_qual.is_const) || + (old_qual.is_restricted && !new_qual.is_restricted) || + (old_qual.is_volatile && !new_qual.is_volatile)) { + return false; + } + if (!is_const_since_second_level && old_qual != new_qual) { + return false; + } + is_const_since_second_level &= new_qual.is_const; + } + // Stop if the unqualified types differ or don't reference other types. + const TypeIR *old_type = FindTypeById(old_types, old_type_id); + const TypeIR *new_type = FindTypeById(new_types, new_type_id); + if (old_type == nullptr || new_type == nullptr) { + return true; + } + const LinkableMessageKind kind = old_type->GetKind(); + if (kind != new_type->GetKind()) { + return true; + } + if (kind != LinkableMessageKind::PointerTypeKind && + kind != LinkableMessageKind::LvalueReferenceTypeKind && + kind != LinkableMessageKind::RvalueReferenceTypeKind) { + return true; + } + // Get the referenced types. + old_type_id = old_type->GetReferencedType(); + new_type_id = new_type->GetReferencedType(); + } +} + +DiffStatus AbiDiffHelper::CompareParameterTypes( const std::string &old_type_id, const std::string &new_type_id, std::deque *type_queue, DiffMessageIR::DiffKind diff_kind) { - if (!AreTypeSizeAndAlignmentEqual(old_type_id, new_type_id)) { + // Compare size and alignment. + const TypeIR *old_type_ir = FindTypeById(old_types_, old_type_id); + const TypeIR *new_type_ir = FindTypeById(new_types_, new_type_id); + if (old_type_ir != nullptr && new_type_ir != nullptr && + !CompareSizeAndAlignment(old_type_ir, new_type_ir)) { return DiffStatus::kDirectDiff; } - return CompareAndDumpTypeDiff(old_type_id, new_type_id, type_queue, - diff_kind); + // Allow the new parameter to be more qualified than the old parameter. + std::string old_referenced_type_id = old_type_id; + std::string new_referenced_type_id = new_type_id; + bool are_qualifiers_equal; + if (!ResolveImplicitlyConvertibleQualifiedReferences( + old_types_, new_types_, old_referenced_type_id, + new_referenced_type_id, are_qualifiers_equal)) { + return DiffStatus::kDirectDiff; + } + // Compare the unqualified referenced types. + DiffStatus result = CompareAndDumpTypeDiff( + old_referenced_type_id, new_referenced_type_id, type_queue, diff_kind); + if (!are_qualifiers_equal) { + result.CombineWith(DiffStatus::kDirectExt); + } + return result; +} + +// This function is the same as CompareParameterTypes except for the arguments +// to ResolveImplicitlyConvertibleQualifiedReferences. +DiffStatus AbiDiffHelper::CompareReturnTypes( + const std::string &old_type_id, const std::string &new_type_id, + std::deque *type_queue, DiffMessageIR::DiffKind diff_kind) { + // Compare size and alignment. + const TypeIR *old_type_ir = FindTypeById(old_types_, old_type_id); + const TypeIR *new_type_ir = FindTypeById(new_types_, new_type_id); + if (old_type_ir != nullptr && new_type_ir != nullptr && + !CompareSizeAndAlignment(old_type_ir, new_type_ir)) { + return DiffStatus::kDirectDiff; + } + // Allow the new return type to be less qualified than the old return type. + std::string old_referenced_type_id = old_type_id; + std::string new_referenced_type_id = new_type_id; + bool are_qualifiers_equal; + if (!ResolveImplicitlyConvertibleQualifiedReferences( + new_types_, old_types_, new_referenced_type_id, + old_referenced_type_id, are_qualifiers_equal)) { + return DiffStatus::kDirectDiff; + } + // Compare the unqualified referenced types. + DiffStatus result = CompareAndDumpTypeDiff( + old_referenced_type_id, new_referenced_type_id, type_queue, diff_kind); + if (!are_qualifiers_equal) { + result.CombineWith(DiffStatus::kDirectExt); + } + return result; } DiffStatus AbiDiffHelper::CompareAndDumpTypeDiff( @@ -786,10 +921,14 @@ DiffStatus AbiDiffHelper::CompareAndDumpTypeDiff( } if (kind == LinkableMessageKind::FunctionTypeKind) { - return CompareFunctionTypes( + DiffStatus result = CompareFunctionTypes( static_cast(old_type), - static_cast(new_type), - type_queue, diff_kind); + static_cast(new_type), type_queue, diff_kind); + // Do not allow extending function pointers, function references, etc. + if (result.IsExtension()) { + result.CombineWith(DiffStatus::kDirectDiff); + } + return result; } return DiffStatus::kNoDiff; } diff --git a/vndk/tools/header-checker/src/repr/abi_diff_helpers.h b/vndk/tools/header-checker/src/repr/abi_diff_helpers.h index 236dfda97..f421b6ab9 100644 --- a/vndk/tools/header-checker/src/repr/abi_diff_helpers.h +++ b/vndk/tools/header-checker/src/repr/abi_diff_helpers.h @@ -36,8 +36,11 @@ class DiffStatus { kNoDiff = 0, // The diff has been added to the IRDiffDumper. kIndirectDiff = 1, + // The diff has not been added to the IRDiffDumper, and the new ABI is + // an extension to the old ABI. + kDirectExt = 2, // The diff has not been added to the IRDiffDumper. - kDirectDiff = 2, + kDirectDiff = 3, }; // Allow implicit conversion. @@ -45,7 +48,11 @@ class DiffStatus { bool HasDiff() const { return status_ != kNoDiff; } - bool IsDirectDiff() const { return status_ == kDirectDiff; } + bool IsDirectDiff() const { + return status_ == kDirectDiff || status_ == kDirectExt; + } + + bool IsExtension() const { return status_ == kDirectExt; } DiffStatus &CombineWith(DiffStatus other) { status_ = std::max(status_, other.status_); @@ -93,9 +100,6 @@ class AbiDiffHelper { bool AreOpaqueTypesEqual(const std::string &old_type_str, const std::string &new_type_str) const; - bool AreTypeSizeAndAlignmentEqual(const std::string &old_type_str, - const std::string &new_type_str) const; - DiffStatus CompareAndDumpTypeDiff( const std::string &old_type_str, const std::string &new_type_str, std::deque *type_queue = nullptr, @@ -123,17 +127,6 @@ class AbiDiffHelper { std::deque *type_queue, DiffMessageIR::DiffKind diff_kind); - DiffStatus CompareFunctionParameters( - const std::vector &old_parameters, - const std::vector &new_parameters, - std::deque *type_queue, - IRDiffDumper::DiffKind diff_kind); - - DiffStatus CompareParameterOrReturnType(const std::string &old_type_id, - const std::string &new_type_id, - std::deque *type_queue, - IRDiffDumper::DiffKind diff_kind); - DiffStatus CompareTemplateInfo( const std::vector &old_template_elements, const std::vector &new_template_elements, @@ -211,6 +204,21 @@ class AbiDiffHelper { const VTableComponentIR &old_component, const VTableComponentIR &new_component); + DiffStatus CompareFunctionParameters( + const std::vector &old_parameters, + const std::vector &new_parameters, + std::deque *type_queue, IRDiffDumper::DiffKind diff_kind); + + DiffStatus CompareParameterTypes(const std::string &old_type_id, + const std::string &new_type_id, + std::deque *type_queue, + IRDiffDumper::DiffKind diff_kind); + + DiffStatus CompareReturnTypes(const std::string &old_type_id, + const std::string &new_type_id, + std::deque *type_queue, + IRDiffDumper::DiffKind diff_kind); + template bool AddToDiff(DiffType *mutable_diff, const DiffElement *oldp, const DiffElement *newp, diff --git a/vndk/tools/header-checker/src/repr/ir_diff_representation.h b/vndk/tools/header-checker/src/repr/ir_diff_representation.h index 699170876..81f8aff61 100644 --- a/vndk/tools/header-checker/src/repr/ir_diff_representation.h +++ b/vndk/tools/header-checker/src/repr/ir_diff_representation.h @@ -347,9 +347,11 @@ class GlobalVarDiffIR : public DiffMessageIR { class FunctionDiffIR : public DiffMessageIR { public: - FunctionDiffIR(const FunctionIR *old_function, - const FunctionIR *new_function) - : old_function_(old_function), new_function_(new_function) {} + FunctionDiffIR(const FunctionIR *old_function, const FunctionIR *new_function, + bool is_extended) + : old_function_(old_function), + new_function_(new_function), + is_extended_(is_extended) {} LinkableMessageKind Kind() const override { return LinkableMessageKind::FunctionKind; @@ -363,9 +365,12 @@ class FunctionDiffIR : public DiffMessageIR { return new_function_; } + bool IsExtended() const { return is_extended_; } + protected: const FunctionIR *old_function_; const FunctionIR *new_function_; + const bool is_extended_; }; diff --git a/vndk/tools/header-checker/src/repr/protobuf/ir_diff_dumper.cpp b/vndk/tools/header-checker/src/repr/protobuf/ir_diff_dumper.cpp index a0eb957d2..ecc2ac37d 100644 --- a/vndk/tools/header-checker/src/repr/protobuf/ir_diff_dumper.cpp +++ b/vndk/tools/header-checker/src/repr/protobuf/ir_diff_dumper.cpp @@ -55,7 +55,8 @@ CompatibilityStatusIR ProtobufIRDiffDumper::GetCompatibilityStatusIR() { if (diff_tu_->enum_type_extension_diffs().size() != 0 || diff_tu_->functions_added().size() != 0 || diff_tu_->global_vars_added().size() != 0 || - diff_tu_->record_type_extension_diffs().size() != 0) { + diff_tu_->record_type_extension_diffs().size() != 0 || + diff_tu_->function_extension_diffs().size() != 0) { combined_status = combined_status | CompatibilityStatusIR::Extension; } @@ -315,7 +316,8 @@ bool ProtobufIRDiffDumper::AddFunctionDiffIR( const FunctionDiffIR *function_diff_ir, const std::string &type_stack, DiffKind diff_kind) { abi_diff::FunctionDeclDiff *added_function_diff = - diff_tu_->add_function_diffs(); + function_diff_ir->IsExtended() ? diff_tu_->add_function_extension_diffs() + : diff_tu_->add_function_diffs(); if (!added_function_diff) { return false; } diff --git a/vndk/tools/header-checker/src/repr/protobuf/proto/abi_diff.proto b/vndk/tools/header-checker/src/repr/protobuf/proto/abi_diff.proto index 384fccbe4..8d0f72f7b 100644 --- a/vndk/tools/header-checker/src/repr/protobuf/proto/abi_diff.proto +++ b/vndk/tools/header-checker/src/repr/protobuf/proto/abi_diff.proto @@ -100,6 +100,7 @@ message TranslationUnitDiff { // Functions and Global variables. repeated FunctionDeclDiff function_diffs = 13; + repeated FunctionDeclDiff function_extension_diffs = 26; repeated GlobalVarDeclDiff global_var_diffs = 14; repeated abi_dump.FunctionDecl functions_removed = 15; diff --git a/vndk/tools/header-checker/tests/integration/function_extensions/include/base.h b/vndk/tools/header-checker/tests/integration/function_extensions/include/base.h new file mode 100644 index 000000000..d25e67ffa --- /dev/null +++ b/vndk/tools/header-checker/tests/integration/function_extensions/include/base.h @@ -0,0 +1,11 @@ +struct Struct; + +extern "C" { +void ConstParameter(char (&)[2]); +void VolatileParameter(Struct &&); +void Restrict(char *__restrict__); +const char *const *MultipleConst(char **); +} + +const char &ConstReturn(); +volatile Struct &&VolatileReturn(); diff --git a/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h b/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h new file mode 100644 index 000000000..585cc1ec4 --- /dev/null +++ b/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h @@ -0,0 +1,11 @@ +struct Struct; + +extern "C" { +void ConstParameter(const char (&)[2]); +void VolatileParameter(volatile Struct &&); +void Restrict(char *); +char **MultipleConst(char const *const *const); +} + +char &ConstReturn(); +Struct &&VolatileReturn(); diff --git a/vndk/tools/header-checker/tests/integration/function_extensions/map.txt b/vndk/tools/header-checker/tests/integration/function_extensions/map.txt new file mode 100644 index 000000000..7fc0fd3e6 --- /dev/null +++ b/vndk/tools/header-checker/tests/integration/function_extensions/map.txt @@ -0,0 +1,9 @@ +libfunction_extensions { + global: + ConstParameter; + VolatileParameter; + Restrict; + MultipleConst; + _Z11ConstReturnv; + _Z14VolatileReturnv; +}; diff --git a/vndk/tools/header-checker/tests/module.py b/vndk/tools/header-checker/tests/module.py index 2688a2165..df29a01d5 100755 --- a/vndk/tools/header-checker/tests/module.py +++ b/vndk/tools/header-checker/tests/module.py @@ -736,6 +736,24 @@ TEST_MODULES = [ linker_flags=['-output-format', 'Json'], has_reference_dump=True, ), + LsdumpModule( + name='libfunction_extensions', + arch='arm64', + srcs=['integration/function_extensions/include/base.h'], + version_script='integration/function_extensions/map.txt', + export_include_dirs=['integration/function_extensions/include'], + linker_flags=['-output-format', 'Json'], + has_reference_dump=True, + ), + LsdumpModule( + name='liballowed_function_extensions', + arch='arm64', + srcs=['integration/function_extensions/include/extensions.h'], + version_script='integration/function_extensions/map.txt', + export_include_dirs=['integration/function_extensions/include'], + linker_flags=['-output-format', 'Json'], + has_reference_dump=True, + ), ] TEST_MODULES = {m.name: m for m in TEST_MODULES} diff --git a/vndk/tools/header-checker/tests/reference_dumps/arm64/liballowed_function_extensions.so.lsdump b/vndk/tools/header-checker/tests/reference_dumps/arm64/liballowed_function_extensions.so.lsdump new file mode 100644 index 000000000..5a3620860 --- /dev/null +++ b/vndk/tools/header-checker/tests/reference_dumps/arm64/liballowed_function_extensions.so.lsdump @@ -0,0 +1,254 @@ +{ + "array_types" : + [ + { + "alignment" : 1, + "linker_set_key" : "_ZTIA2_c", + "name" : "char[2]", + "referenced_type" : "_ZTIc", + "self_type" : "_ZTIA2_c", + "size" : 2, + "source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h" + } + ], + "builtin_types" : + [ + { + "alignment" : 1, + "is_integral" : true, + "is_unsigned" : true, + "linker_set_key" : "_ZTIc", + "name" : "char", + "referenced_type" : "_ZTIc", + "self_type" : "_ZTIc", + "size" : 1 + }, + { + "linker_set_key" : "_ZTIv", + "name" : "void", + "referenced_type" : "_ZTIv", + "self_type" : "_ZTIv" + } + ], + "elf_functions" : + [ + { + "name" : "ConstParameter" + }, + { + "name" : "MultipleConst" + }, + { + "name" : "Restrict" + }, + { + "name" : "VolatileParameter" + }, + { + "name" : "_Z11ConstReturnv" + }, + { + "name" : "_Z14VolatileReturnv" + } + ], + "elf_objects" : [], + "enum_types" : [], + "function_types" : [], + "functions" : + [ + { + "function_name" : "ConstParameter", + "linker_set_key" : "ConstParameter", + "parameters" : + [ + { + "referenced_type" : "_ZTIRA2_Kc" + } + ], + "return_type" : "_ZTIv", + "source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h" + }, + { + "function_name" : "MultipleConst", + "linker_set_key" : "MultipleConst", + "parameters" : + [ + { + "referenced_type" : "_ZTIKPKPKc" + } + ], + "return_type" : "_ZTIPPc", + "source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h" + }, + { + "function_name" : "Restrict", + "linker_set_key" : "Restrict", + "parameters" : + [ + { + "referenced_type" : "_ZTIPc" + } + ], + "return_type" : "_ZTIv", + "source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h" + }, + { + "function_name" : "VolatileParameter", + "linker_set_key" : "VolatileParameter", + "parameters" : + [ + { + "referenced_type" : "_ZTIOV6Struct" + } + ], + "return_type" : "_ZTIv", + "source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h" + }, + { + "function_name" : "ConstReturn", + "linker_set_key" : "_Z11ConstReturnv", + "return_type" : "_ZTIRc", + "source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h" + }, + { + "function_name" : "VolatileReturn", + "linker_set_key" : "_Z14VolatileReturnv", + "return_type" : "_ZTIO6Struct", + "source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h" + } + ], + "global_vars" : [], + "lvalue_reference_types" : + [ + { + "alignment" : 8, + "linker_set_key" : "_ZTIRA2_Kc", + "name" : "const char (&)[2]", + "referenced_type" : "_ZTIA2_Kc", + "self_type" : "_ZTIRA2_Kc", + "size" : 8, + "source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h" + }, + { + "alignment" : 8, + "linker_set_key" : "_ZTIRc", + "name" : "char &", + "referenced_type" : "_ZTIc", + "self_type" : "_ZTIRc", + "size" : 8, + "source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h" + } + ], + "pointer_types" : + [ + { + "alignment" : 8, + "linker_set_key" : "_ZTIPKPKc", + "name" : "const char *const *", + "referenced_type" : "_ZTIKPKc", + "self_type" : "_ZTIPKPKc", + "size" : 8, + "source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h" + }, + { + "alignment" : 8, + "linker_set_key" : "_ZTIPKc", + "name" : "const char *", + "referenced_type" : "_ZTIKc", + "self_type" : "_ZTIPKc", + "size" : 8, + "source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h" + }, + { + "alignment" : 8, + "linker_set_key" : "_ZTIPPc", + "name" : "char **", + "referenced_type" : "_ZTIPc", + "self_type" : "_ZTIPPc", + "size" : 8, + "source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h" + }, + { + "alignment" : 8, + "linker_set_key" : "_ZTIPc", + "name" : "char *", + "referenced_type" : "_ZTIc", + "self_type" : "_ZTIPc", + "size" : 8, + "source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h" + } + ], + "qualified_types" : + [ + { + "alignment" : 1, + "is_const" : true, + "linker_set_key" : "_ZTIA2_Kc", + "name" : "const char[2]", + "referenced_type" : "_ZTIA2_c", + "self_type" : "_ZTIA2_Kc", + "size" : 2, + "source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h" + }, + { + "alignment" : 8, + "is_const" : true, + "linker_set_key" : "_ZTIKPKPKc", + "name" : "const char *const *const", + "referenced_type" : "_ZTIPKPKc", + "self_type" : "_ZTIKPKPKc", + "size" : 8, + "source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h" + }, + { + "alignment" : 8, + "is_const" : true, + "linker_set_key" : "_ZTIKPKc", + "name" : "const char *const", + "referenced_type" : "_ZTIPKc", + "self_type" : "_ZTIKPKc", + "size" : 8, + "source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h" + }, + { + "alignment" : 1, + "is_const" : true, + "linker_set_key" : "_ZTIKc", + "name" : "const char", + "referenced_type" : "_ZTIc", + "self_type" : "_ZTIKc", + "size" : 1, + "source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h" + }, + { + "is_volatile" : true, + "linker_set_key" : "_ZTIV6Struct", + "name" : "volatile Struct", + "referenced_type" : "_ZTI6Struct", + "self_type" : "_ZTIV6Struct", + "source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h" + } + ], + "record_types" : [], + "rvalue_reference_types" : + [ + { + "alignment" : 8, + "linker_set_key" : "_ZTIO6Struct", + "name" : "Struct &&", + "referenced_type" : "_ZTI6Struct", + "self_type" : "_ZTIO6Struct", + "size" : 8, + "source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h" + }, + { + "alignment" : 8, + "linker_set_key" : "_ZTIOV6Struct", + "name" : "volatile Struct &&", + "referenced_type" : "_ZTIV6Struct", + "self_type" : "_ZTIOV6Struct", + "size" : 8, + "source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h" + } + ] +} diff --git a/vndk/tools/header-checker/tests/reference_dumps/arm64/libfunction_extensions.so.lsdump b/vndk/tools/header-checker/tests/reference_dumps/arm64/libfunction_extensions.so.lsdump new file mode 100644 index 000000000..9ad40a0d1 --- /dev/null +++ b/vndk/tools/header-checker/tests/reference_dumps/arm64/libfunction_extensions.so.lsdump @@ -0,0 +1,244 @@ +{ + "array_types" : + [ + { + "alignment" : 1, + "linker_set_key" : "_ZTIA2_c", + "name" : "char[2]", + "referenced_type" : "_ZTIc", + "self_type" : "_ZTIA2_c", + "size" : 2, + "source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/base.h" + } + ], + "builtin_types" : + [ + { + "alignment" : 1, + "is_integral" : true, + "is_unsigned" : true, + "linker_set_key" : "_ZTIc", + "name" : "char", + "referenced_type" : "_ZTIc", + "self_type" : "_ZTIc", + "size" : 1 + }, + { + "linker_set_key" : "_ZTIv", + "name" : "void", + "referenced_type" : "_ZTIv", + "self_type" : "_ZTIv" + } + ], + "elf_functions" : + [ + { + "name" : "ConstParameter" + }, + { + "name" : "MultipleConst" + }, + { + "name" : "Restrict" + }, + { + "name" : "VolatileParameter" + }, + { + "name" : "_Z11ConstReturnv" + }, + { + "name" : "_Z14VolatileReturnv" + } + ], + "elf_objects" : [], + "enum_types" : [], + "function_types" : [], + "functions" : + [ + { + "function_name" : "ConstParameter", + "linker_set_key" : "ConstParameter", + "parameters" : + [ + { + "referenced_type" : "_ZTIRA2_c" + } + ], + "return_type" : "_ZTIv", + "source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/base.h" + }, + { + "function_name" : "MultipleConst", + "linker_set_key" : "MultipleConst", + "parameters" : + [ + { + "referenced_type" : "_ZTIPPc" + } + ], + "return_type" : "_ZTIPKPKc", + "source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/base.h" + }, + { + "function_name" : "Restrict", + "linker_set_key" : "Restrict", + "parameters" : + [ + { + "referenced_type" : "_ZTIrPc" + } + ], + "return_type" : "_ZTIv", + "source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/base.h" + }, + { + "function_name" : "VolatileParameter", + "linker_set_key" : "VolatileParameter", + "parameters" : + [ + { + "referenced_type" : "_ZTIO6Struct" + } + ], + "return_type" : "_ZTIv", + "source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/base.h" + }, + { + "function_name" : "ConstReturn", + "linker_set_key" : "_Z11ConstReturnv", + "return_type" : "_ZTIRKc", + "source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/base.h" + }, + { + "function_name" : "VolatileReturn", + "linker_set_key" : "_Z14VolatileReturnv", + "return_type" : "_ZTIOV6Struct", + "source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/base.h" + } + ], + "global_vars" : [], + "lvalue_reference_types" : + [ + { + "alignment" : 8, + "linker_set_key" : "_ZTIRA2_c", + "name" : "char (&)[2]", + "referenced_type" : "_ZTIA2_c", + "self_type" : "_ZTIRA2_c", + "size" : 8, + "source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/base.h" + }, + { + "alignment" : 8, + "linker_set_key" : "_ZTIRKc", + "name" : "const char &", + "referenced_type" : "_ZTIKc", + "self_type" : "_ZTIRKc", + "size" : 8, + "source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/base.h" + } + ], + "pointer_types" : + [ + { + "alignment" : 8, + "linker_set_key" : "_ZTIPKPKc", + "name" : "const char *const *", + "referenced_type" : "_ZTIKPKc", + "self_type" : "_ZTIPKPKc", + "size" : 8, + "source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/base.h" + }, + { + "alignment" : 8, + "linker_set_key" : "_ZTIPKc", + "name" : "const char *", + "referenced_type" : "_ZTIKc", + "self_type" : "_ZTIPKc", + "size" : 8, + "source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/base.h" + }, + { + "alignment" : 8, + "linker_set_key" : "_ZTIPPc", + "name" : "char **", + "referenced_type" : "_ZTIPc", + "self_type" : "_ZTIPPc", + "size" : 8, + "source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/base.h" + }, + { + "alignment" : 8, + "linker_set_key" : "_ZTIPc", + "name" : "char *", + "referenced_type" : "_ZTIc", + "self_type" : "_ZTIPc", + "size" : 8, + "source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/base.h" + } + ], + "qualified_types" : + [ + { + "alignment" : 8, + "is_const" : true, + "linker_set_key" : "_ZTIKPKc", + "name" : "const char *const", + "referenced_type" : "_ZTIPKc", + "self_type" : "_ZTIKPKc", + "size" : 8, + "source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/base.h" + }, + { + "alignment" : 1, + "is_const" : true, + "linker_set_key" : "_ZTIKc", + "name" : "const char", + "referenced_type" : "_ZTIc", + "self_type" : "_ZTIKc", + "size" : 1, + "source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/base.h" + }, + { + "is_volatile" : true, + "linker_set_key" : "_ZTIV6Struct", + "name" : "volatile Struct", + "referenced_type" : "_ZTI6Struct", + "self_type" : "_ZTIV6Struct", + "source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/base.h" + }, + { + "alignment" : 8, + "is_restricted" : true, + "linker_set_key" : "_ZTIrPc", + "name" : "char *__restrict", + "referenced_type" : "_ZTIPc", + "self_type" : "_ZTIrPc", + "size" : 8, + "source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/base.h" + } + ], + "record_types" : [], + "rvalue_reference_types" : + [ + { + "alignment" : 8, + "linker_set_key" : "_ZTIO6Struct", + "name" : "Struct &&", + "referenced_type" : "_ZTI6Struct", + "self_type" : "_ZTIO6Struct", + "size" : 8, + "source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/base.h" + }, + { + "alignment" : 8, + "linker_set_key" : "_ZTIOV6Struct", + "name" : "volatile Struct &&", + "referenced_type" : "_ZTIV6Struct", + "self_type" : "_ZTIOV6Struct", + "size" : 8, + "source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/base.h" + } + ] +} diff --git a/vndk/tools/header-checker/tests/test.py b/vndk/tools/header-checker/tests/test.py index cf2b3b9f8..80120339a 100755 --- a/vndk/tools/header-checker/tests/test.py +++ b/vndk/tools/header-checker/tests/test.py @@ -441,6 +441,21 @@ class HeaderCheckerTest(unittest.TestCase): flags=["-input-format-new", "Json", "-input-format-old", "Json"], create_old=False, create_new=False) + def test_function_extensions(self): + diff = self.prepare_and_run_abi_diff_all_archs( + "libfunction_extensions", "liballowed_function_extensions", 4, + flags=["-input-format-new", "Json", "-input-format-old", "Json"], + create_old=False, create_new=False) + self.assertEqual(6, diff.count('function_extension_diffs')) + + diff = self.prepare_and_run_abi_diff_all_archs( + "liballowed_function_extensions", "libfunction_extensions", 8, + flags=["-input-format-new", "Json", "-input-format-old", "Json"], + create_old=False, create_new=False) + # Adding and removing __restrict__ at the first level are extensions. + self.assertEqual(1, diff.count('function_extension_diffs')) + self.assertEqual(5, diff.count('function_diffs')) + if __name__ == '__main__': unittest.main()