2019-08-07 03:13:29 +08:00
// RUN: %clang_cc1 -fsyntax-only -Wdangling -Wdangling-field -Wreturn-stack-address -verify %s
struct [[gsl::Owner(int)]] MyIntOwner {
MyIntOwner ( ) ;
int & operator * ( ) ;
} ;
struct [[gsl::Pointer(int)]] MyIntPointer {
MyIntPointer ( int * p = nullptr ) ;
// Conversion operator and constructor conversion will result in two
2019-09-04 00:17:24 +08:00
// different ASTs. The former is tested with another owner and
2019-08-07 03:13:29 +08:00
// pointer type.
MyIntPointer ( const MyIntOwner & ) ;
int & operator * ( ) ;
MyIntOwner toOwner ( ) ;
} ;
2019-09-04 00:17:24 +08:00
struct MySpecialIntPointer : MyIntPointer {
} ;
// We did see examples in the wild when a derived class changes
// the ownership model. So we have a test for it.
struct [[gsl::Owner(int)]] MyOwnerIntPointer : MyIntPointer {
} ;
2019-08-07 03:13:29 +08:00
struct [[gsl::Pointer(long)]] MyLongPointerFromConversion {
MyLongPointerFromConversion ( long * p = nullptr ) ;
long & operator * ( ) ;
} ;
struct [[gsl::Owner(long)]] MyLongOwnerWithConversion {
MyLongOwnerWithConversion ( ) ;
operator MyLongPointerFromConversion ( ) ;
long & operator * ( ) ;
MyIntPointer releaseAsMyPointer ( ) ;
long * releaseAsRawPointer ( ) ;
} ;
void danglingHeapObject ( ) {
new MyLongPointerFromConversion ( MyLongOwnerWithConversion { } ) ; // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
new MyIntPointer ( MyIntOwner { } ) ; // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
}
void intentionalFalseNegative ( ) {
int i ;
MyIntPointer p { & i } ;
// In this case we do not have enough information in a statement local
// analysis to detect the problem.
new MyIntPointer ( p ) ;
new MyIntPointer ( MyIntPointer { p } ) ;
}
MyIntPointer ownershipTransferToMyPointer ( ) {
MyLongOwnerWithConversion t ;
return t . releaseAsMyPointer ( ) ; // ok
}
long * ownershipTransferToRawPointer ( ) {
MyLongOwnerWithConversion t ;
return t . releaseAsRawPointer ( ) ; // ok
}
struct Y {
int a [ 4 ] ;
} ;
void dangligGslPtrFromTemporary ( ) {
2019-09-04 00:17:24 +08:00
MyIntPointer p = Y { } . a ; // TODO
2019-08-07 03:13:29 +08:00
( void ) p ;
}
struct DanglingGslPtrField {
2019-09-04 00:17:24 +08:00
MyIntPointer p ; // expected-note {{pointer member declared here}}
2019-08-07 03:13:29 +08:00
MyLongPointerFromConversion p2 ; // expected-note {{pointer member declared here}}
2019-09-04 00:17:24 +08:00
DanglingGslPtrField ( int i ) : p ( & i ) { } // TODO
2019-08-07 03:13:29 +08:00
DanglingGslPtrField ( ) : p2 ( MyLongOwnerWithConversion { } ) { } // expected-warning {{initializing pointer member 'p2' to point to a temporary object whose lifetime is shorter than the lifetime of the constructed object}}
DanglingGslPtrField ( double ) : p ( MyIntOwner { } ) { } // expected-warning {{initializing pointer member 'p' to point to a temporary object whose lifetime is shorter than the lifetime of the constructed object}}
} ;
MyIntPointer danglingGslPtrFromLocal ( ) {
int j ;
2019-09-04 00:17:24 +08:00
return & j ; // TODO
2019-08-07 03:13:29 +08:00
}
MyIntPointer returningLocalPointer ( ) {
MyIntPointer localPointer ;
return localPointer ; // ok
}
MyIntPointer daglingGslPtrFromLocalOwner ( ) {
MyIntOwner localOwner ;
return localOwner ; // expected-warning {{address of stack memory associated with local variable 'localOwner' returned}}
}
MyLongPointerFromConversion daglingGslPtrFromLocalOwnerConv ( ) {
MyLongOwnerWithConversion localOwner ;
return localOwner ; // expected-warning {{address of stack memory associated with local variable 'localOwner' returned}}
}
MyIntPointer danglingGslPtrFromTemporary ( ) {
return MyIntOwner { } ; // expected-warning {{returning address of local temporary object}}
}
2019-08-09 23:16:35 +08:00
MyIntOwner makeTempOwner ( ) ;
MyIntPointer danglingGslPtrFromTemporary2 ( ) {
return makeTempOwner ( ) ; // expected-warning {{returning address of local temporary object}}
}
2019-08-07 03:13:29 +08:00
MyLongPointerFromConversion danglingGslPtrFromTemporaryConv ( ) {
return MyLongOwnerWithConversion { } ; // expected-warning {{returning address of local temporary object}}
}
int * noFalsePositive ( MyIntOwner & o ) {
MyIntPointer p = o ;
return & * p ; // ok
}
MyIntPointer global ;
MyLongPointerFromConversion global2 ;
void initLocalGslPtrWithTempOwner ( ) {
MyIntPointer p = MyIntOwner { } ; // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
p = MyIntOwner { } ; // TODO ?
global = MyIntOwner { } ; // TODO ?
MyLongPointerFromConversion p2 = MyLongOwnerWithConversion { } ; // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
p2 = MyLongOwnerWithConversion { } ; // TODO ?
global2 = MyLongOwnerWithConversion { } ; // TODO ?
}
2019-08-15 00:34:56 +08:00
namespace __gnu_cxx {
2019-08-09 23:16:35 +08:00
template < typename T >
2019-08-10 07:03:50 +08:00
struct basic_iterator {
basic_iterator operator + + ( ) ;
2019-08-11 16:05:28 +08:00
T & operator * ( ) const ;
2019-09-04 00:17:24 +08:00
T * operator - > ( ) const ;
2019-08-10 07:03:50 +08:00
} ;
template < typename T >
bool operator ! = ( basic_iterator < T > , basic_iterator < T > ) ;
2019-08-15 00:34:56 +08:00
}
namespace std {
2019-08-21 00:45:06 +08:00
template < typename T > struct remove_reference { typedef T type ; } ;
template < typename T > struct remove_reference < T & > { typedef T type ; } ;
template < typename T > struct remove_reference < T & & > { typedef T type ; } ;
2019-08-15 00:34:56 +08:00
2019-08-21 00:45:06 +08:00
template < typename T >
2019-08-15 00:34:56 +08:00
typename remove_reference < T > : : type & & move ( T & & t ) noexcept ;
2019-08-09 23:16:35 +08:00
2019-08-21 00:45:06 +08:00
template < typename C >
auto data ( const C & c ) - > decltype ( c . data ( ) ) ;
2019-09-04 00:17:24 +08:00
template < typename C >
auto begin ( C & c ) - > decltype ( c . begin ( ) ) ;
template < typename T , int N >
T * begin ( T ( & array ) [ N ] ) ;
2019-08-09 23:16:35 +08:00
template < typename T >
struct vector {
2019-08-15 00:34:56 +08:00
typedef __gnu_cxx : : basic_iterator < T > iterator ;
2019-08-09 23:16:35 +08:00
iterator begin ( ) ;
2019-08-10 07:03:50 +08:00
iterator end ( ) ;
2019-08-11 22:39:42 +08:00
const T * data ( ) const ;
2019-08-10 07:03:50 +08:00
T & at ( int n ) ;
} ;
template < typename T >
struct basic_string_view {
basic_string_view ( const T * ) ;
const T * begin ( ) const ;
2019-08-09 23:16:35 +08:00
} ;
template < typename T >
struct basic_string {
2019-09-04 00:17:24 +08:00
basic_string ( ) ;
basic_string ( const T * ) ;
2019-08-09 23:16:35 +08:00
const T * c_str ( ) const ;
2019-08-10 07:03:50 +08:00
operator basic_string_view < T > ( ) const ;
2019-08-09 23:16:35 +08:00
} ;
2019-08-10 07:03:50 +08:00
2019-08-09 23:16:35 +08:00
template < typename T >
struct unique_ptr {
2019-08-10 08:32:29 +08:00
T & operator * ( ) ;
2019-08-09 23:16:35 +08:00
T * get ( ) const ;
2019-08-07 03:13:29 +08:00
} ;
2019-08-10 07:03:50 +08:00
template < typename T >
struct optional {
optional ( ) ;
optional ( const T & ) ;
2019-08-15 05:55:57 +08:00
T & operator * ( ) & ;
T & & operator * ( ) & & ;
T & value ( ) & ;
T & & value ( ) & & ;
} ;
template < typename T >
struct stack {
T & top ( ) ;
2019-08-10 07:03:50 +08:00
} ;
2019-08-21 00:45:06 +08:00
struct any { } ;
template < typename T >
T any_cast ( const any & operand ) ;
2019-09-04 00:17:24 +08:00
template < typename T >
struct reference_wrapper {
template < typename U >
reference_wrapper ( U & & ) ;
} ;
template < typename T >
reference_wrapper < T > ref ( T & t ) noexcept ;
2019-08-09 23:16:35 +08:00
}
2019-08-07 03:13:29 +08:00
2019-09-04 00:17:24 +08:00
struct Unannotated {
typedef std : : vector < int > : : iterator iterator ;
iterator begin ( ) ;
operator iterator ( ) const ;
} ;
2019-08-07 03:13:29 +08:00
void modelIterators ( ) {
2019-08-09 23:16:35 +08:00
std : : vector < int > : : iterator it = std : : vector < int > ( ) . begin ( ) ; // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
2019-08-07 03:13:29 +08:00
( void ) it ;
}
2019-08-09 23:16:35 +08:00
std : : vector < int > : : iterator modelIteratorReturn ( ) {
return std : : vector < int > ( ) . begin ( ) ; // expected-warning {{returning address of local temporary object}}
}
2019-08-21 00:45:06 +08:00
const int * modelFreeFunctions ( ) {
return std : : data ( std : : vector < int > ( ) ) ; // expected-warning {{returning address of local temporary object}}
}
int & modelAnyCast ( ) {
return std : : any_cast < int & > ( std : : any { } ) ; // expected-warning {{returning reference to local temporary object}}
}
int modelAnyCast2 ( ) {
return std : : any_cast < int > ( std : : any { } ) ; // ok
}
int modelAnyCast3 ( ) {
return std : : any_cast < int & > ( std : : any { } ) ; // ok
}
2019-08-09 23:16:35 +08:00
const char * danglingRawPtrFromLocal ( ) {
std : : basic_string < char > s ;
return s . c_str ( ) ; // expected-warning {{address of stack memory associated with local variable 's' returned}}
}
2019-08-15 05:55:57 +08:00
int & danglingRawPtrFromLocal2 ( ) {
std : : optional < int > o ;
return o . value ( ) ; // expected-warning {{reference to stack memory associated with local variable 'o' returned}}
}
int & danglingRawPtrFromLocal3 ( ) {
std : : optional < int > o ;
return * o ; // expected-warning {{reference to stack memory associated with local variable 'o' returned}}
}
2019-08-09 23:16:35 +08:00
const char * danglingRawPtrFromTemp ( ) {
return std : : basic_string < char > ( ) . c_str ( ) ; // expected-warning {{returning address of local temporary object}}
}
std : : unique_ptr < int > getUniquePtr ( ) ;
int * danglingUniquePtrFromTemp ( ) {
return getUniquePtr ( ) . get ( ) ; // expected-warning {{returning address of local temporary object}}
}
int * danglingUniquePtrFromTemp2 ( ) {
return std : : unique_ptr < int > ( ) . get ( ) ; // expected-warning {{returning address of local temporary object}}
}
2019-08-10 07:03:50 +08:00
void danglingReferenceFromTempOwner ( ) {
2019-08-15 05:55:57 +08:00
int & & r = * std : : optional < int > ( ) ; // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
int & & r2 = * std : : optional < int > ( 5 ) ; // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
int & & r3 = std : : optional < int > ( 5 ) . value ( ) ; // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
int & r4 = std : : vector < int > ( ) . at ( 3 ) ; // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
2019-08-10 07:03:50 +08:00
}
std : : vector < int > getTempVec ( ) ;
std : : optional < std : : vector < int > > getTempOptVec ( ) ;
2019-08-13 00:19:39 +08:00
void testLoops ( ) {
for ( auto i : getTempVec ( ) ) // ok
;
for ( auto i : * getTempOptVec ( ) ) // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
;
}
2019-08-10 07:03:50 +08:00
int & usedToBeFalsePositive ( std : : vector < int > & v ) {
std : : vector < int > : : iterator it = v . begin ( ) ;
int & value = * it ;
return value ; // ok
}
int & doNotFollowReferencesForLocalOwner ( ) {
std : : unique_ptr < int > localOwner ;
int & p = * localOwner . get ( ) ;
// In real world code localOwner is usually moved here.
return p ; // ok
}
const char * trackThroughMultiplePointer ( ) {
return std : : basic_string_view < char > ( std : : basic_string < char > ( ) ) . begin ( ) ; // expected-warning {{returning address of local temporary object}}
}
2019-08-10 08:32:29 +08:00
struct X {
2019-08-11 16:05:28 +08:00
X ( std : : unique_ptr < int > up ) :
pointee ( * up ) , pointee2 ( up . get ( ) ) , pointer ( std : : move ( up ) ) { }
2019-08-10 08:32:29 +08:00
int & pointee ;
2019-08-11 16:05:28 +08:00
int * pointee2 ;
2019-08-10 08:32:29 +08:00
std : : unique_ptr < int > pointer ;
} ;
2019-08-11 16:05:28 +08:00
std : : vector < int > : : iterator getIt ( ) ;
2019-08-11 22:39:42 +08:00
std : : vector < int > getVec ( ) ;
2019-08-11 16:05:28 +08:00
2019-08-11 22:39:42 +08:00
const int & handleGslPtrInitsThroughReference ( ) {
2019-08-11 16:05:28 +08:00
const auto & it = getIt ( ) ; // Ok, it is lifetime extended.
return * it ;
}
2019-08-11 22:39:42 +08:00
void handleGslPtrInitsThroughReference2 ( ) {
const std : : vector < int > & v = getVec ( ) ;
const int * val = v . data ( ) ; // Ok, it is lifetime extended.
}
2019-09-04 00:17:24 +08:00
void handleTernaryOperator ( bool cond ) {
std : : basic_string < char > def ;
std : : basic_string_view < char > v = cond ? def : " " ; // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
}
std : : reference_wrapper < int > danglingPtrFromNonOwnerLocal ( ) {
int i = 5 ;
return i ; // TODO
}
std : : reference_wrapper < int > danglingPtrFromNonOwnerLocal2 ( ) {
int i = 5 ;
return std : : ref ( i ) ; // TODO
}
std : : reference_wrapper < int > danglingPtrFromNonOwnerLocal3 ( ) {
int i = 5 ;
return std : : reference_wrapper < int > ( i ) ; // TODO
}
std : : reference_wrapper < Unannotated > danglingPtrFromNonOwnerLocal4 ( ) {
Unannotated i ;
return std : : reference_wrapper < Unannotated > ( i ) ; // TODO
}
std : : reference_wrapper < Unannotated > danglingPtrFromNonOwnerLocal5 ( ) {
Unannotated i ;
return std : : ref ( i ) ; // TODO
}
int * returnPtrToLocalArray ( ) {
int a [ 5 ] ;
return std : : begin ( a ) ; // TODO
}
struct ptr_wrapper {
std : : vector < int > : : iterator member ;
} ;
ptr_wrapper getPtrWrapper ( ) ;
std : : vector < int > : : iterator returnPtrFromWrapper ( ) {
ptr_wrapper local = getPtrWrapper ( ) ;
return local . member ;
}
std : : vector < int > : : iterator returnPtrFromWrapperThroughRef ( ) {
ptr_wrapper local = getPtrWrapper ( ) ;
ptr_wrapper & local2 = local ;
return local2 . member ;
}
std : : vector < int > : : iterator returnPtrFromWrapperThroughRef2 ( ) {
ptr_wrapper local = getPtrWrapper ( ) ;
std : : vector < int > : : iterator & local2 = local . member ;
return local2 ;
}
void checkPtrMemberFromAggregate ( ) {
std : : vector < int > : : iterator local = getPtrWrapper ( ) . member ; // OK.
}
std : : vector < int > : : iterator doNotInterferWithUnannotated ( ) {
Unannotated value ;
// Conservative choice for now. Probably not ok, but we do not warn.
return std : : begin ( value ) ;
}
std : : vector < int > : : iterator doNotInterferWithUnannotated2 ( ) {
Unannotated value ;
return value ;
}
std : : vector < int > : : iterator supportDerefAddrofChain ( int a , std : : vector < int > : : iterator value ) {
switch ( a ) {
default :
return value ;
case 1 :
return * & value ;
case 2 :
return * & * & value ;
case 3 :
return * & * & * & value ;
}
}
int & supportDerefAddrofChain2 ( int a , std : : vector < int > : : iterator value ) {
switch ( a ) {
default :
return * value ;
case 1 :
return * * & value ;
case 2 :
return * * & * & value ;
case 3 :
return * * & * & * & value ;
}
}
int * supportDerefAddrofChain3 ( int a , std : : vector < int > : : iterator value ) {
switch ( a ) {
default :
return & * value ;
case 1 :
return & * & * value ;
case 2 :
return & * & * * & value ;
case 3 :
return & * & * * & * & value ;
}
}
MyIntPointer handleDerivedToBaseCast1 ( MySpecialIntPointer ptr ) {
return ptr ;
}
MyIntPointer handleDerivedToBaseCast2 ( MyOwnerIntPointer ptr ) {
return ptr ; // expected-warning {{address of stack memory associated with parameter 'ptr' returned}}
}
2019-11-28 01:08:51 +08:00
std : : vector < int > : : iterator noFalsePositiveWithVectorOfPointers ( ) {
std : : vector < std : : vector < int > : : iterator > iters ;
return iters . at ( 0 ) ;
}