1.99.9: Fixed duplicated entries in the XML report, fixed false positives, etc.
diff --git a/abi-compliance-checker.pl b/abi-compliance-checker.pl
index 6716938..44aef2f 100755
--- a/abi-compliance-checker.pl
+++ b/abi-compliance-checker.pl
@@ -1,12 +1,12 @@
#!/usr/bin/perl
###########################################################################
-# ABI Compliance Checker (ACC) 1.99.8.5
+# ABI Compliance Checker (ACC) 1.99.9
# A tool for checking backward compatibility of a C/C++ library API
#
# Copyright (C) 2009-2010 The Linux Foundation
# Copyright (C) 2009-2011 Institute for System Programming, RAS
# Copyright (C) 2011-2012 Nokia Corporation and/or its subsidiary(-ies)
-# Copyright (C) 2011-2013 ROSA Laboratory
+# Copyright (C) 2011-2014 ROSA Laboratory
#
# Written by Andrey Ponomarenko
#
@@ -17,7 +17,7 @@
# REQUIREMENTS
# ============
# Linux
-# - G++ (3.0-4.7, recommended 4.5 or newer)
+# - G++ (3.0-4.7, 4.8.3, recommended 4.5 or newer)
# - GNU Binutils (readelf, c++filt, objdump)
# - Perl 5 (5.8 or newer)
# - Ctags (5.8 or newer)
@@ -64,10 +64,10 @@
use Data::Dumper;
use Config;
-my $TOOL_VERSION = "1.99.8.5";
+my $TOOL_VERSION = "1.99.9";
my $ABI_DUMP_VERSION = "3.2";
my $OLDEST_SUPPORTED_VERSION = "1.18";
-my $XML_REPORT_VERSION = "1.1";
+my $XML_REPORT_VERSION = "1.2";
my $XML_ABI_DUMP_VERSION = "1.2";
my $OSgroup = get_OSgroup();
my $ORIG_DIR = cwd();
@@ -93,7 +93,7 @@
$UserLang, $TargetHeadersPath, $BinaryOnly, $SourceOnly, $BinaryReportPath,
$SourceReportPath, $UseXML, $Browse, $OpenReport, $SortDump, $DumpFormat,
$ExtraInfo, $ExtraDump, $Force, $Tolerance, $Tolerant, $SkipSymbolsListPath,
-$CheckInfo, $Quick, $AffectLimit, $AllAffected, $CppIncompat);
+$CheckInfo, $Quick, $AffectLimit, $AllAffected, $CppIncompat, $SkipInternal);
my $CmdName = get_filename($0);
my %OS_LibExt = (
@@ -154,7 +154,7 @@
my $ShortUsage = "ABI Compliance Checker (ACC) $TOOL_VERSION
A tool for checking backward compatibility of a C/C++ library API
-Copyright (C) 2012 ROSA Laboratory
+Copyright (C) 2014 ROSA Laboratory
License: GNU LGPL or GNU GPL
Usage: $CmdName [options]
@@ -277,7 +277,8 @@
"tolerant!" => \$Tolerant,
"check!" => \$CheckInfo,
"quick!" => \$Quick,
- "all-affected!" => \$AllAffected
+ "all-affected!" => \$AllAffected,
+ "skip-internal=s" => \$SkipInternal
) or ERR_MESSAGE();
sub ERR_MESSAGE()
@@ -785,6 +786,9 @@
-quick
Quick analysis. Disable check of some template instances.
+
+ -skip-internal PATTERN
+ Do not check internal interfaces matched by the pattern.
REPORT:
Compatibility report will be generated to:
@@ -2259,7 +2263,7 @@
unlink($DumpPath);
$Content=~s/\n[ ]+/ /g;
- my @Lines = split("\n", $Content);
+ my @Lines = split(/\n/, $Content);
# clean memory
undef $Content;
@@ -8375,9 +8379,10 @@
my $Detected = undef;
- while($Content=~s/(\A|\n[^\#\/\n][^\n]*?|\n)(\*\s*|\s+|\@|\,|\()($RegExp_C|$RegExp_F)(\s*(\,|\)|\;|\-\>|\.|\:\s*\d))/$1$2c99_$3$4/g)
+ while($Content=~s/(\A|\n[^\#\/\n][^\n]*?|\n)(\*\s*|\s+|\@|\,|\()($RegExp_C|$RegExp_F)(\s*([\,\)\;\.\[]|\-\>|\:\s*\d))/$1$2c99_$3$4/g)
{ # MATCH:
# int foo(int new, int class, int (*new)(int));
+ # int foo(char template[], char*);
# unsigned private: 8;
# DO NOT MATCH:
# #pragma GCC visibility push(default)
@@ -8675,6 +8680,9 @@
writeLog($Version, "Temporary header file \'$TmpHeaderPath\' with the following content will be compiled to create GCC translation unit dump:\n".readFile($TmpHeaderPath)."\n");
# create TU dump
my $TUdump = "-fdump-translation-unit -fkeep-inline-functions -c";
+ if($UserLang eq "C") {
+ $TUdump .= " -U__cplusplus -D_Bool=\"bool\"";
+ }
if($CppMode{$Version}==1
or $MinGWMode{$Version}==1) {
$TUdump .= " -fpreprocessed";
@@ -10516,7 +10524,7 @@
if($MName=~/reserved|padding|f_spare/i) {
return 1;
}
- if($MName=~/\A[_]*(spare|pad|unused)[_\d]*\Z/i) {
+ if($MName=~/\A[_]*(spare|pad|unused|dummy)[_\d]*\Z/i) {
return 1;
}
if($MName=~/(pad\d+)/i) {
@@ -10994,7 +11002,7 @@
if($Size_Old ne $Size_New
and $Size_Old and $Size_New)
{
- my $ProblemType = "";
+ my $ProblemType = undef;
if(isCopyingClass($BaseId, 1)) {
$ProblemType = "Size_Of_Copying_Class";
}
@@ -11654,6 +11662,7 @@
and $Base_1{"Name"} ne $Base_2{"Name"})
{
if($Level eq "Binary"
+ and $Type1{"Size"} and $Type2{"Size"}
and $Type1{"Size"} ne $Type2{"Size"})
{
%{$SubProblems{"DataType_Size"}{$Typedef_1{"Name"}}}=(
@@ -11716,6 +11725,7 @@
and $Type1_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
{ # checking size
if($Level eq "Binary"
+ and $Type1_Pure{"Size"} and $Type2_Pure{"Size"}
and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
{
my $ProblemKind = "DataType_Size";
@@ -12070,6 +12080,7 @@
my $MemberType1_Name = $TypeInfo{1}{$MemberType1_Id}{"Name"};
my $MemberType2_Name = $TypeInfo{2}{$MemberType2_Id}{"Name"};
if($Level eq "Binary"
+ and $SizeV1 and $SizeV2
and $SizeV1 ne $SizeV2)
{
if($MemberType1_Name eq $MemberType2_Name or (isAnon($MemberType1_Name) and isAnon($MemberType2_Name))
@@ -12101,7 +12112,6 @@
}
if($ProblemType eq "Private_Field_Size")
{ # private field size with no effect
- $ProblemType = "";
}
if($ProblemType eq "Field_Size")
{
@@ -12225,6 +12235,8 @@
}
else
{
+ # TODO: Private_Field_Type rule?
+
if(not isPublic(\%Type1_Pure, $Member_Pos)
or isUnnamed($Member_Name)) {
next;
@@ -12232,7 +12244,6 @@
}
if($ProblemType eq "Private_Field_Type_And_Size")
{ # private field change with no effect
- next;
}
%{$SubProblems{$ProblemType}{$Member_Name}}=(
"Target"=>$Member_Name,
@@ -12584,6 +12595,12 @@
{ # non-public global data
return 0;
}
+
+ if(defined $SkipInternal)
+ {
+ return 0 if($Symbol=~/($SkipInternal)/);
+ }
+
if($CheckObjectsOnly) {
return 0 if($Symbol=~/\A(_init|_fini)\Z/);
}
@@ -13995,12 +14012,16 @@
{
if(defined $Sub_SubProblems->{"DataType_Size"})
{ # add "Global_Data_Size" problem
+
foreach my $Loc (keys(%{$Sub_SubProblems->{"DataType_Size"}}))
{
if(index($Loc,"->")==-1)
- { # add a new problem
- $AddProblems->{"Global_Data_Size"} = $Sub_SubProblems->{"DataType_Size"};
- last;
+ {
+ if($Loc eq $Sub_SubProblems->{"DataType_Size"}{$Loc}{"Type_Name"})
+ {
+ $AddProblems->{"Global_Data_Size"}{$Loc} = $Sub_SubProblems->{"DataType_Size"}{$Loc}; # add a new problem
+ last;
+ }
}
}
}
@@ -15025,7 +15046,7 @@
if(not checkDump(1, "2.20")
or not checkDump(2, "2.20"))
- { # added restrict attribute in 2.6
+ { # added type prefix in 2.20
if($TN1=~/\A(struct|union|enum) \Q$TN2\E\Z/
or $TN2=~/\A(struct|union|enum) \Q$TN1\E\Z/) {
return 0;
@@ -15063,6 +15084,16 @@
}
}
}
+
+ my ($N1, $N2) = ($TN1, $TN2);
+ $N1=~s/\b(struct|union) //g;
+ $N2=~s/\b(struct|union) //g;
+
+ if($N1 eq $N2)
+ { # QList<struct QUrl> and QList<QUrl>
+ return 0;
+ }
+
return 1;
}
@@ -15917,13 +15948,13 @@
$TestInfo .= " <library>$TargetLibraryName</library>\n";
$TestInfo .= " <version1>\n";
$TestInfo .= " <number>".$Descriptor{1}{"Version"}."</number>\n";
- $TestInfo .= " <architecture>$Arch1</architecture>\n";
+ $TestInfo .= " <arch>$Arch1</arch>\n";
$TestInfo .= " <gcc>$GccV1</gcc>\n";
$TestInfo .= " </version1>\n";
$TestInfo .= " <version2>\n";
$TestInfo .= " <number>".$Descriptor{2}{"Version"}."</number>\n";
- $TestInfo .= " <architecture>$Arch2</architecture>\n";
+ $TestInfo .= " <arch>$Arch2</arch>\n";
$TestInfo .= " <gcc>$GccV2</gcc>\n";
$TestInfo .= " </version2>\n";
$TestInfo = "<test_info>\n".$TestInfo."</test_info>\n\n";
@@ -16319,7 +16350,9 @@
$CHANGED_CONSTANTS .= " <problem id=\"$Kind\">\n";
$CHANGED_CONSTANTS .= " <change".getXmlParams($Change, $CompatProblems_Constants{$Level}{$Constant}{$Kind}).">$Change</change>\n";
$CHANGED_CONSTANTS .= " <effect".getXmlParams($Effect, $CompatProblems_Constants{$Level}{$Constant}{$Kind}).">$Effect</effect>\n";
- $CHANGED_CONSTANTS .= " <overcome".getXmlParams($Overcome, $CompatProblems_Constants{$Level}{$Constant}{$Kind}).">$Overcome</overcome>\n";
+ if($Overcome) {
+ $CHANGED_CONSTANTS .= " <overcome".getXmlParams($Overcome, $CompatProblems_Constants{$Level}{$Constant}{$Kind}).">$Overcome</overcome>\n";
+ }
$CHANGED_CONSTANTS .= " </problem>\n";
}
$CHANGED_CONSTANTS .= " </constant>\n";
@@ -16818,7 +16851,8 @@
foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
{
$INTERFACE_PROBLEMS .= " <library name=\"$DyLib\">\n";
- foreach my $Symbol (sort {lc($tr_name{$a}?$tr_name{$a}:$a) cmp lc($tr_name{$b}?$tr_name{$b}:$b)} keys(%SymbolChanges))
+ my @SortedInterfaces = sort {lc($tr_name{$a}?$tr_name{$a}:$a) cmp lc($tr_name{$b}?$tr_name{$b}:$b)} keys(%{$ReportMap{$HeaderName}{$DyLib}});
+ foreach my $Symbol (@SortedInterfaces)
{
$INTERFACE_PROBLEMS .= " <symbol name=\"$Symbol\">\n";
foreach my $Kind (keys(%{$SymbolChanges{$Symbol}}))
@@ -16833,8 +16867,9 @@
$INTERFACE_PROBLEMS .= " <change".getXmlParams($Change, \%Problem).">$Change</change>\n";
my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
$INTERFACE_PROBLEMS .= " <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n";
- my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
- $INTERFACE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
+ if(my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"}) {
+ $INTERFACE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
+ }
$INTERFACE_PROBLEMS .= " </problem>\n";
}
}
@@ -17019,8 +17054,9 @@
$TYPE_PROBLEMS .= " <change".getXmlParams($Change, \%Problem).">$Change</change>\n";
my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
$TYPE_PROBLEMS .= " <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n";
- my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
- $TYPE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
+ if(my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"}) {
+ $TYPE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
+ }
$TYPE_PROBLEMS .= " </problem>\n";
}
}
@@ -17387,16 +17423,23 @@
my $Description = $SProblems{$Symbol}{"Descr"};
my $Location = $SProblems{$Symbol}{"Location"};
my $Target = "";
- if($Param_Name) {
- $Target = " affected=\"param\" param_name=\"$Param_Name\"";
+ if($Param_Name)
+ {
+ $Target .= " param=\"$Param_Name\"";
+ $Description=~s/parameter $Param_Name /parameter \@param /;
}
elsif($Location=~/\Aretval(\-|\Z)/i) {
- $Target = " affected=\"retval\"";
+ $Target .= " affected=\"retval\"";
}
elsif($Location=~/\Athis(\-|\Z)/i) {
- $Target = " affected=\"this\"";
+ $Target .= " affected=\"this\"";
}
- $Affected .= " <symbol$Target name=\"$Symbol\">\n";
+
+ if($Description=~s/\AField ([^\s]+) /Field \@field /) {
+ $Target .= " field=\"$1\"";
+ }
+
+ $Affected .= " <symbol name=\"$Symbol\"$Target>\n";
$Affected .= " <comment>".xmlSpecChars($Description)."</comment>\n";
$Affected .= " </symbol>\n";
}
@@ -17555,14 +17598,23 @@
if($ExtendedSymbols{$Symbol}) {
push(@Sentence, " This is a symbol from an external library that may use the \'$TargetLibraryName\' library and change the ABI after recompiling.");
}
- return join(" ", @Sentence);
+
+ my $Sent = join(" ", @Sentence);
+
+ if($ReportFormat eq "xml")
+ {
+ $Sent=~s/->/./g;
+ $Sent=~s/'//g;
+ }
+
+ return $Sent;
}
sub getFieldType($$$)
{
my ($Location, $TypeId, $LibVersion) = @_;
- my @Fields = split("->", $Location);
+ my @Fields = split(/\->/, $Location);
foreach my $Name (@Fields)
{
@@ -17775,7 +17827,10 @@
$Report .= $Summary."\n";
$Report .= get_Report_Added($Level).get_Report_Removed($Level);
$Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level);
- $Report .= get_Report_SymbolsInfo($Level);
+
+ # additional symbols info (if needed)
+ # $Report .= get_Report_SymbolsInfo($Level);
+
$Report .= "</report>\n";
return $Report;
}
@@ -20132,7 +20187,14 @@
}
}
$SymVer{$LibVersion} = $ABI->{"SymbolVersion"};
- $Descriptor{$LibVersion}{"Version"} = $ABI->{"LibraryVersion"};
+
+ if(my $V = $TargetVersion{$LibVersion}) {
+ $Descriptor{$LibVersion}{"Version"} = $V;
+ }
+ else {
+ $Descriptor{$LibVersion}{"Version"} = $ABI->{"LibraryVersion"};
+ }
+
$SkipTypes{$LibVersion} = $ABI->{"SkipTypes"};
if(not $SkipTypes{$LibVersion})
{ # support for old dumps
@@ -20904,10 +20966,10 @@
}
# check GCC version
- if($GCC_Ver=~/\A4\.8(|\.0|\.1)\Z/)
+ if($GCC_Ver=~/\A4\.8(|\.[012])\Z/)
{ # bug http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57850
# introduced in 4.8
- # fixed in 4.9
+ # fixed in 4.8.3
printMsg("WARNING", "Not working properly with GCC $GCC_Ver. Please update or downgrade GCC or use a local installation by --gcc-path=PATH option.");
$EMERGENCY_MODE_48 = 1;
}
@@ -22692,7 +22754,7 @@
}
if($ShowVersion)
{
- printMsg("INFO", "ABI Compliance Checker (ACC) $TOOL_VERSION\nCopyright (C) 2012 ROSA Laboratory\nLicense: LGPL or GPL <http://www.gnu.org/licenses/>\nThis program is free software: you can redistribute it and/or modify it.\n\nWritten by Andrey Ponomarenko.");
+ printMsg("INFO", "ABI Compliance Checker (ACC) $TOOL_VERSION\nCopyright (C) 2014 ROSA Laboratory\nLicense: LGPL or GPL <http://www.gnu.org/licenses/>\nThis program is free software: you can redistribute it and/or modify it.\n\nWritten by Andrey Ponomarenko.");
exit(0);
}
if($DumpVersion)