Fix undefined behavior: member function calls where 'this' is a null pointer.

llvm-svn: 162430
This commit is contained in:
Richard Smith 2012-08-23 06:16:52 +00:00
parent 7bdc8ae20b
commit 802c4b7015
9 changed files with 49 additions and 33 deletions

View File

@ -33,11 +33,11 @@ namespace clang {
char Data[1]; // Variable sized. char Data[1]; // Variable sized.
void addRef() { void addRef() {
if (this) ++RefCount; ++RefCount;
} }
void dropRef() { void dropRef() {
if (this && --RefCount == 0) if (--RefCount == 0)
delete [] (char*)this; delete [] (char*)this;
} }
}; };
@ -63,22 +63,27 @@ namespace clang {
RopePiece(RopeRefCountString *Str, unsigned Start, unsigned End) RopePiece(RopeRefCountString *Str, unsigned Start, unsigned End)
: StrData(Str), StartOffs(Start), EndOffs(End) { : StrData(Str), StartOffs(Start), EndOffs(End) {
StrData->addRef(); if (StrData)
StrData->addRef();
} }
RopePiece(const RopePiece &RP) RopePiece(const RopePiece &RP)
: StrData(RP.StrData), StartOffs(RP.StartOffs), EndOffs(RP.EndOffs) { : StrData(RP.StrData), StartOffs(RP.StartOffs), EndOffs(RP.EndOffs) {
StrData->addRef(); if (StrData)
StrData->addRef();
} }
~RopePiece() { ~RopePiece() {
StrData->dropRef(); if (StrData)
StrData->dropRef();
} }
void operator=(const RopePiece &RHS) { void operator=(const RopePiece &RHS) {
if (StrData != RHS.StrData) { if (StrData != RHS.StrData) {
StrData->dropRef(); if (StrData)
StrData->dropRef();
StrData = RHS.StrData; StrData = RHS.StrData;
StrData->addRef(); if (StrData)
StrData->addRef();
} }
StartOffs = RHS.StartOffs; StartOffs = RHS.StartOffs;
EndOffs = RHS.EndOffs; EndOffs = RHS.EndOffs;
@ -191,7 +196,8 @@ public:
~RewriteRope() { ~RewriteRope() {
// If we had an allocation buffer, drop our reference to it. // If we had an allocation buffer, drop our reference to it.
AllocBuffer->dropRef(); if (AllocBuffer)
AllocBuffer->dropRef();
} }
typedef RopePieceBTree::iterator iterator; typedef RopePieceBTree::iterator iterator;

View File

@ -59,7 +59,7 @@ bool trans::canApplyWeak(ASTContext &Ctx, QualType type,
return false; // id/NSObject is not safe for weak. return false; // id/NSObject is not safe for weak.
if (!AllowOnUnknownClass && !Class->hasDefinition()) if (!AllowOnUnknownClass && !Class->hasDefinition())
return false; // forward classes are not verifiable, therefore not safe. return false; // forward classes are not verifiable, therefore not safe.
if (Class->isArcWeakrefUnavailable()) if (Class && Class->isArcWeakrefUnavailable())
return false; return false;
} }

View File

@ -10438,10 +10438,10 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
// If this definition appears within the record, do the checking when // If this definition appears within the record, do the checking when
// the record is complete. // the record is complete.
const FunctionDecl *Primary = MD; const FunctionDecl *Primary = MD;
if (MD->getTemplatedKind() != FunctionDecl::TK_NonTemplate) if (const FunctionDecl *Pattern = MD->getTemplateInstantiationPattern())
// Find the uninstantiated declaration that actually had the '= default' // Find the uninstantiated declaration that actually had the '= default'
// on it. // on it.
MD->getTemplateInstantiationPattern()->isDefined(Primary); Pattern->isDefined(Primary);
if (Primary == Primary->getCanonicalDecl()) if (Primary == Primary->getCanonicalDecl())
return; return;
@ -10966,14 +10966,16 @@ void DelegatingCycleHelper(CXXConstructorDecl* Ctor,
if (Ctor->isInvalidDecl()) if (Ctor->isInvalidDecl())
return; return;
const FunctionDecl *FNTarget = 0; CXXConstructorDecl *Target = Ctor->getTargetConstructor();
CXXConstructorDecl *Target;
// Target may not be determinable yet, for instance if this is a dependent
// We ignore the result here since if we don't have a body, Target will be // call in an uninstantiated template.
// null below. if (Target) {
(void)Ctor->getTargetConstructor()->hasBody(FNTarget); const FunctionDecl *FNTarget = 0;
Target (void)Target->hasBody(FNTarget);
= const_cast<CXXConstructorDecl*>(cast_or_null<CXXConstructorDecl>(FNTarget)); Target = const_cast<CXXConstructorDecl*>(
cast_or_null<CXXConstructorDecl>(FNTarget));
}
CXXConstructorDecl *Canonical = Ctor->getCanonicalDecl(), CXXConstructorDecl *Canonical = Ctor->getCanonicalDecl(),
// Avoid dereferencing a null pointer here. // Avoid dereferencing a null pointer here.
@ -10997,17 +10999,18 @@ void DelegatingCycleHelper(CXXConstructorDecl* Ctor,
diag::warn_delegating_ctor_cycle) diag::warn_delegating_ctor_cycle)
<< Ctor; << Ctor;
// Don't add a note for a function delegating directo to itself. // Don't add a note for a function delegating directly to itself.
if (TCanonical != Canonical) if (TCanonical != Canonical)
S.Diag(Target->getLocation(), diag::note_it_delegates_to); S.Diag(Target->getLocation(), diag::note_it_delegates_to);
CXXConstructorDecl *C = Target; CXXConstructorDecl *C = Target;
while (C->getCanonicalDecl() != Canonical) { while (C->getCanonicalDecl() != Canonical) {
const FunctionDecl *FNTarget = 0;
(void)C->getTargetConstructor()->hasBody(FNTarget); (void)C->getTargetConstructor()->hasBody(FNTarget);
assert(FNTarget && "Ctor cycle through bodiless function"); assert(FNTarget && "Ctor cycle through bodiless function");
C C = const_cast<CXXConstructorDecl*>(
= const_cast<CXXConstructorDecl*>(cast<CXXConstructorDecl>(FNTarget)); cast<CXXConstructorDecl>(FNTarget));
S.Diag(C->getLocation(), diag::note_which_delegates_to); S.Diag(C->getLocation(), diag::note_which_delegates_to);
} }
} }
@ -11030,9 +11033,8 @@ void Sema::CheckDelegatingCtorCycles() {
for (DelegatingCtorDeclsType::iterator for (DelegatingCtorDeclsType::iterator
I = DelegatingCtorDecls.begin(ExternalSource), I = DelegatingCtorDecls.begin(ExternalSource),
E = DelegatingCtorDecls.end(); E = DelegatingCtorDecls.end();
I != E; ++I) { I != E; ++I)
DelegatingCycleHelper(*I, Valid, Invalid, Current, *this); DelegatingCycleHelper(*I, Valid, Invalid, Current, *this);
}
for (CI = Invalid.begin(), CE = Invalid.end(); CI != CE; ++CI) for (CI = Invalid.begin(), CE = Invalid.end(); CI != CE; ++CI)
(*CI)->setInvalidDecl(); (*CI)->setInvalidDecl();

View File

@ -3101,8 +3101,8 @@ bool Sema::CheckObjCARCUnavailableWeakConversion(QualType castType,
canExprType->isObjCObjectPointerType()) { canExprType->isObjCObjectPointerType()) {
if (const ObjCObjectPointerType *ObjT = if (const ObjCObjectPointerType *ObjT =
canExprType->getAs<ObjCObjectPointerType>()) canExprType->getAs<ObjCObjectPointerType>())
if (ObjT->getInterfaceDecl()->isArcWeakrefUnavailable()) if (const ObjCInterfaceDecl *ObjI = ObjT->getInterfaceDecl())
return false; return !ObjI->isArcWeakrefUnavailable();
} }
return true; return true;
} }

View File

@ -886,12 +886,14 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
if (lifetime == Qualifiers::OCL_Weak) { if (lifetime == Qualifiers::OCL_Weak) {
bool err = false; bool err = false;
if (const ObjCObjectPointerType *ObjT = if (const ObjCObjectPointerType *ObjT =
PropertyIvarType->getAs<ObjCObjectPointerType>()) PropertyIvarType->getAs<ObjCObjectPointerType>()) {
if (ObjT->getInterfaceDecl()->isArcWeakrefUnavailable()) { const ObjCInterfaceDecl *ObjI = ObjT->getInterfaceDecl();
if (ObjI && ObjI->isArcWeakrefUnavailable()) {
Diag(PropertyDiagLoc, diag::err_arc_weak_unavailable_property); Diag(PropertyDiagLoc, diag::err_arc_weak_unavailable_property);
Diag(property->getLocation(), diag::note_property_declare); Diag(property->getLocation(), diag::note_property_declare);
err = true; err = true;
} }
}
if (!err && !getLangOpts().ObjCARCWeak) { if (!err && !getLangOpts().ObjCARCWeak) {
Diag(PropertyDiagLoc, diag::err_arc_weak_no_runtime); Diag(PropertyDiagLoc, diag::err_arc_weak_no_runtime);
Diag(property->getLocation(), diag::note_property_declare); Diag(property->getLocation(), diag::note_property_declare);

View File

@ -1999,9 +1999,11 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
for (unsigned I = 0; I < Depth; ++I) for (unsigned I = 0; I < Depth; ++I)
TemplateArgLists.addOuterTemplateArguments(0, 0); TemplateArgLists.addOuterTemplateArguments(0, 0);
LocalInstantiationScope Scope(*this);
InstantiatingTemplate Inst(*this, TemplateLoc, Template); InstantiatingTemplate Inst(*this, TemplateLoc, Template);
if (Inst) if (Inst)
return QualType(); return QualType();
CanonType = SubstType(Pattern->getUnderlyingType(), CanonType = SubstType(Pattern->getUnderlyingType(),
TemplateArgLists, AliasTemplate->getLocation(), TemplateArgLists, AliasTemplate->getLocation(),
AliasTemplate->getDeclName()); AliasTemplate->getDeclName());

View File

@ -570,6 +570,9 @@ static void PrepareArgumentPackDeduction(Sema &S,
SavedPacks[I] = Deduced[PackIndices[I]]; SavedPacks[I] = Deduced[PackIndices[I]];
Deduced[PackIndices[I]] = TemplateArgument(); Deduced[PackIndices[I]] = TemplateArgument();
if (!S.CurrentInstantiationScope)
continue;
// If the template arugment pack was explicitly specified, add that to // If the template arugment pack was explicitly specified, add that to
// the set of deduced arguments. // the set of deduced arguments.
const TemplateArgument *ExplicitArgs; const TemplateArgument *ExplicitArgs;
@ -2601,7 +2604,8 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
// explicitly-specified set (C++0x [temp.arg.explicit]p9). // explicitly-specified set (C++0x [temp.arg.explicit]p9).
const TemplateArgument *ExplicitArgs; const TemplateArgument *ExplicitArgs;
unsigned NumExplicitArgs; unsigned NumExplicitArgs;
if (CurrentInstantiationScope->getPartiallySubstitutedPack(&ExplicitArgs, if (CurrentInstantiationScope &&
CurrentInstantiationScope->getPartiallySubstitutedPack(&ExplicitArgs,
&NumExplicitArgs) &NumExplicitArgs)
== Param) == Param)
Builder.push_back(TemplateArgument(ExplicitArgs, NumExplicitArgs)); Builder.push_back(TemplateArgument(ExplicitArgs, NumExplicitArgs));

View File

@ -520,7 +520,7 @@ bool SymbolReaper::isLive(const VarRegion *VR, bool includeStoreBindings) const{
const StackFrameContext *CurrentContext = LCtx->getCurrentStackFrame(); const StackFrameContext *CurrentContext = LCtx->getCurrentStackFrame();
if (VarContext == CurrentContext) { if (VarContext == CurrentContext) {
// If no statemetnt is provided, everything is live. // If no statement is provided, everything is live.
if (!Loc) if (!Loc)
return true; return true;
@ -548,7 +548,7 @@ bool SymbolReaper::isLive(const VarRegion *VR, bool includeStoreBindings) const{
return false; return false;
} }
return VarContext->isParentOf(CurrentContext); return !VarContext || VarContext->isParentOf(CurrentContext);
} }
SymbolVisitor::~SymbolVisitor() {} SymbolVisitor::~SymbolVisitor() {}

View File

@ -35,7 +35,7 @@ namespace clang {
class RewriterTestContext { class RewriterTestContext {
public: public:
RewriterTestContext() RewriterTestContext()
: Diagnostics(llvm::IntrusiveRefCntPtr<DiagnosticIDs>()), : Diagnostics(llvm::IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs)),
DiagnosticPrinter(llvm::outs(), DiagnosticOptions()), DiagnosticPrinter(llvm::outs(), DiagnosticOptions()),
Files((FileSystemOptions())), Files((FileSystemOptions())),
Sources(Diagnostics, Files), Sources(Diagnostics, Files),