[StaticAnalyzer] Potential bug in MemRegion.cpp?

When the following function is called by (RegionOffset
MemRegion::getAsOffset() const:1257), and the first parameter (Child) is a
NULL pointer I get a segmentation fault.

@file: MemRegion.cpp
01164 static bool isImmediateBase(const CXXRecordDecl *Child,
01165 const CXXRecordDecl *Base) {
01166 // Note that we do NOT canonicalize the base class here, because
01167 // ASTRecordLayout doesn't either. If that leads us down the wrong
path,
01168 // so be it; at least we won't crash.
01169 for (CXXRecordDecl::base_class_const_iterator I =
Child->bases_begin(),
01170 E =
Child->bases_end();
01171 I != E; ++I) {
01172 if (I->getType()->getAsCXXRecordDecl() == Base)
01173 return true;
01174 }
01175
01176 return false;
01177 }

For now I just return `false' when `Child' pointer is NULL. Is this fix okay
or there is something else required to be done?

Thanks,
-Aditya

I think the bug here is that "Child" should never be NULL. How are you getting into this situation?

Jordan

I was compiling a program when I hit this segmentation fault. The program is
kind of big and I don't know how to reduce it to a minimal test case.

From: Jordan Rose [mailto:jordan_rose@apple.com]
Sent: Thursday, September 19, 2013 11:13 AM
To: Aditya Kumar
Cc: 'Clang Dev'
Subject: Re: [cfe-dev] [StaticAnalyzer] Potential bug in MemRegion.cpp?

I think the bug here is that "Child" should never be NULL. How are you
getting into this situation?

Jordan

> When the following function is called by (RegionOffset
> MemRegion::getAsOffset() const:1257), and the first parameter (Child)
> is a NULL pointer I get a segmentation fault.
>
> @file: MemRegion.cpp
> 01164 static bool isImmediateBase(const CXXRecordDecl *Child,
> 01165 const CXXRecordDecl *Base) {
> 01166 // Note that we do NOT canonicalize the base class here, because
> 01167 // ASTRecordLayout doesn't either. If that leads us down the

wrong

If it's not a private program you can create a bug at http://llvm.org/bugs/ and attach the preprocessed file. If it is a private program (corporate or something) well...you could at least report where the caller is and what the original MemRegion is (using MemRegion::dump) and I can try to figure it out from that.

Jordan

I’m not sure of the test case but the problem seems to be in MemRegion::getAsOffset().
In switch case case CXXBaseObjectRegionKind:
if we cannot compute the offset of the base class we need to continue in the loop instead of moving further down-

Index: lib/StaticAnalyzer/Core/MemRegion.cpp

Try creduce?

Karthik,

You are right. This is basically the reason I got the error.

— lib/StaticAnalyzer/Core/MemRegion.cpp (revision 190992)

+++ lib/StaticAnalyzer/Core/MemRegion.cpp (working copy)

@@ -1244,6 +1244,7 @@

if (!Child) {

// We cannot compute the offset of the base class.

SymbolicOffsetBase = R;

  • continue;

}

In addition to what you have suggested, I think we should also return false (in MemRegion.cpp:isImmediateBase), or may be assert when the Child pointer is NULL.

@file: MemRegion.cpp
static bool isImmediateBase(const CXXRecordDecl *Child,
const CXXRecordDecl *Base) {

  • if (!Child)

  • return false;

Yes the program is private, so I have the Memregion::dump(), hope this
helps.
I was curious if I could figure out the statement/function in the program
where this bug occurs. That way I could try to get a minimal test case.
Is it possible to see the program code from within the debugger?

Program received signal SIGSEGV, Segmentation fault.
0x0000000000eaaf2e in clang::CXXRecordDecl::data (this=0x0)
  at
/prj/llvm-arm/home/kaditya/llvm-debug/llvm/tools/clang/lib/CodeGen/../../inc
lude/clang/AST/DeclCXX.h:559
559 return *DefinitionData;
(gdb) up
#1 0x0000000000f0cc62 in clang::CXXRecordDecl::bases_begin (this=0x0)
  at
/prj/llvm-arm/home/kaditya/llvm-debug/llvm/tools/clang/lib/CodeGen/../../inc
lude/clang/AST/DeclCXX.h:673
673 base_class_const_iterator bases_begin() const { return
data().getBases(); }
(gdb)
#2 0x000000000177a670 in isImmediateBase (Child=0x0, Base=0x4a55520)
  at
/prj/llvm-arm/home/kaditya/llvm-debug/llvm/tools/clang/lib/StaticAnalyzer/Co
re/MemRegion.cpp:1154
1154 for (CXXRecordDecl::base_class_const_iterator I =
Child->bases_begin(),

#3 0x000000000177a8be in clang::ento::MemRegion::getAsOffset
(this=0x5cda100)
  at
/prj/llvm-arm/home/kaditya/llvm-debug/llvm/tools/clang/lib/StaticAnalyzer/Co
re/MemRegion.cpp:1242
1242 if (!isImmediateBase(Child, BOR->getDecl()))

(gdb) p this->dump()
base{SymRegion{reg_$323<element{SymRegion{conj_$309{const void_cv_type *}},0
S32b,void *}>},Tile}->i_$1 = void
(gdb) p this->getString()
$2 = {static npos = 18446744073709551615,
  _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>>
= {<No data fields>}, <No data fields>},
  _M_p = 0x59f8bc8
"base{SymRegion{reg_$323<element{SymRegion{conj_$309{const void_cv_type
*}},0 S32b,void *}>},Tile}->i_"}}

Thanks
-Aditya

From: Jordan Rose [mailto:jordan_rose@apple.com]
Sent: Thursday, September 19, 2013 7:22 PM
To: Aditya Kumar
Cc: 'Clang Dev'
Subject: Re: [cfe-dev] [StaticAnalyzer] Potential bug in MemRegion.cpp?

If it's not a private program you can create a bug at

http://llvm.org/bugs/ and

attach the preprocessed file. If it is a private program (corporate or
something) well...you could at least report where the caller is and what

the

original MemRegion is (using MemRegion::dump) and I can try to figure it

out

from that.

Jordan

> I was compiling a program when I hit this segmentation fault. The
> program is kind of big and I don't know how to reduce it to a minimal

test

case.
>
>
>
>> From: Jordan Rose [mailto:jordan_rose@apple.com]
>> Sent: Thursday, September 19, 2013 11:13 AM
>> To: Aditya Kumar
>> Cc: 'Clang Dev'
>> Subject: Re: [cfe-dev] [StaticAnalyzer] Potential bug in MemRegion.cpp?
>>
>> I think the bug here is that "Child" should never be NULL. How are
>> you getting into this situation?
>>
>> Jordan
>>
>>
>>> When the following function is called by (RegionOffset
>>> MemRegion::getAsOffset() const:1257), and the first parameter
>>> (Child) is a NULL pointer I get a segmentation fault.
>>>
>>> @file: MemRegion.cpp
>>> 01164 static bool isImmediateBase(const CXXRecordDecl *Child,
>>> 01165 const CXXRecordDecl *Base) {
>>> 01166 // Note that we do NOT canonicalize the base class here,

because

Hm.

base{SymRegion{reg_$323<element{SymRegion{conj_$309{const void_cv_type *}},0
S32b,void *}>},Tile}->i_

Yeah, this doesn’t look like a good region. IIRC, a void* region should never have a base region directly wrapping it—there should always be an element region in between representing a cast. When the program tries to figure out where the “Tile” base class is located, there’s no way to know, because our most derived class is “void”.

Then again, we’re not actually checking for this in MemRegionManager::getCXXBaseObjectRegion. You could try inserting an assertion there that if the base is a symbolic region, it’s not void*.

if (auto symRegion = dyn_cast(Super))
assert(!symRegion->getSymbol()->getType()->isVoidPointerType());

This doesn’t fire on any of the regression tests in the repository, but I didn’t test it against any real projects. It should trip up your case, though, and then the stack trace should include the location where this bad region is formed.

Jordan