2009-03-22 12:00:21 +01:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2019-02-09 07:24:06 +01:00
* Copyright ( C ) 2007 - 2019 Cppcheck team .
2009-03-22 12:00:21 +01:00
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
2009-09-27 17:08:31 +02:00
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
2009-03-22 12:00:21 +01:00
*/
2017-05-27 04:33:47 +02:00
2009-10-25 12:49:06 +01:00
# include "checkautovariables.h"
2017-05-27 04:33:47 +02:00
# include "settings.h"
2009-03-22 12:00:21 +01:00
# include "testsuite.h"
2017-05-27 04:33:47 +02:00
# include "tokenize.h"
2009-03-22 12:00:21 +01:00
2011-10-13 20:53:06 +02:00
class TestAutoVariables : public TestFixture {
2009-03-22 12:00:21 +01:00
public :
2014-11-20 14:20:09 +01:00
TestAutoVariables ( ) : TestFixture ( " TestAutoVariables " ) {
2013-08-07 16:27:37 +02:00
}
2009-03-22 12:00:21 +01:00
private :
2015-10-07 14:40:09 +02:00
Settings settings ;
2009-03-22 12:00:21 +01:00
2015-03-15 12:36:40 +01:00
void check ( const char code [ ] , bool inconclusive = false , bool runSimpleChecks = true , const char * filename = " test.cpp " ) {
2010-12-01 18:00:55 +01:00
// Clear the error buffer..
errout . str ( " " ) ;
2011-08-09 18:24:39 +02:00
settings . inconclusive = inconclusive ;
2010-12-01 18:00:55 +01:00
// Tokenize..
Tokenizer tokenizer ( & settings , this ) ;
2009-03-22 12:00:21 +01:00
std : : istringstream istr ( code ) ;
2015-03-15 12:36:40 +01:00
tokenizer . tokenize ( istr , filename ) ;
2011-02-12 15:39:26 +01:00
CheckAutoVariables checkAutoVariables ( & tokenizer , & settings , this ) ;
2012-03-01 18:38:20 +01:00
checkAutoVariables . returnReference ( ) ;
2013-10-06 16:07:27 +02:00
checkAutoVariables . assignFunctionArg ( ) ;
2018-11-10 16:40:40 +01:00
checkAutoVariables . checkVarLifetime ( ) ;
2011-02-12 15:39:26 +01:00
2013-04-13 18:38:15 +02:00
if ( runSimpleChecks ) {
2013-12-30 17:45:28 +01:00
tokenizer . simplifyTokenList2 ( ) ;
2013-04-13 18:38:15 +02:00
// Check auto variables
checkAutoVariables . autoVariables ( ) ;
}
2009-03-22 12:00:21 +01:00
}
2019-01-12 15:45:25 +01:00
void run ( ) OVERRIDE {
2015-10-07 14:40:09 +02:00
settings . addEnabled ( " warning " ) ;
settings . addEnabled ( " style " ) ;
LOAD_LIB_2 ( settings . library , " std.cfg " ) ;
2011-02-08 01:26:34 +01:00
TEST_CASE ( testautovar1 ) ;
TEST_CASE ( testautovar2 ) ;
2011-07-21 01:02:54 +02:00
TEST_CASE ( testautovar3 ) ; // ticket #2925
2011-07-22 00:20:19 +02:00
TEST_CASE ( testautovar4 ) ; // ticket #2928
2011-07-22 04:26:42 +02:00
TEST_CASE ( testautovar5 ) ; // ticket #2926
2011-07-27 10:43:44 +02:00
TEST_CASE ( testautovar6 ) ; // ticket #2931
2011-09-02 04:22:33 +02:00
TEST_CASE ( testautovar7 ) ; // ticket #3066
2012-03-01 18:38:20 +01:00
TEST_CASE ( testautovar8 ) ;
TEST_CASE ( testautovar9 ) ;
2013-02-01 19:16:17 +01:00
TEST_CASE ( testautovar10 ) ; // ticket #2930 - void f(char *p) { p = '\0'; }
2013-06-13 16:19:19 +02:00
TEST_CASE ( testautovar11 ) ; // ticket #4641 - fp, assign local struct member address to function parameter
2013-09-28 00:14:12 +02:00
TEST_CASE ( testautovar12 ) ; // ticket #5024 - crash
2014-03-09 08:17:24 +01:00
TEST_CASE ( testautovar13 ) ; // ticket #5537 - crash
2014-10-21 16:21:33 +02:00
TEST_CASE ( testautovar14 ) ; // ticket #4776 - assignment of function parameter, goto
2015-02-24 06:11:31 +01:00
TEST_CASE ( testautovar15 ) ; // ticket #6538
2018-12-01 10:11:02 +01:00
TEST_CASE ( testautovar16 ) ; // ticket #8114
2011-02-08 01:26:34 +01:00
TEST_CASE ( testautovar_array1 ) ;
TEST_CASE ( testautovar_array2 ) ;
2015-08-28 20:29:51 +02:00
TEST_CASE ( testautovar_ptrptr ) ; // ticket #6956
2011-02-08 01:26:34 +01:00
TEST_CASE ( testautovar_return1 ) ;
TEST_CASE ( testautovar_return2 ) ;
2011-08-10 18:16:31 +02:00
TEST_CASE ( testautovar_return3 ) ;
2018-11-11 07:52:38 +01:00
TEST_CASE ( testautovar_return4 ) ;
2009-07-27 19:32:01 +02:00
TEST_CASE ( testautovar_extern ) ;
2009-08-09 15:43:00 +02:00
TEST_CASE ( testinvaliddealloc ) ;
2014-05-01 07:32:37 +02:00
TEST_CASE ( testinvaliddealloc_C ) ;
2011-05-07 01:26:04 +02:00
TEST_CASE ( testassign1 ) ; // Ticket #1819
TEST_CASE ( testassign2 ) ; // Ticket #2765
2009-06-09 19:45:58 +02:00
2018-01-24 21:33:58 +01:00
TEST_CASE ( assignAddressOfLocalArrayToGlobalPointer ) ;
2018-01-25 22:50:41 +01:00
TEST_CASE ( assignAddressOfLocalVariableToGlobalPointer ) ;
2018-01-24 21:33:58 +01:00
2009-06-09 19:45:58 +02:00
TEST_CASE ( returnLocalVariable1 ) ;
TEST_CASE ( returnLocalVariable2 ) ;
2015-11-15 14:48:13 +01:00
TEST_CASE ( returnLocalVariable3 ) ; // &x[0]
TEST_CASE ( returnLocalVariable4 ) ; // x+y
TEST_CASE ( returnLocalVariable5 ) ; // cast
2018-01-27 14:48:45 +01:00
TEST_CASE ( returnLocalVariable6 ) ; // valueflow
2010-01-23 20:39:12 +01:00
// return reference..
2011-02-08 01:26:34 +01:00
TEST_CASE ( returnReference1 ) ;
TEST_CASE ( returnReference2 ) ;
2011-02-12 15:39:26 +01:00
TEST_CASE ( returnReference3 ) ;
2011-12-26 07:44:16 +01:00
TEST_CASE ( returnReference4 ) ;
2012-01-08 15:32:22 +01:00
TEST_CASE ( returnReference5 ) ;
2012-03-28 18:21:06 +02:00
TEST_CASE ( returnReference6 ) ;
2012-07-18 07:22:29 +02:00
TEST_CASE ( returnReference7 ) ;
2019-01-26 11:03:57 +01:00
TEST_CASE ( returnReferenceFunction ) ;
2019-02-22 06:38:56 +01:00
TEST_CASE ( returnReferenceContainer ) ;
2014-05-22 11:39:11 +02:00
TEST_CASE ( returnReferenceLiteral ) ;
TEST_CASE ( returnReferenceCalculation ) ;
2015-08-14 13:03:07 +02:00
TEST_CASE ( returnReferenceLambda ) ;
2015-08-26 13:31:51 +02:00
TEST_CASE ( returnReferenceInnerScope ) ;
2019-01-31 10:34:41 +01:00
TEST_CASE ( returnReferenceRecursive ) ;
2010-01-26 22:11:34 +01:00
2019-01-23 07:29:16 +01:00
TEST_CASE ( danglingReference ) ;
2011-04-18 06:56:39 +02:00
// global namespace
TEST_CASE ( testglobalnamespace ) ;
2011-09-01 03:36:31 +02:00
TEST_CASE ( returnParameterAddress ) ;
2014-03-01 16:30:59 +01:00
TEST_CASE ( testconstructor ) ; // ticket #5478 - crash
2014-03-22 11:14:11 +01:00
TEST_CASE ( variableIsUsedInScope ) ; // ticket #5599 crash in variableIsUsedInScope()
2018-11-10 16:40:40 +01:00
TEST_CASE ( danglingLifetimeLambda ) ;
TEST_CASE ( danglingLifetimeContainer ) ;
TEST_CASE ( danglingLifetime ) ;
2018-11-16 06:12:28 +01:00
TEST_CASE ( danglingLifetimeFunction ) ;
2018-11-11 16:43:54 +01:00
TEST_CASE ( invalidLifetime ) ;
2009-03-22 12:00:21 +01:00
}
2014-11-20 14:20:09 +01:00
void testautovar1 ( ) {
2009-03-28 21:47:38 +01:00
check ( " void func1(int **res) \n "
2009-03-22 12:00:21 +01:00
" { \n "
2010-01-01 22:53:34 +01:00
" int num = 2; \n "
" *res = # \n "
" } " ) ;
2012-07-07 20:31:18 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (error) Address of local auto-variable assigned to a function parameter. \n " , errout . str ( ) ) ;
2009-06-06 21:25:41 +02:00
2011-04-27 02:16:09 +02:00
check ( " void func1(int **res) \n "
" { \n "
" int num = 2; \n "
" res = # \n "
" } " ) ;
2014-08-04 11:45:24 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (warning) Assignment of function parameter has no effect outside the function. Did you forget dereferencing it? \n " , errout . str ( ) ) ;
2011-04-27 02:16:09 +02:00
2009-06-06 21:25:41 +02:00
check ( " void func1(int **res) \n "
" { \n "
" int num = 2; \n "
" foo.res = # \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2009-03-22 12:00:21 +01:00
}
2009-07-27 19:34:17 +02:00
2014-11-20 14:20:09 +01:00
void testautovar2 ( ) {
2011-02-08 01:26:34 +01:00
check ( " class Fred { \n "
" void func1(int **res); \n "
" } \n "
" void Fred::func1(int **res) \n "
" { \n "
" int num = 2; \n "
" *res = # \n "
" } " ) ;
2012-07-07 20:31:18 +02:00
ASSERT_EQUALS ( " [test.cpp:7]: (error) Address of local auto-variable assigned to a function parameter. \n " , errout . str ( ) ) ;
2011-02-08 01:26:34 +01:00
2011-04-27 02:16:09 +02:00
check ( " class Fred { \n "
" void func1(int **res); \n "
" } \n "
" void Fred::func1(int **res) \n "
" { \n "
" int num = 2; \n "
" res = # \n "
" } " ) ;
2014-08-04 11:45:24 +02:00
ASSERT_EQUALS ( " [test.cpp:7]: (warning) Assignment of function parameter has no effect outside the function. Did you forget dereferencing it? \n " , errout . str ( ) ) ;
2011-04-27 02:16:09 +02:00
2011-02-08 01:26:34 +01:00
check ( " class Fred { \n "
" void func1(int **res); \n "
" } \n "
" void Fred::func1(int **res) \n "
" { \n "
" int num = 2; \n "
" foo.res = # \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void testautovar3 ( ) { // ticket #2925
2011-07-21 01:02:54 +02:00
check ( " void foo(int **p) \n "
" { \n "
" int x[100]; \n "
" *p = x; \n "
" } " ) ;
2012-07-07 20:31:18 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (error) Address of local auto-variable assigned to a function parameter. \n " , errout . str ( ) ) ;
2011-07-21 01:02:54 +02:00
}
2014-11-20 14:20:09 +01:00
void testautovar4 ( ) { // ticket #2928
2011-07-22 00:20:19 +02:00
check ( " void foo(int **p) \n "
" { \n "
" static int x[100]; \n "
" *p = x; \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void testautovar5 ( ) { // ticket #2926
2011-07-22 04:26:42 +02:00
check ( " void foo(struct AB *ab) \n "
" { \n "
" char a; \n "
" ab->a = &a; \n "
2011-08-09 18:24:39 +02:00
" } " , false ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " void foo(struct AB *ab) \n "
" { \n "
" char a; \n "
" ab->a = &a; \n "
" } " , true ) ;
2012-07-07 20:31:18 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (error, inconclusive) Address of local auto-variable assigned to a function parameter. \n " , errout . str ( ) ) ;
2011-07-22 04:26:42 +02:00
}
2014-11-20 14:20:09 +01:00
void testautovar6 ( ) { // ticket #2931
2011-07-22 14:31:31 +02:00
check ( " void foo(struct X *x) \n "
" { \n "
" char a[10]; \n "
" x->str = a; \n "
2011-08-09 18:24:39 +02:00
" } " , false ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " void foo(struct X *x) \n "
" { \n "
" char a[10]; \n "
" x->str = a; \n "
" } " , true ) ;
2012-07-07 20:31:18 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (error, inconclusive) Address of local auto-variable assigned to a function parameter. \n " , errout . str ( ) ) ;
2011-09-02 04:22:33 +02:00
}
2014-11-20 14:20:09 +01:00
void testautovar7 ( ) { // ticket #3066
2011-09-02 04:22:33 +02:00
check ( " struct txt_scrollpane_s * TXT_NewScrollPane(struct txt_widget_s * target) \n "
" { \n "
" struct txt_scrollpane_s * scrollpane; \n "
" target->parent = &scrollpane->widget; \n "
" return scrollpane; \n "
" } " , false ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2011-07-22 14:31:31 +02:00
}
2014-11-20 14:20:09 +01:00
void testautovar8 ( ) {
2012-03-01 18:38:20 +01:00
check ( " void foo(int*& p) { \n "
" int i = 0; \n "
" p = &i; \n "
" } " , false ) ;
2012-07-07 20:31:18 +02:00
ASSERT_EQUALS ( " [test.cpp:3]: (error) Address of local auto-variable assigned to a function parameter. \n " , errout . str ( ) ) ;
2012-07-13 14:21:45 +02:00
check ( " void foo(std::string& s) { \n "
2013-04-13 18:38:15 +02:00
" s = foo; \n "
2012-07-13 14:21:45 +02:00
" } " , false ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2012-03-01 18:38:20 +01:00
}
2014-11-20 14:20:09 +01:00
void testautovar9 ( ) {
2012-03-01 18:38:20 +01:00
check ( " struct FN {int i;}; \n "
" struct FP {FN* f}; \n "
" void foo(int*& p, FN* p_fp) { \n "
" FN fn; \n "
" FP fp; \n "
" p = &fn.i; \n "
" p = &p_fp->i; \n "
" p = &fp.f->i; \n "
" } " , false ) ;
2012-07-07 20:31:18 +02:00
ASSERT_EQUALS ( " [test.cpp:6]: (error) Address of local auto-variable assigned to a function parameter. \n " , errout . str ( ) ) ;
2012-03-01 18:38:20 +01:00
}
2014-11-20 14:20:09 +01:00
void testautovar10 ( ) { // #2930 - assignment of function parameter
2013-02-01 19:16:17 +01:00
check ( " void foo(char* p) { \n "
" p = 0; \n "
" } " ) ;
2014-08-04 11:45:24 +02:00
ASSERT_EQUALS ( " [test.cpp:2]: (warning) Assignment of function parameter has no effect outside the function. Did you forget dereferencing it? \n " , errout . str ( ) ) ;
2013-02-01 19:16:17 +01:00
2013-02-18 17:52:49 +01:00
check ( " void foo(int b) { \n "
" b = foo(b); \n "
" } " ) ;
2018-08-17 19:56:36 +02:00
ASSERT_EQUALS ( " [test.cpp:2]: (style) Assignment of function parameter has no effect outside the function. \n " , errout . str ( ) ) ;
check ( " void foo(int b) { \n "
" b += 1; \n "
" } " ) ;
2014-08-04 11:45:24 +02:00
ASSERT_EQUALS ( " [test.cpp:2]: (style) Assignment of function parameter has no effect outside the function. \n " , errout . str ( ) ) ;
2013-02-18 17:52:49 +01:00
2018-06-24 08:25:19 +02:00
check ( " void foo(std::string s) { \n "
" s = foo(b); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:2]: (style) Assignment of function parameter has no effect outside the function. \n " , errout . str ( ) ) ;
2015-08-09 14:51:23 +02:00
check ( " void foo(char* p) { \n " // don't warn for self assignment, there is another warning for this
" p = p; \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2013-02-01 19:16:17 +01:00
check ( " void foo(char* p) { \n "
" if (!p) p = buf; \n "
" *p = 0; \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2013-02-02 15:26:14 +01:00
check ( " void foo(char* p) { \n "
" if (!p) p = buf; \n "
" do_something(p); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2013-02-18 17:52:49 +01:00
check ( " void foo(char* p) { \n "
" while (!p) p = buf; \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " void foo(char* p) { \n "
" p = 0; \n "
" asm( \" somecmd \" ); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " void foo(Foo* p) { \n "
" p = 0; \n "
" } " ) ;
2014-08-04 11:45:24 +02:00
ASSERT_EQUALS ( " [test.cpp:2]: (warning) Assignment of function parameter has no effect outside the function. Did you forget dereferencing it? \n " , errout . str ( ) ) ;
2013-02-18 17:52:49 +01:00
check ( " class Foo {}; \n "
" void foo(Foo p) { \n "
" p = 0; \n "
" } " ) ;
2014-08-04 11:45:24 +02:00
ASSERT_EQUALS ( " [test.cpp:3]: (style) Assignment of function parameter has no effect outside the function. \n " , errout . str ( ) ) ;
2013-02-18 17:52:49 +01:00
check ( " void foo(Foo p) { \n "
" p = 0; \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " void foo(int& p) { \n "
" p = 0; \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2013-10-06 16:07:27 +02:00
check ( " double foo(double d) { \n " // #5005
" int i = d; \n "
" d = i; \n "
" return d; "
" } " , false , false ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2014-08-04 11:45:24 +02:00
check ( " void foo(int* ptr) { \n " // #4793
" ptr++; \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:2]: (warning) Assignment of function parameter has no effect outside the function. Did you forget dereferencing it? \n " , errout . str ( ) ) ;
2016-10-10 21:34:40 +02:00
check ( " void foo(int* ptr) { \n " // #3177
" --ptr; \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:2]: (warning) Assignment of function parameter has no effect outside the function. Did you forget dereferencing it? \n " , errout . str ( ) ) ;
2016-12-19 15:25:36 +01:00
check ( " void foo(struct S* const x) { \n " // #7839
" ++x->n; \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2013-02-01 19:16:17 +01:00
}
2014-11-20 14:20:09 +01:00
void testautovar11 ( ) { // #4641 - fp, assign local struct member address to function parameter
2013-06-13 16:19:19 +02:00
check ( " struct A { \n "
2015-08-25 21:19:19 +02:00
" char (*data)[10]; \n "
2013-06-13 16:19:19 +02:00
" }; \n "
" void foo(char** p) { \n "
" struct A a = bar(); \n "
2015-08-25 21:19:19 +02:00
" *p = &(*a.data)[0]; \n "
2013-06-13 16:19:19 +02:00
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " struct A { \n "
" char data[10]; \n "
" }; \n "
" void foo(char** p) { \n "
" struct A a = bar(); \n "
" *p = &a.data[0]; \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:6]: (error) Address of local auto-variable assigned to a function parameter. \n " , errout . str ( ) ) ;
2013-10-06 14:23:26 +02:00
// #4998
check ( " void f(s8**out) { \n "
" s8 *p; \n " // <- p is pointer => no error
" *out = &p[1]; \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " void f(s8**out) { \n "
" s8 p[10]; \n " // <- p is array => error
" *out = &p[1]; \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (error) Address of local auto-variable assigned to a function parameter. \n " , errout . str ( ) ) ;
2013-06-13 16:19:19 +02:00
}
2013-09-28 09:32:41 +02:00
2014-11-20 14:20:09 +01:00
void testautovar12 ( ) { // Ticket #5024, #5050 - Crash on invalid input
2018-09-08 21:10:34 +02:00
ASSERT_THROW ( check ( " void f(int* a) { a = } " ) , InternalError ) ;
2014-03-01 10:37:55 +01:00
check ( " struct custom_type { custom_type(int) {} }; \n "
" void func(int) {} \n "
" int var; \n "
" void init() { func(var); } \n "
" UNKNOWN_MACRO_EXPANDING_TO_SIGNATURE { custom_type a(var); } " ) ;
2013-09-28 00:14:12 +02:00
}
2013-06-13 16:19:19 +02:00
2014-11-20 14:20:09 +01:00
void testautovar13 ( ) { // Ticket #5537
2014-03-09 08:17:24 +01:00
check ( " class FileManager { \n "
" FileManager() : UniqueRealDirs(*new UniqueDirContainer()) \n "
" {} \n "
" ~FileManager() { \n "
" delete &UniqueRealDirs; \n "
" } \n "
" }; \n " ) ;
}
2014-11-20 14:20:09 +01:00
void testautovar14 ( ) { // Ticket #4776
2014-10-21 16:21:33 +02:00
check ( " void f(int x) { \n "
" label: "
" if (x>0) { \n "
" x = x >> 1; \n "
" goto label; \n "
" } \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2015-02-24 06:11:31 +01:00
}
void testautovar15 ( ) { // Ticket #6538
check ( " static const float4 darkOutline(0.05f, 0.05f, 0.05f, 0.95f); \n "
" static const float darkLuminosity = 0.05 + \n "
" 0.0722f * math::powf(darkOutline[2], 2.2); \n "
" const float4* ChooseOutlineColor(const float4& textColor) { \n "
" const float lumdiff = something; \n "
" if (lumdiff > 5.0f) \n "
" return &darkOutline; \n "
" return 0; \n "
" } " , false , false ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2014-10-21 16:21:33 +02:00
}
2018-12-01 10:11:02 +01:00
void testautovar16 ( ) { // Ticket #8114
check ( " void f(const void* ptr, bool* result) { \n "
" int dummy; \n "
" *result = (&dummy < ptr); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void testautovar_array1 ( ) {
2009-03-22 12:00:21 +01:00
check ( " void func1(int* arr[2]) \n "
" { \n "
" int num=2; "
2010-01-23 20:39:12 +01:00
" arr[0]=# \n "
" } " ) ;
2012-07-07 20:31:18 +02:00
ASSERT_EQUALS ( " [test.cpp:3]: (error) Address of local auto-variable assigned to a function parameter. \n " , errout . str ( ) ) ;
2009-03-22 12:00:21 +01:00
}
2009-07-27 19:34:17 +02:00
2014-11-20 14:20:09 +01:00
void testautovar_array2 ( ) {
2011-02-08 01:26:34 +01:00
check ( " class Fred { \n "
" void func1(int* arr[2]); \n "
" } \n "
" void Fred::func1(int* arr[2]) \n "
" { \n "
" int num=2; "
" arr[0]=# \n "
" } " ) ;
2012-07-07 20:31:18 +02:00
ASSERT_EQUALS ( " [test.cpp:6]: (error) Address of local auto-variable assigned to a function parameter. \n " , errout . str ( ) ) ;
2011-02-08 01:26:34 +01:00
}
2015-08-28 20:29:51 +02:00
void testautovar_ptrptr ( ) { // #6596
check ( " void remove_duplicate_matches (char **matches) { \n "
" char dead_slot; \n "
" matches[0] = (char *)&dead_slot; \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (error) Address of local auto-variable assigned to a function parameter. \n " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void testautovar_return1 ( ) {
2009-03-28 21:54:12 +01:00
check ( " int* func1() \n "
" { \n "
" int num=2; "
2011-02-08 01:26:34 +01:00
" return # "
" } " ) ;
2018-11-12 10:08:17 +01:00
ASSERT_EQUALS ( " [test.cpp:3] -> [test.cpp:3] -> [test.cpp:3]: (error) Returning pointer to local variable 'num' that will be invalid when returning. \n " , errout . str ( ) ) ;
2009-03-28 21:54:12 +01:00
}
2009-06-09 19:45:58 +02:00
2014-11-20 14:20:09 +01:00
void testautovar_return2 ( ) {
2011-02-08 01:26:34 +01:00
check ( " class Fred { \n "
2015-12-05 20:55:26 +01:00
" int* func1(); \n "
2011-02-08 01:26:34 +01:00
" } \n "
" int* Fred::func1() \n "
" { \n "
" int num=2; "
" return # "
" } " ) ;
2018-11-12 10:08:17 +01:00
ASSERT_EQUALS ( " [test.cpp:6] -> [test.cpp:6] -> [test.cpp:6]: (error) Returning pointer to local variable 'num' that will be invalid when returning. \n " , errout . str ( ) ) ;
2011-02-08 01:26:34 +01:00
}
2014-11-20 14:20:09 +01:00
void testautovar_return3 ( ) {
2011-08-10 18:16:31 +02:00
// #2975 - FP
check ( " void** f() \n "
" { \n "
" void *&value = tls[id]; "
" return &value; "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2018-11-11 07:52:38 +01:00
void testautovar_return4 ( ) {
// #8058 - FP ignore return in lambda
check ( " void foo() { \n "
" int cond2; \n "
" dostuff([&cond2]() { return &cond2; }); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void testautovar_extern ( ) {
2009-07-27 19:32:01 +02:00
check ( " struct foo *f() \n "
" { \n "
" extern struct foo f; \n "
" return &f; \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2009-07-27 19:32:01 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void testinvaliddealloc ( ) {
2012-04-26 16:44:33 +02:00
check ( " void func1() { \n "
" char tmp1[256]; \n "
" free(tmp1); \n "
" char tmp2[256]; \n "
" delete tmp2; \n "
" char tmp3[256]; \n "
2013-04-13 18:38:15 +02:00
" delete tmp3; \n "
2012-04-26 16:44:33 +02:00
" char tmp4[256]; \n "
" delete[] (tmp4); \n "
" char tmp5[256]; \n "
" delete[] tmp5; \n "
" } " ) ;
2012-07-07 20:31:18 +02:00
ASSERT_EQUALS ( " [test.cpp:3]: (error) Deallocation of an auto-variable results in undefined behaviour. \n "
" [test.cpp:5]: (error) Deallocation of an auto-variable results in undefined behaviour. \n "
" [test.cpp:7]: (error) Deallocation of an auto-variable results in undefined behaviour. \n "
" [test.cpp:9]: (error) Deallocation of an auto-variable results in undefined behaviour. \n "
" [test.cpp:11]: (error) Deallocation of an auto-variable results in undefined behaviour. \n " , errout . str ( ) ) ;
2012-04-26 16:44:33 +02:00
check ( " void func1() { \n "
" char* tmp1[256]; \n "
" init(tmp1); \n "
" delete tmp1[34]; \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2009-08-16 10:27:40 +02:00
2018-11-03 18:55:12 +01:00
check ( " void func1() { \n "
" static char tmp1[256]; \n "
" char *p = tmp1; \n "
" free(p); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:4]: (error) Deallocation of an static variable (tmp1) results in undefined behaviour. \n " , errout . str ( ) ) ;
check ( " char tmp1[256]; \n "
" void func1() { \n "
" char *p; if (x) p = tmp1; \n "
" free(p); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:4]: (error) Deallocation of an global variable (tmp1) results in undefined behaviour. \n " , errout . str ( ) ) ;
2009-08-16 10:27:40 +02:00
check ( " void f() \n "
" { \n "
" char psz_title[10]; \n "
" { \n "
" char *psz_title = 0; \n "
" abc(0, psz_title); \n "
" free(psz_title); \n "
" } \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2014-03-06 06:32:30 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// #2298 new check: passing stack-address to free()
check ( " int main() { \n "
" int *p = malloc(4); \n "
" free(&p); \n "
" return 0; \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (error) Deallocation of an auto-variable results in undefined behaviour. \n " , errout . str ( ) ) ;
check ( " int main() { \n "
" int i; \n "
" free(&i); \n "
" return 0; \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (error) Deallocation of an auto-variable results in undefined behaviour. \n " , errout . str ( ) ) ;
2014-04-27 10:56:55 +02:00
// #5732
check ( " int main() { \n "
" long (*pKoeff)[256] = new long[9][256]; \n "
" delete[] pKoeff; \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " int main() { \n "
" long *pKoeff[256]; \n "
" delete[] pKoeff; \n "
" } " ) ;
2015-08-25 21:19:19 +02:00
ASSERT_EQUALS ( " [test.cpp:3]: (error) Deallocation of an auto-variable results in undefined behaviour. \n " , errout . str ( ) ) ;
2014-05-01 07:32:37 +02:00
2014-05-12 19:53:49 +02:00
check ( " int main() { \n "
" long *pKoeff[256]; \n "
" free (pKoeff); \n "
" } " ) ;
2015-08-25 21:19:19 +02:00
ASSERT_EQUALS ( " [test.cpp:3]: (error) Deallocation of an auto-variable results in undefined behaviour. \n " , errout . str ( ) ) ;
2014-05-12 19:53:49 +02:00
check ( " void foo() { \n "
2014-05-15 21:20:16 +02:00
" const intPtr& intref = Getter(); \n "
" delete intref; \n "
2014-05-12 19:53:49 +02:00
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " void test() { \n "
" MyObj& obj = *new MyObj; \n "
" delete &obj; \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2015-06-20 21:00:54 +02:00
// #6506
check ( " struct F { \n "
" void free(void*) {} \n "
" }; \n "
" void foo() { \n "
" char c1[1]; \n "
" F().free(c1); \n "
" char *c2 = 0; \n "
" F().free(&c2); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " class foo { \n "
" void free(void* ); \n "
" void someMethod() { \n "
" char **dst_copy = NULL; \n "
" free(&dst_copy); \n "
" } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2015-11-11 16:59:13 +01:00
// #6551
check ( " bool foo( ) { \n "
" SwTxtFld * pTxtFld = GetFldTxtAttrAt(); \n "
" delete static_cast<SwFmtFld*>(&pTxtFld->GetAttr()); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2018-12-29 09:31:21 +01:00
// #8910
check ( " void f() { \n "
" char stack[512]; \n "
" RGNDATA *data; \n "
" if (data_size > sizeof (stack)) data = malloc (data_size); \n "
" else data = (RGNDATA *)stack; \n "
" if ((char *)data != stack) free (data); \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2014-05-01 07:32:37 +02:00
}
2014-11-20 14:20:09 +01:00
void testinvaliddealloc_C ( ) {
2014-05-01 07:32:37 +02:00
// #5691
check ( " void svn_repos_dir_delta2() { \n "
" struct context c; \n "
" SVN_ERR(delete(&c, root_baton, src_entry, pool)); \n "
" } \n " , false , true , " test.c " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2009-08-09 15:43:00 +02:00
}
2009-06-09 19:45:58 +02:00
2014-11-20 14:20:09 +01:00
void testassign1 ( ) { // Ticket #1819
2010-10-22 21:12:28 +02:00
check ( " void f(EventPtr *eventP, ActionPtr **actionsP) { \n "
" EventPtr event = *eventP; \n "
" *actionsP = &event->actions; \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2011-05-07 01:26:04 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void testassign2 ( ) { // Ticket #2765
2011-05-07 01:26:04 +02:00
check ( " static void function(unsigned long **datap) { \n "
" struct my_s *mr = global_structure_pointer; \n "
" *datap = &mr->value; \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2011-05-07 00:18:48 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2018-01-24 21:33:58 +01:00
}
void assignAddressOfLocalArrayToGlobalPointer ( ) {
check ( " int *p; \n "
" void f() { \n "
" int x[10]; \n "
" p = x; \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:4]: (warning) Address of local array x is assigned to global pointer p and not reassigned before x goes out of scope. \n " , errout . str ( ) ) ;
check ( " int *p; \n "
" void f() { \n "
" int x[10]; \n "
" p = x; \n "
" p = 0; \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2018-01-25 22:50:41 +01:00
}
void assignAddressOfLocalVariableToGlobalPointer ( ) {
check ( " int *p; \n "
" void f() { \n "
" int x; \n "
" p = &x; \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:4]: (warning) Address of local variable x is assigned to global pointer p and not reassigned before x goes out of scope. \n " , errout . str ( ) ) ;
check ( " int *p; \n "
" void f() { \n "
" int x; \n "
" p = &x; \n "
" p = 0; \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-10-22 21:12:28 +02:00
}
2014-11-20 14:20:09 +01:00
void returnLocalVariable1 ( ) {
2009-06-09 19:45:58 +02:00
check ( " char *foo() \n "
" { \n "
" char str[100] = {0}; \n "
" return str; \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2018-11-21 08:43:57 +01:00
ASSERT_EQUALS (
2018-12-15 17:58:45 +01:00
" [test.cpp:4] -> [test.cpp:3] -> [test.cpp:4]: (error) Returning pointer to local variable 'str' that will be invalid when returning. \n " ,
2018-11-21 08:43:57 +01:00
errout . str ( ) ) ;
2011-02-08 01:26:34 +01:00
2015-11-15 12:10:35 +01:00
check ( " char *foo() \n " // use ValueFlow
" { \n "
" char str[100] = {0}; \n "
" char *p = str; \n "
" return p; \n "
" } " ) ;
2018-11-21 08:43:57 +01:00
ASSERT_EQUALS (
2018-12-15 17:58:45 +01:00
" [test.cpp:4] -> [test.cpp:3] -> [test.cpp:5]: (error) Returning pointer to local variable 'str' that will be invalid when returning. \n " ,
2018-11-21 08:43:57 +01:00
errout . str ( ) ) ;
2015-11-15 12:10:35 +01:00
2011-02-08 01:26:34 +01:00
check ( " class Fred { \n "
" char *foo(); \n "
" }; \n "
" char *Fred::foo() \n "
" { \n "
" char str[100] = {0}; \n "
" return str; \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2018-11-21 08:43:57 +01:00
ASSERT_EQUALS (
2018-12-15 17:58:45 +01:00
" [test.cpp:7] -> [test.cpp:6] -> [test.cpp:7]: (error) Returning pointer to local variable 'str' that will be invalid when returning. \n " ,
2018-11-21 08:43:57 +01:00
errout . str ( ) ) ;
2016-01-30 20:02:39 +01:00
check ( " char * format_reg(char *outbuffer_start) { \n "
" return outbuffer_start; \n "
" } \n "
" void print_with_operands() { \n "
" char temp[42]; \n "
" char *tp = temp; \n "
" tp = format_reg(tp); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2009-06-09 19:45:58 +02:00
}
2014-11-20 14:20:09 +01:00
void returnLocalVariable2 ( ) {
2009-06-09 19:45:58 +02:00
check ( " std::string foo() \n "
" { \n "
" char str[100] = {0}; \n "
" return str; \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2009-06-09 19:45:58 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2011-02-08 01:26:34 +01:00
check ( " class Fred { \n "
" std::string foo(); \n "
" }; \n "
" std::string Fred::foo() \n "
" { \n "
" char str[100] = {0}; \n "
" return str; \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2011-02-08 01:26:34 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2009-06-09 19:45:58 +02:00
}
2010-01-23 20:39:12 +01:00
2015-11-15 14:48:13 +01:00
void returnLocalVariable3 ( ) { // &x[..]
// #3030
check ( " char *foo() { \n "
" char q[] = \" AAAAAAAAAAAA \" ; \n "
" return &q[1]; \n "
" } " ) ;
2018-11-12 10:08:17 +01:00
ASSERT_EQUALS ( " [test.cpp:3] -> [test.cpp:2] -> [test.cpp:3]: (error) Returning pointer to local variable 'q' that will be invalid when returning. \n " , errout . str ( ) ) ;
2015-11-15 14:48:13 +01:00
check ( " char *foo() \n "
" { \n "
" static char q[] = \" AAAAAAAAAAAA \" ; \n "
" return &q[1]; \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2019-02-22 21:10:05 +01:00
check ( " char *foo() \n "
" { \n "
" char q[] = \" AAAAAAAAAAAA \" ; \n "
" char *p; \n "
" p = &q[1]; \n "
" return p; \n "
" } \n " ) ;
ASSERT_EQUALS ( " [test.cpp:5] -> [test.cpp:3] -> [test.cpp:6]: (error) Returning pointer to local variable 'q' that will be invalid when returning. \n " , errout . str ( ) ) ;
2015-11-15 14:48:13 +01:00
}
void returnLocalVariable4 ( ) { // x+y
check ( " char *foo() { \n "
" char x[10] = {0}; \n "
" return x+5; \n "
" } " ) ;
2018-11-21 08:43:57 +01:00
ASSERT_EQUALS (
2018-12-15 17:58:45 +01:00
" [test.cpp:3] -> [test.cpp:2] -> [test.cpp:3]: (error) Returning pointer to local variable 'x' that will be invalid when returning. \n " ,
2018-11-21 08:43:57 +01:00
errout . str ( ) ) ;
2015-11-15 19:34:36 +01:00
check ( " char *foo(int y) { \n "
" char x[10] = {0}; \n "
" return (x+8)-y; \n "
" } " ) ;
2018-11-21 08:43:57 +01:00
ASSERT_EQUALS (
2018-12-15 17:58:45 +01:00
" [test.cpp:3] -> [test.cpp:2] -> [test.cpp:3]: (error) Returning pointer to local variable 'x' that will be invalid when returning. \n " ,
2018-11-21 08:43:57 +01:00
errout . str ( ) ) ;
2015-11-15 14:48:13 +01:00
}
void returnLocalVariable5 ( ) { // cast
check ( " char *foo() { \n "
" int x[10] = {0}; \n "
" return (char *)x; \n "
" } " ) ;
2018-11-21 08:43:57 +01:00
ASSERT_EQUALS (
2018-12-15 17:58:45 +01:00
" [test.cpp:3] -> [test.cpp:2] -> [test.cpp:3]: (error) Returning pointer to local variable 'x' that will be invalid when returning. \n " ,
2018-11-21 08:43:57 +01:00
errout . str ( ) ) ;
2015-11-15 14:48:13 +01:00
}
2018-01-27 14:48:45 +01:00
void returnLocalVariable6 ( ) { // valueflow
check ( " int *foo() { \n "
" int x = 123; \n "
" int p = &x; \n "
" return p; \n "
" } " ) ;
2018-11-12 10:08:17 +01:00
ASSERT_EQUALS ( " [test.cpp:3] -> [test.cpp:2] -> [test.cpp:4]: (error) Returning object that points to local variable 'x' that will be invalid when returning. \n " , errout . str ( ) ) ;
2018-01-27 14:48:45 +01:00
}
2015-11-15 14:48:13 +01:00
2014-11-20 14:20:09 +01:00
void returnReference1 ( ) {
2019-01-23 07:29:16 +01:00
check ( " int &foo() \n "
" { \n "
" int s = 0; \n "
" int& x = s; \n "
" return x; \n "
" } \n " ) ;
ASSERT_EQUALS ( " [test.cpp:4] -> [test.cpp:5]: (error) Reference to local variable returned. \n " , errout . str ( ) ) ;
2010-01-23 20:39:12 +01:00
check ( " std::string &foo() \n "
" { \n "
" std::string s; \n "
" return s; \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2019-01-23 07:29:16 +01:00
ASSERT_EQUALS ( " [test.cpp:4]: (error) Reference to local variable returned. \n " , errout . str ( ) ) ;
2010-01-23 20:39:12 +01:00
check ( " std::vector<int> &foo() \n "
" { \n "
" std::vector<int> v; \n "
" return v; \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2019-01-23 07:29:16 +01:00
ASSERT_EQUALS ( " [test.cpp:4]: (error) Reference to local variable returned. \n " , errout . str ( ) ) ;
2010-01-23 20:39:12 +01:00
check ( " std::vector<int> &foo() \n "
" { \n "
" static std::vector<int> v; \n "
" return v; \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2010-01-23 20:39:12 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-01-26 22:11:34 +01:00
check ( " std::string hello() \n "
" { \n "
" return \" hello \" ; \n "
" } \n "
" \n "
" std::string &f() \n "
" { \n "
" return hello(); \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2012-07-07 20:31:18 +02:00
ASSERT_EQUALS ( " [test.cpp:8]: (error) Reference to temporary returned. \n " , errout . str ( ) ) ;
2012-08-22 13:08:32 +02:00
2012-10-14 17:30:37 +02:00
// make sure scope is used in function lookup
check ( " class Fred { \n "
" std::string hello() { \n "
" return std::string(); \n "
" } \n "
" }; \n "
" std::string &f() { \n "
" return hello(); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2012-08-22 13:08:32 +02:00
check ( " std::string hello() { \n "
" return std::string(); \n "
" } \n "
" \n "
" std::string &f() { \n "
" return hello(); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:6]: (error) Reference to temporary returned. \n " , errout . str ( ) ) ;
2012-09-10 15:20:38 +02:00
check ( " std::string hello() { \n "
" return \" foo \" ; \n "
" } \n "
" \n "
" std::string &f() { \n "
" return hello().substr(1); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2012-08-22 13:08:32 +02:00
check ( " class Foo; \n "
" Foo hello() { \n "
" return Foo(); \n "
" } \n "
" \n "
" Foo& f() { \n "
" return hello(); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:7]: (error) Reference to temporary returned. \n " , errout . str ( ) ) ;
2012-10-14 17:30:37 +02:00
// make sure function overloads are handled properly
check ( " class Foo; \n "
" Foo & hello(bool) { \n "
" static Foo foo; \n "
" return foo; \n "
" } \n "
" Foo hello() { \n "
" return Foo(); \n "
" } \n "
" \n "
" Foo& f() { \n "
" return hello(true); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2012-08-22 13:08:32 +02:00
check ( " Foo hello() { \n "
" return Foo(); \n "
" } \n "
" \n "
" Foo& f() { \n " // Unknown type - might be a reference
" return hello(); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-01-23 20:39:12 +01:00
}
2010-01-26 22:11:34 +01:00
2014-11-20 14:20:09 +01:00
void returnReference2 ( ) {
2011-02-08 01:26:34 +01:00
check ( " class Fred { \n "
" std::string &foo(); \n "
" } \n "
" std::string &Fred::foo() \n "
" { \n "
" std::string s; \n "
" return s; \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2019-01-23 07:29:16 +01:00
ASSERT_EQUALS ( " [test.cpp:7]: (error) Reference to local variable returned. \n " , errout . str ( ) ) ;
2011-02-08 01:26:34 +01:00
check ( " class Fred { \n "
" std::vector<int> &foo(); \n "
" }; \n "
" std::vector<int> &Fred::foo() \n "
" { \n "
" std::vector<int> v; \n "
" return v; \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2019-01-23 07:29:16 +01:00
ASSERT_EQUALS ( " [test.cpp:7]: (error) Reference to local variable returned. \n " , errout . str ( ) ) ;
2011-02-08 01:26:34 +01:00
check ( " class Fred { \n "
" std::vector<int> &foo(); \n "
" }; \n "
" std::vector<int> &Fred::foo() \n "
" { \n "
" static std::vector<int> v; \n "
" return v; \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2011-02-08 01:26:34 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " class Fred { \n "
" std::string &f(); \n "
" }; \n "
" std::string hello() \n "
" { \n "
" return \" hello \" ; \n "
" } \n "
" std::string &Fred::f() \n "
" { \n "
" return hello(); \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2012-07-07 20:31:18 +02:00
ASSERT_EQUALS ( " [test.cpp:10]: (error) Reference to temporary returned. \n " , errout . str ( ) ) ;
2011-02-08 01:26:34 +01:00
check ( " class Fred { \n "
" std::string hello(); \n "
" std::string &f(); \n "
" }; \n "
" std::string Fred::hello() \n "
" { \n "
" return \" hello \" ; \n "
" } \n "
" std::string &Fred::f() \n "
" { \n "
" return hello(); \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2012-07-07 20:31:18 +02:00
ASSERT_EQUALS ( " [test.cpp:11]: (error) Reference to temporary returned. \n " , errout . str ( ) ) ;
2012-08-22 13:08:32 +02:00
check ( " class Bar; \n "
" Bar foo() { \n "
" return something; \n "
" } \n "
" Bar& bar() { \n "
" return foo(); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:6]: (error) Reference to temporary returned. \n " , errout . str ( ) ) ;
check ( " std::map<int, string> foo() { \n "
" return something; \n "
" } \n "
" std::map<int, string>& bar() { \n "
" return foo(); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:5]: (error) Reference to temporary returned. \n " , errout . str ( ) ) ;
check ( " Bar foo() { \n "
" return something; \n "
" } \n "
" Bar& bar() { \n " // Unknown type - might be a typedef to a reference type
" return foo(); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2012-08-22 19:17:23 +02:00
// Don't crash with function in unknown scope (#4076)
check ( " X& a::Bar() {} "
" X& foo() { "
" return Bar(); "
" } " ) ;
2011-02-08 01:26:34 +01:00
}
2014-11-20 14:20:09 +01:00
void returnReference3 ( ) {
2011-02-12 15:39:26 +01:00
check ( " double & f(double & rd) { \n "
" double ret = getValue(); \n "
" rd = ret; \n "
" return rd; \n "
2013-04-13 18:38:15 +02:00
" } " , false , false ) ;
2011-02-12 15:39:26 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2011-12-26 07:44:16 +01:00
// Returning reference to global variable
2014-11-20 14:20:09 +01:00
void returnReference4 ( ) {
2011-12-26 07:44:16 +01:00
check ( " double a; \n "
" double & f() { \n "
2013-04-13 18:38:15 +02:00
" return a; \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2011-12-26 07:44:16 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void returnReference5 ( ) {
2012-01-08 15:32:22 +01:00
check ( " struct A { \n "
" int i; \n "
" }; \n "
" struct B { \n "
" A a; \n "
" }; \n "
" struct C { \n "
" B *b; \n "
" const A& a() const { \n "
" const B *pb = b; \n "
" const A &ra = pb->a; \n "
" return ra; \n "
" } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void returnReference6 ( ) {
2012-03-28 18:21:06 +02:00
check ( " Fred & create() { \n "
" Fred &fred(*new Fred); \n "
" return fred; \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void returnReference7 ( ) { // 3791 - false positive for overloaded function
2012-07-18 07:22:29 +02:00
check ( " std::string a(); \n "
" std::string &a(int); \n "
" std::string &b() { \n "
" return a(12); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2012-10-14 17:30:37 +02:00
check ( " std::string &a(int); \n "
" std::string a(); \n "
" std::string &b() { \n "
" return a(12); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2012-07-18 07:22:29 +02:00
}
2019-01-26 11:03:57 +01:00
void returnReferenceFunction ( ) {
check ( " int& f(int& a) { \n "
" return a; \n "
" } \n "
" int& hello() { \n "
" int x = 0; \n "
" return f(x); \n "
" } \n " ) ;
ASSERT_EQUALS (
" [test.cpp:1] -> [test.cpp:2] -> [test.cpp:6] -> [test.cpp:6]: (error) Reference to local variable returned. \n " ,
errout . str ( ) ) ;
2019-02-22 06:38:56 +01:00
check ( " int& f(int& a) { \n "
" return a; \n "
" } \n "
" int* hello() { \n "
" int x = 0; \n "
" return &f(x); \n "
" } \n " ) ;
ASSERT_EQUALS (
" [test.cpp:1] -> [test.cpp:2] -> [test.cpp:6] -> [test.cpp:6] -> [test.cpp:5] -> [test.cpp:6]: (error) Returning pointer to local variable 'x' that will be invalid when returning. \n " ,
errout . str ( ) ) ;
2019-01-26 11:03:57 +01:00
check ( " int f(int& a) { \n "
" return a; \n "
" } \n "
" int& hello() { \n "
" int x = 0; \n "
" return f(x); \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " int& f(int a) { \n "
" return a; \n "
" } \n "
" int& hello() { \n "
" int x = 0; \n "
" return f(x); \n "
" } \n " ) ;
ASSERT_EQUALS ( " [test.cpp:2]: (error) Reference to local variable returned. \n " , errout . str ( ) ) ;
check ( " int f(int a) { \n "
" return a; \n "
" } \n "
" int& hello() { \n "
" int x = 0; \n "
" return f(x); \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " template<class T> \n "
" int& f(int& x, T y) { \n "
" x += y; \n "
" return x; \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2019-02-22 06:38:56 +01:00
void returnReferenceContainer ( ) {
check ( " auto& f() { \n "
" std::vector<int> x; \n "
" return x[0]; \n "
" } \n " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (error) Reference to local variable returned. \n " , errout . str ( ) ) ;
check ( " struct A { int foo; }; \n "
" int& f(std::vector<A> v) { \n "
" auto it = v.begin(); \n "
" return it->foo; \n "
" } \n " ) ;
ASSERT_EQUALS ( " [test.cpp:3] -> [test.cpp:4]: (error) Reference to local variable returned. \n " , errout . str ( ) ) ;
check ( " struct A { int foo; }; \n "
" int& f(std::vector<A>& v) { \n "
" auto it = v.begin(); \n "
" return it->foo; \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void returnReferenceLiteral ( ) {
2014-05-22 11:39:11 +02:00
check ( " const std::string &a() { \n "
" return \" foo \" ; \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:2]: (error) Reference to temporary returned. \n " , errout . str ( ) ) ;
check ( " const std::string a() { \n "
" return \" foo \" ; \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void returnReferenceCalculation ( ) {
2014-05-22 11:39:11 +02:00
check ( " const std::string &a(const std::string& str) { \n "
" return \" foo \" + str; \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:2]: (error) Reference to temporary returned. \n " , errout . str ( ) ) ;
2015-01-31 10:12:20 +01:00
check ( " int& operator<<(int out, int path) { \n "
" return out << path; \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:2]: (error) Reference to temporary returned. \n " , errout . str ( ) ) ;
2014-05-24 12:32:44 +02:00
check ( " std::ostream& operator<<(std::ostream& out, const std::string& path) { \n "
" return out << path; \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2015-01-31 10:12:20 +01:00
check ( " std::ostream& operator<<(std::ostream* out, const std::string& path) { \n "
" return *out << path; \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2014-05-24 12:32:44 +02:00
check ( " Unknown1& operator<<(Unknown1 out, Unknown2 path) { \n "
" return out << path; \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2014-05-22 11:39:11 +02:00
check ( " int& a(int b) { \n "
" return 2*(b+1); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:2]: (error) Reference to temporary returned. \n " , errout . str ( ) ) ;
check ( " const std::string &a(const std::string& str) { \n "
" return str; \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " const std::string &a(int bar) { \n "
" return foo(bar + 1); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " const std::string a(const std::string& str) { \n "
" return \" foo \" + str; \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2016-12-22 11:49:59 +01:00
check ( " int& incValue(int& value) { \n "
" return ++value; \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2014-05-22 11:39:11 +02:00
}
2015-08-14 13:03:07 +02:00
void returnReferenceLambda ( ) {
// #6787
check ( " const Item& foo(const Container& items) const { \n "
" return bar(items.begin(), items.end(), \n "
" [](const Item& lhs, const Item& rhs) { \n "
" return false; \n "
" }); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2016-05-20 23:46:56 +02:00
// #5844
check ( " map<string,string> const &getVariableTable() { \n "
" static map<string,string> const s_var = []{ \n "
" map<string,string> var; \n "
" return var; \n "
" }(); \n "
" return s_var; \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2017-02-26 13:41:49 +01:00
// #7583
check ( " Command& foo() { \n "
" return f([]() -> int { return 1; }); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2015-08-14 13:03:07 +02:00
}
2011-04-18 06:56:39 +02:00
2015-08-26 13:31:51 +02:00
void returnReferenceInnerScope ( ) {
// #6951
check ( " const Callback& make() { \n "
" struct _Wrapper { \n "
" static ulong call(void* o, const void* f, const void*[]) { \n "
" return 1; \n "
" } \n "
" }; \n "
" return _make(_Wrapper::call, pmf); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2019-01-31 10:34:41 +01:00
void returnReferenceRecursive ( ) {
check ( " int& f() { return f(); } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " int& g(int& i) { return i; } \n "
" int& f() { return g(f()); } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2019-01-23 07:29:16 +01:00
void danglingReference ( ) {
2019-01-26 11:03:57 +01:00
check ( " int f( int k ) \n "
2019-01-23 07:29:16 +01:00
" { \n "
" static int &r = k; \n "
" return r; \n "
" } \n " ) ;
ASSERT_EQUALS ( " [test.cpp:3] -> [test.cpp:3]: (error) Non-local reference variable 'r' to local variable 'k' \n " ,
errout . str ( ) ) ;
check ( " int &f( int & k ) \n "
" { \n "
" static int &r = k; \n "
" return r; \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void testglobalnamespace ( ) {
2011-04-18 06:56:39 +02:00
check ( " class SharedPtrHolder \n "
" { \n "
" ::std::tr1::shared_ptr<int> pNum; \n "
" public: \n "
" void SetNum(const ::std::tr1::shared_ptr<int> & apNum) \n "
" { \n "
" pNum = apNum; \n "
" } \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void returnParameterAddress ( ) {
2011-09-01 03:36:31 +02:00
check ( " int* foo(int y) \n "
" { \n "
" return &y; \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2011-09-01 03:36:31 +02:00
2018-11-12 10:08:17 +01:00
ASSERT_EQUALS ( " [test.cpp:3] -> [test.cpp:1] -> [test.cpp:3]: (error) Returning pointer to local variable 'y' that will be invalid when returning. \n " , errout . str ( ) ) ;
2011-09-02 00:30:49 +02:00
check ( " int ** foo(int * y) \n "
" { \n "
" return &y; \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2011-09-02 00:30:49 +02:00
2018-11-12 10:08:17 +01:00
ASSERT_EQUALS ( " [test.cpp:3] -> [test.cpp:1] -> [test.cpp:3]: (error) Returning pointer to local variable 'y' that will be invalid when returning. \n " , errout . str ( ) ) ;
2011-09-02 16:39:04 +02:00
check ( " const int * foo(const int & y) \n "
" { \n "
" return &y; \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2011-09-02 16:39:04 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2018-11-17 09:41:59 +01:00
check ( " int * foo(int * y) \n "
" { \n "
" return y; \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2019-02-18 09:35:07 +01:00
check ( " struct s { void *p; }; \n "
" extern struct s* f(void); \n "
" void g(void **q) \n "
" { \n "
" struct s *r = f(); \n "
" *q = &r->p; \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2011-09-01 03:36:31 +02:00
}
2014-11-20 14:20:09 +01:00
void testconstructor ( ) { // Ticket #5478 - crash while checking a constructor
2014-03-01 16:30:59 +01:00
check ( " class const_tree_iterator { \n "
" const_tree_iterator(bool (*_incream)(node_type*&)) {} \n "
" const_tree_iterator& parent() { \n "
" return const_tree_iterator(foo); \n "
" } \n "
" }; " ) ;
}
2014-11-20 14:20:09 +01:00
void variableIsUsedInScope ( ) {
2014-03-22 11:14:11 +01:00
check ( " void removed_cb (GList *uids) { \n "
" for (; uids; uids = uids->next) { \n "
" } \n "
" } \n "
" void opened_cb () { \n "
" g_signal_connect (G_CALLBACK (removed_cb)); \n "
" } " ) ;
}
2018-11-10 16:40:40 +01:00
void danglingLifetimeLambda ( ) {
check ( " auto f() { \n "
" int a = 1; \n "
" auto l = [&](){ return a; }; \n "
" return l; \n "
" } \n " ) ;
ASSERT_EQUALS ( " [test.cpp:3] -> [test.cpp:2] -> [test.cpp:4]: (error) Returning lambda that captures local variable 'a' that will be invalid when returning. \n " , errout . str ( ) ) ;
check ( " auto f() { \n "
" int a = 1; \n "
" return [&](){ return a; }; \n "
" } \n " ) ;
ASSERT_EQUALS ( " [test.cpp:3] -> [test.cpp:2] -> [test.cpp:3]: (error) Returning lambda that captures local variable 'a' that will be invalid when returning. \n " , errout . str ( ) ) ;
check ( " auto f(int a) { \n "
" return [&](){ return a; }; \n "
" } \n " ) ;
ASSERT_EQUALS ( " [test.cpp:2] -> [test.cpp:1] -> [test.cpp:2]: (error) Returning lambda that captures local variable 'a' that will be invalid when returning. \n " , errout . str ( ) ) ;
check ( " auto f(int a) { \n "
" auto p = &a; \n "
" return [=](){ return p; }; \n "
" } \n " ) ;
ASSERT_EQUALS ( " [test.cpp:2] -> [test.cpp:3] -> [test.cpp:1] -> [test.cpp:3]: (error) Returning lambda that captures local variable 'a' that will be invalid when returning. \n " , errout . str ( ) ) ;
check ( " auto g(int& a) { \n "
" int p = a; \n "
" return [&](){ return p; }; \n "
" } \n " ) ;
ASSERT_EQUALS ( " [test.cpp:3] -> [test.cpp:2] -> [test.cpp:3]: (error) Returning lambda that captures local variable 'p' that will be invalid when returning. \n " , errout . str ( ) ) ;
check ( " auto f() { \n "
" return [=](){ \n "
" int a = 1; \n "
" return [&](){ return a; }; \n "
" }; \n "
" } \n " ) ;
ASSERT_EQUALS ( " [test.cpp:4] -> [test.cpp:3] -> [test.cpp:4]: (error) Returning lambda that captures local variable 'a' that will be invalid when returning. \n " , errout . str ( ) ) ;
// TODO: Variable is not set correctly for this case
check ( " auto f(int b) { \n "
" return [=](int a){ \n "
" a += b; \n "
" return [&](){ return a; }; \n "
" }; \n "
" } \n " ) ;
TODO_ASSERT_EQUALS ( " [test.cpp:3] -> [test.cpp:4]: (error) Returning lambda that captures local variable 'a' that will be invalid when returning. \n " , " " , errout . str ( ) ) ;
check ( " auto g(int& a) { \n "
" return [&](){ return a; }; \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " auto g(int a) { \n "
" auto p = a; \n "
" return [=](){ return p; }; \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " auto g(int& a) { \n "
" auto p = a; \n "
" return [=](){ return p; }; \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " auto g(int& a) { \n "
" int& p = a; \n "
" return [&](){ return p; }; \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " template<class F> \n "
" void g(F); \n "
" auto f() { \n "
" int x; \n "
" return g([&]() { return x; }); \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
void danglingLifetimeContainer ( ) {
check ( " auto f(const std::vector<int>& x) { \n "
" auto it = x.begin(); \n "
" return it; \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " auto f() { \n "
" std::vector<int> x; \n "
" auto it = x.begin(); \n "
" return it; \n "
" } \n " ) ;
ASSERT_EQUALS ( " [test.cpp:3] -> [test.cpp:2] -> [test.cpp:4]: (error) Returning iterator to local container 'x' that will be invalid when returning. \n " , errout . str ( ) ) ;
check ( " auto f() { \n "
" std::vector<int> x; \n "
" auto p = x.data(); \n "
" return p; \n "
" } \n " ) ;
ASSERT_EQUALS ( " [test.cpp:3] -> [test.cpp:2] -> [test.cpp:4]: (error) Returning object that points to local variable 'x' that will be invalid when returning. \n " , errout . str ( ) ) ;
2019-02-22 06:38:56 +01:00
check ( " auto f() { \n "
" std::vector<int> x; \n "
" auto p = &x[0]; \n "
" return p; \n "
" } \n " ) ;
ASSERT_EQUALS (
" [test.cpp:3] -> [test.cpp:2] -> [test.cpp:4]: (error) Returning pointer to local variable 'x' that will be invalid when returning. \n " ,
errout . str ( ) ) ;
check ( " struct A { int foo; }; \n "
" int* f(std::vector<A> v) { \n "
" auto it = v.begin(); \n "
" return &it->foo; \n "
" } \n " ) ;
ASSERT_EQUALS (
" [test.cpp:3] -> [test.cpp:4] -> [test.cpp:2] -> [test.cpp:4]: (error) Returning object that points to local variable 'v' that will be invalid when returning. \n " ,
errout . str ( ) ) ;
2018-11-10 16:40:40 +01:00
check ( " auto f(std::vector<int> x) { \n "
" auto it = x.begin(); \n "
" return it; \n "
" } \n " ) ;
ASSERT_EQUALS ( " [test.cpp:2] -> [test.cpp:1] -> [test.cpp:3]: (error) Returning iterator to local container 'x' that will be invalid when returning. \n " , errout . str ( ) ) ;
2018-11-16 06:12:28 +01:00
check ( " auto f() { \n "
" std::vector<int> x; \n "
" auto it = x.begin(); \n "
" return std::next(it); \n "
" } \n " ) ;
ASSERT_EQUALS (
" [test.cpp:3] -> [test.cpp:4] -> [test.cpp:2] -> [test.cpp:4]: (error) Returning object that points to local variable 'x' that will be invalid when returning. \n " ,
errout . str ( ) ) ;
check ( " auto f() { \n "
" std::vector<int> x; \n "
" auto it = x.begin(); \n "
" return it + 1; \n "
" } \n " ) ;
ASSERT_EQUALS (
" [test.cpp:3] -> [test.cpp:2] -> [test.cpp:4]: (error) Returning iterator to local container 'x' that will be invalid when returning. \n " ,
errout . str ( ) ) ;
check ( " auto f() { \n "
" std::vector<int> x; \n "
" auto it = x.begin(); \n "
" return std::next(it + 1); \n "
" } \n " ) ;
ASSERT_EQUALS (
" [test.cpp:3] -> [test.cpp:4] -> [test.cpp:2] -> [test.cpp:4]: (error) Returning object that points to local variable 'x' that will be invalid when returning. \n " ,
errout . str ( ) ) ;
2018-11-21 08:43:57 +01:00
check ( " std::vector<int*> f() { \n "
" int i = 0; \n "
" std::vector<int*> v; \n "
" v.push_back(&i); \n "
" return v; \n "
" } \n " ) ;
ASSERT_EQUALS (
" [test.cpp:4] -> [test.cpp:4] -> [test.cpp:2] -> [test.cpp:5]: (error) Returning object that points to local variable 'i' that will be invalid when returning. \n " ,
errout . str ( ) ) ;
check ( " std::vector<int*> f() { \n "
" std::vector<int*> r; \n "
" int i = 0; \n "
" std::vector<int*> v; \n "
" v.push_back(&i); \n "
" r.assign(v.begin(), v.end()); \n "
" return r; \n "
" } \n " ) ;
ASSERT_EQUALS (
" [test.cpp:5] -> [test.cpp:5] -> [test.cpp:5] -> [test.cpp:3] -> [test.cpp:7]: (error) Returning object that points to local variable 'i' that will be invalid when returning. \n " ,
errout . str ( ) ) ;
check ( " struct A { \n "
" std::vector<int*> v; \n "
" void f() { \n "
" int i; \n "
" v.push_back(&i); \n "
" } \n "
" }; \n " ) ;
ASSERT_EQUALS (
" [test.cpp:5] -> [test.cpp:5] -> [test.cpp:4] -> [test.cpp:5]: (error) Non-local variable 'v' will use object that points to local variable 'i'. \n " ,
errout . str ( ) ) ;
check ( " struct A { \n "
" std::vector<int*> v; \n "
" void f() { \n "
" int i; \n "
" int * p = &i; \n "
" v.push_back(p); \n "
" } \n "
" }; \n " ) ;
ASSERT_EQUALS (
" [test.cpp:5] -> [test.cpp:6] -> [test.cpp:4] -> [test.cpp:6]: (error) Non-local variable 'v' will use object that points to local variable 'i'. \n " ,
errout . str ( ) ) ;
2018-12-02 14:31:31 +01:00
check ( " struct A { \n "
" std::vector<int*> m; \n "
" void f() { \n "
" int x; \n "
" std::vector<int*> v; \n "
" v.push_back(&x); \n "
" m.insert(m.end(), v.begin(), v.end()); \n "
" } \n "
" }; \n " ) ;
ASSERT_EQUALS (
" [test.cpp:6] -> [test.cpp:6] -> [test.cpp:6] -> [test.cpp:4] -> [test.cpp:7]: (error) Non-local variable 'm' will use object that points to local variable 'x'. \n " ,
errout . str ( ) ) ;
2019-02-22 06:37:02 +01:00
check ( " std::vector<int>::iterator f(std::vector<int> v) { \n "
" for(auto it = v.begin();it != v.end();it++) { \n "
" return it; \n "
" } \n "
" return {}; \n "
" } \n " ) ;
ASSERT_EQUALS (
" [test.cpp:2] -> [test.cpp:1] -> [test.cpp:3]: (error) Returning iterator to local container 'v' that will be invalid when returning. \n " ,
errout . str ( ) ) ;
2018-11-21 08:43:57 +01:00
check ( " struct A { \n "
" std::vector<std::string> v; \n "
" void f() { \n "
" char s[3]; \n "
" v.push_back(s); \n "
" } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " std::vector<std::string> f() { \n "
" const char * s = \" hello \" ; \n "
" std::vector<std::string> v; \n "
" v.push_back(s); \n "
" return v; \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2018-11-10 16:40:40 +01:00
check ( " auto f() { \n "
" static std::vector<int> x; \n "
" return x.begin(); \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " std::string g() { \n "
" std::vector<char> v; \n "
" return v.data(); \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2018-11-17 09:41:59 +01:00
check ( " std::vector<int>::iterator f(std::vector<int>* v) { \n "
" return v->begin(); \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " std::vector<int>::iterator f(std::vector<int>* v) { \n "
" std::vector<int>* v = new std::vector<int>(); \n "
" return v->begin(); \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " int f(std::vector<int> v) { \n "
" return *v.begin(); \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " int f(std::vector<int> v) { \n "
" return v.end() - v.begin(); \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2018-11-10 16:40:40 +01:00
check ( " auto g() { \n "
" std::vector<char> v; \n "
" return {v, [v]() { return v.data(); }}; \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " template<class F> \n "
" void g(F); \n "
" auto f() { \n "
" std::vector<char> v; \n "
" return g([&]() { return v.data(); }); \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2018-12-02 14:31:31 +01:00
check ( " std::vector<int> g(); \n "
" struct A { \n "
" std::vector<int> m; \n "
" void f() { \n "
" std::vector<int> v = g(); \n "
" m.insert(m.end(), v.begin(), v.end()); \n "
" } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " class A { \n "
" int f( P p ) { \n "
" std::vector< S > maps; \n "
" m2.insert( m1.begin(), m1.end() ); \n "
" } \n "
" struct B {}; \n "
" std::map< S, B > m1; \n "
" std::map< S, B > m2; \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2018-11-10 16:40:40 +01:00
}
void danglingLifetime ( ) {
check ( " auto f() { \n "
" std::vector<int> a; \n "
" auto it = a.begin(); \n "
" return [=](){ return it; }; \n "
" } \n " ) ;
ASSERT_EQUALS ( " [test.cpp:3] -> [test.cpp:4] -> [test.cpp:2] -> [test.cpp:4]: (error) Returning lambda that captures local variable 'a' that will be invalid when returning. \n " , errout . str ( ) ) ;
check ( " auto f(std::vector<int> a) { \n "
" auto it = a.begin(); \n "
" return [=](){ return it; }; \n "
" } \n " ) ;
ASSERT_EQUALS ( " [test.cpp:2] -> [test.cpp:3] -> [test.cpp:1] -> [test.cpp:3]: (error) Returning lambda that captures local variable 'a' that will be invalid when returning. \n " , errout . str ( ) ) ;
2018-12-15 17:58:45 +01:00
check ( " struct e {}; \n "
" e * j() { \n "
" e c[20]; \n "
" return c; \n "
" } \n " ) ;
ASSERT_EQUALS (
" [test.cpp:4] -> [test.cpp:3] -> [test.cpp:4]: (error) Returning pointer to local variable 'c' that will be invalid when returning. \n " ,
errout . str ( ) ) ;
2018-11-10 16:40:40 +01:00
check ( " auto f(std::vector<int>& a) { \n "
" auto it = a.begin(); \n "
" return [=](){ return it; }; \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2018-11-17 09:41:59 +01:00
check ( " int * f(int a[]) { \n "
" return a; \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2018-12-01 19:07:46 +01:00
check ( " void f() { \n "
" struct b { \n "
" uint32_t f[6]; \n "
" } d; \n "
" uint32_t *a = d.f; \n "
2018-12-01 19:14:43 +01:00
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2019-01-06 17:15:57 +01:00
// Don't decay std::array
2018-12-01 19:14:43 +01:00
check ( " std::array<char, 1> f() { \n "
" std::array<char, 1> x; \n "
" return x; \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2019-01-06 17:15:57 +01:00
// Make sure we don't hang
2018-12-01 19:14:43 +01:00
check ( " struct A; \n "
" void f() { \n "
" using T = A[3]; \n "
" A &&a = T{1, 2, 3}[1]; \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2019-01-06 17:15:57 +01:00
// Make sure we don't hang
2018-12-01 19:14:43 +01:00
check ( " struct A; \n "
" void f() { \n "
" using T = A[3]; \n "
" A &&a = T{1, 2, 3}[1](); \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2019-01-06 17:15:57 +01:00
// Make sure we don't hang
2018-12-01 19:14:43 +01:00
check ( " struct A; \n "
" void f() { \n "
" using T = A[3]; \n "
" A &&a = T{1, 2, 3}[1]; \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2019-01-06 17:15:57 +01:00
// Make sure we don't hang
2018-12-01 19:14:43 +01:00
check ( " struct A; \n "
" void f() { \n "
" using T = A[3]; \n "
" A &&a = T{1, 2, 3}[1](); \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// Crash #8872
check ( " struct a { \n "
" void operator()(b c) override { \n "
" d(c, [&] { c->e }); \n "
" } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " struct a { \n "
" void operator()(b c) override { \n "
" d(c, [=] { c->e }); \n "
" } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2018-12-15 17:58:45 +01:00
check ( " struct a { \n "
" a(char* b) {} \n "
" }; \n "
" a f() { \n "
" char c[20]; \n "
" return c; \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " struct a { \n "
" a(char* b) {} \n "
" }; \n "
" a g() { \n "
" char c[20]; \n "
" a d = c; \n "
" return d; \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2019-01-11 09:51:02 +01:00
check ( " void f() { \n "
" struct a { \n "
" std::vector<int> v; \n "
" auto g() { return v.end(); } \n "
" }; \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2019-01-26 11:03:57 +01:00
check ( " int * f(std::vector<int>& v) { \n "
" for(int & x : v) \n "
" return &x; \n "
" return nullptr; \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2018-11-10 16:40:40 +01:00
}
2018-11-16 06:12:28 +01:00
void danglingLifetimeFunction ( ) {
check ( " auto f() { \n "
" int a; \n "
" return std::ref(a); \n "
" } \n " ) ;
ASSERT_EQUALS (
" [test.cpp:3] -> [test.cpp:2] -> [test.cpp:3]: (error) Returning object that points to local variable 'a' that will be invalid when returning. \n " ,
errout . str ( ) ) ;
check ( " auto f() { \n "
" int a; \n "
" return std::make_tuple(std::ref(a)); \n "
" } \n " ) ;
ASSERT_EQUALS (
" [test.cpp:3] -> [test.cpp:3] -> [test.cpp:2] -> [test.cpp:3]: (error) Returning object that points to local variable 'a' that will be invalid when returning. \n " ,
errout . str ( ) ) ;
2019-01-29 09:47:52 +01:00
check ( " template<class T> \n "
" auto by_value(T x) { \n "
" return [=] { return x; }; \n "
" } \n "
" auto g() { \n "
" std::vector<int> v; \n "
" return by_value(v.begin()); \n "
" } \n " ) ;
ASSERT_EQUALS (
" [test.cpp:7] -> [test.cpp:7] -> [test.cpp:3] -> [test.cpp:3] -> [test.cpp:6] -> [test.cpp:7]: (error) Returning object that points to local variable 'v' that will be invalid when returning. \n " ,
errout . str ( ) ) ;
check ( " auto by_ref(int& x) { \n "
" return [&] { return x; }; \n "
" } \n "
" auto f() { \n "
" int i = 0; \n "
" return by_ref(i); \n "
" } \n " ) ;
ASSERT_EQUALS (
" [test.cpp:2] -> [test.cpp:1] -> [test.cpp:2] -> [test.cpp:6] -> [test.cpp:5] -> [test.cpp:6]: (error) Returning object that points to local variable 'i' that will be invalid when returning. \n " ,
errout . str ( ) ) ;
2018-11-16 06:12:28 +01:00
check ( " auto f(int x) { \n "
" int a; \n "
" std::tie(a) = x; \n "
" return a; \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2018-11-11 16:43:54 +01:00
void invalidLifetime ( ) {
check ( " void foo(int a) { \n "
" std::function<void()> f; \n "
" if (a > 0) { \n "
" int b = a + 1; \n "
" f = [&]{ return b; }; \n "
" } \n "
" f(); \n "
" } \n " ) ;
ASSERT_EQUALS ( " [test.cpp:5] -> [test.cpp:4] -> [test.cpp:7]: (error) Using lambda that captures local variable 'b' that is out of scope. \n " , errout . str ( ) ) ;
2018-11-12 10:08:17 +01:00
check ( " void f(bool b) { \n "
" int* x; \n "
" if(b) { \n "
" int y[6] = {0,1,2,3,4,5}; \n "
" x = y; \n "
" } \n "
" x[3]; \n "
" } \n " ) ;
2018-11-21 08:43:57 +01:00
ASSERT_EQUALS (
2018-12-15 17:58:45 +01:00
" [test.cpp:5] -> [test.cpp:4] -> [test.cpp:7]: (error) Using pointer to local variable 'y' that is out of scope. \n " ,
2018-11-21 08:43:57 +01:00
errout . str ( ) ) ;
2018-11-12 10:08:17 +01:00
2018-11-11 16:43:54 +01:00
check ( " void foo(int a) { \n "
" std::function<void()> f; \n "
" if (a > 0) { \n "
" int b = a + 1; \n "
" f = [&]{ return b; }; \n "
" f(); \n "
" } \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " struct a { \n "
" b(); \n "
" std::list<int> c; \n "
" }; \n "
" void a::b() { \n "
" c.end() \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " void b(char f[], char c[]) { \n "
" std::string d(c); { \n "
" std::string e; \n "
" b(f, e.c_str()) \n "
" } \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2018-11-12 10:08:17 +01:00
2018-11-14 06:59:25 +01:00
check ( " void f(bool b) { \n "
" std::string s; \n "
" if(b) { \n "
" char buf[3]; \n "
" s = buf; \n "
" } \n "
" std::cout << s; \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2018-11-12 10:08:17 +01:00
check ( " int &a[]; \n "
" void b(){int *c = a}; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2018-11-11 16:43:54 +01:00
}
2009-03-22 12:00:21 +01:00
} ;
REGISTER_TEST ( TestAutoVariables )