This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: [PATCH] Loosen the Gold ODR checker to only compare filenames
This patch should do a better job. I went back to the
substring-comparison the original code used, and chopped off the line
number in addition to the directory. The code to remove the directory
is different because the original code wasn't a transitive relation:
it reported that "c:1" < "d/a:1" < "a/b:1" < "c:1".
2011-02-03 Jeffrey Yasskin <jyasskin@google.com>
* symtab.cc: Sort by just the filename.
On Thu, Feb 3, 2011 at 2:10 PM, Jeffrey Yasskin <jyasskin@google.com> wrote:
> Whoops, please don't submit this. The strings that Source_location
> points at don't live long enough to use them in the way I'm using
> them. I'll send a working patch shortly.
>
> On Wed, Feb 2, 2011 at 10:44 PM, Jeffrey Yasskin <jyasskin@google.com> wrote:
>> Code compiled with different flags, especially -O, may have a
>> different line number for the first instruction in a function. This
>> produces false positives in the ODR checker when linking object files
>> that should be ABI-compatible.
>>
>> The best fixes would be to A) look at the DW_AT_decl_line of the
>> DW_TAG_subprogram for the function, but this would require gold to
>> parse a whole new debug section, or B) hash the ODR-relevant aspects
>> of each function into a new dwarf attribute, but this would require
>> gcc to produce the hash and gold to parse a whole new debug section.
>>
>> Instead, loosening the ODR check to allow a function's definitions to
>> be from anywhere within the same file removes the false positives with
>> much less work, and would have caused very few extra false negatives
>> in Google's codebase.
>>
>> 2011-02-02 ?Jeffrey Yasskin ?<jyasskin@google.com>
>>
>> ? ? ? * dwarf_reader.h: Add a Source_location type, and change the
>> addr2line functions to return it.
>> ? ? ? * dwarf_reader.cc: Implement Source_location, and change the
>> addr2line functions to return it.
>> ? ? ? * symtab.cc: Sort by just the filename.
>> ? ? ? * object.cc: Convert a Source_location return to a std::string.
>>
>
Index: gold/symtab.cc
===================================================================
RCS file: /cvs/src/src/gold/symtab.cc,v
retrieving revision 1.146
diff -u -r1.146 symtab.cc
--- gold/symtab.cc 24 Jan 2011 21:48:40 -0000 1.146
+++ gold/symtab.cc 3 Feb 2011 22:37:54 -0000
@@ -3012,11 +3012,12 @@
// We check for ODR violations by looking for symbols with the same
// name for which the debugging information reports that they were
// defined in different source locations. When comparing the source
-// location, we consider instances with the same base filename and
-// line number to be the same. This is because different object
-// files/shared libraries can include the same header file using
-// different paths, and we don't want to report an ODR violation in
-// that case.
+// location, we consider instances with the same base filename to be
+// the same. This is because different object files/shared libraries
+// can include the same header file using different paths, and
+// different optimization settings can make the line number appear to
+// be a couple lines off, and we don't want to report an ODR violation
+// in those cases.
// This struct is used to compare line information, as returned by
// Dwarf_line_info::one_addr2line. It implements a < comparison
@@ -3027,13 +3028,29 @@
bool
operator()(const std::string& s1, const std::string& s2) const
{
- std::string::size_type pos1 = s1.rfind('/');
- std::string::size_type pos2 = s2.rfind('/');
- if (pos1 == std::string::npos
- || pos2 == std::string::npos)
- return s1 < s2;
- return s1.compare(pos1, std::string::npos,
- s2, pos2, std::string::npos) < 0;
+ // Inputs should be of the form "dirname/filename:linenum" where
+ // "dirname/" is optional. We want to compare just the filename.
+
+ // Find the last '/' and ':' in each string.
+ std::string::size_type s1begin = s1.rfind('/');
+ std::string::size_type s2begin = s2.rfind('/');
+ std::string::size_type s1end = s1.rfind(':');
+ std::string::size_type s2end = s2.rfind(':');
+ // If there was no '/' in a string, start at the beginning.
+ if (s1begin == std::string::npos)
+ s1begin = 0;
+ if (s2begin == std::string::npos)
+ s2begin = 0;
+ // If the ':' appeared in the directory name, compare to the end
+ // of the string.
+ if (s1end < s1begin)
+ s1end = std::string::npos;
+ if (s2end < s2begin)
+ s2end = std::string::npos;
+ // Compare takes lengths, not end indices. Passing slightly less
+ // than npos will still extend to the end of the string.
+ return s1.compare(s1begin, s1end - s1begin,
+ s2, s2begin, s2end - s2begin) < 0;
}
};