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()