[cfe-dev] lower bound error searching for module preprocessing entities within a source range

Tom Honermann thonermann at coverity.com
Wed Aug 28 15:19:35 PDT 2013


Attached is a patch to correct a lower bound search error that occurs 
when searching for module preprocessing entities within a source range.

The test case I've been using for this is:

$ cat t.c
#if __GNUC__
#endif
void f(void) {
}

The problem I was having was that a query for macro expansions occurring 
within the definition of f() (source range 3:1-4:1) was returning the 
expansion of __GNUC__ occurring at line 1:5.  Clearly, no expansions 
should be found for that source range.

The problem was due to lines 4315-4316 below.  The loop progressively 
reduces a half open range indicated by [First,First+Count) with PPI 
pointing to an element in the middle of that range.  Note that PPI is 
always dereferenceable - it is not a past-the-end iterator (indeed, it 
is unconditionally dereferenced at line 4313).

If all of the source locations for the preprocessed entities precede the 
specified source location, then the loop will exit with PPI pointing to 
the last element in the range [pp_begin,pp_end).  However, the intention 
is that, if all entities precede the specified source location, then PPI 
is expected to point to pp_end (a past-the-end iterator) when the loop 
exits (see line 4322).  When the loop exits with PPI not set to pp_end, 
then it is interpreted as pointing to the first preprocessed entity with 
a source location following the specified location.  This is why my 
query is incorrectly including the preceding macro expansion.

The attached patch against trunk (revision 189518) modifies lines 
4315-4316 to first increment PPI, and then to assign First to PPI.  This 
causes PPI to be advanced appropriately to satisfy the comparison at 
line 4322 when all entities precede the specified source location.

I looked for a simple way to provide a test for this behavior, but I 
wasn't able to find one.  It seems there may be some way to test this 
with c-index-test, but I wasn't able to figure out a way to do so (the 
problem only occurs when the relevant code is loaded from a PCH file). 
I'm afraid I'm not very familiar with the existing tests.  I did run the 
Clang test suite (make test) and no regressions were reported.

lib/Serialization/ASTReader.cpp:
4280 /// \brief Returns the first preprocessed entity ID that ends after 
\arg BLoc.
4281 PreprocessedEntityID
4282 ASTReader::findBeginPreprocessedEntity(SourceLocation BLoc) const {
4283   if (SourceMgr.isLocalSourceLocation(BLoc))
4284     return getTotalNumPreprocessedEntities();
4285
4286   GlobalSLocOffsetMapType::const_iterator
4287     SLocMapI = 
GlobalSLocOffsetMap.find(SourceManager::MaxLoadedOffset -
4288                                         BLoc.getOffset() - 1);
4289   assert(SLocMapI != GlobalSLocOffsetMap.end() &&
4290          "Corrupted global sloc offset map");
4291
4292   if (SLocMapI->second->NumPreprocessedEntities == 0)
4293     return findNextPreprocessedEntity(SLocMapI);
4294
4295   ModuleFile &M = *SLocMapI->second;
4296   typedef const PPEntityOffset *pp_iterator;
4297   pp_iterator pp_begin = M.PreprocessedEntityOffsets;
4298   pp_iterator pp_end = pp_begin + M.NumPreprocessedEntities;
4299
4300   size_t Count = M.NumPreprocessedEntities;
4301   size_t Half;
4302   pp_iterator First = pp_begin;
4303   pp_iterator PPI;
4304
4305   // Do a binary search manually instead of using std::lower_bound 
because
4306   // The end locations of entities may be unordered (when a macro 
expansion
4307   // is inside another macro argument), but for this case it is not 
important
4308   // whether we get the first macro expansion or its containing macro.
4309   while (Count > 0) {
4310     Half = Count/2;
4311     PPI = First;
4312     std::advance(PPI, Half);
4313     if (SourceMgr.isBeforeInTranslationUnit(ReadSourceLocation(M, 
PPI->End),
4314                                             BLoc)){
4315       First = PPI;
4316       ++First;
4317       Count = Count - Half - 1;
4318     } else
4319       Count = Half;
4320   }
4321
4322   if (PPI == pp_end)
4323     return findNextPreprocessedEntity(SLocMapI);
4324
4325   return M.BasePreprocessedEntityID + (PPI - pp_begin);
4326 }

Tom.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: clang-module-find-pp-entity.patch
Type: text/x-patch
Size: 511 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20130828/a724a355/attachment.bin>


More information about the cfe-dev mailing list