2014-09-11 18:10:19 +02:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2016-01-01 14:34:45 +01:00
* Copyright ( C ) 2007 - 2016 Cppcheck team .
2014-09-11 18:10:19 +02: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
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include "preprocessor.h"
# include "tokenize.h"
# include "symboldatabase.h"
# include "checktype.h"
# include "testsuite.h"
# include "testutils.h"
# include <tinyxml2.h>
class TestType : public TestFixture {
public :
2014-11-20 14:20:09 +01:00
TestType ( ) : TestFixture ( " TestType " ) {
2014-09-11 18:10:19 +02:00
}
private :
2014-11-20 14:20:09 +01:00
void run ( ) {
2014-09-11 18:10:19 +02:00
TEST_CASE ( checkTooBigShift ) ;
TEST_CASE ( checkIntegerOverflow ) ;
TEST_CASE ( signConversion ) ;
2015-05-25 10:02:17 +02:00
TEST_CASE ( longCastAssign ) ;
TEST_CASE ( longCastReturn ) ;
2016-11-22 22:37:13 +01:00
TEST_CASE ( checkFloatToIntegerOverflow ) ;
2014-09-11 18:10:19 +02:00
}
2014-11-20 14:20:09 +01:00
void check ( const char code [ ] , Settings * settings = 0 ) {
2014-09-11 18:10:19 +02:00
// Clear the error buffer..
errout . str ( " " ) ;
if ( ! settings ) {
static Settings _settings ;
settings = & _settings ;
}
settings - > addEnabled ( " warning " ) ;
// Tokenize..
Tokenizer tokenizer ( settings , this ) ;
std : : istringstream istr ( code ) ;
tokenizer . tokenize ( istr , " test.cpp " ) ;
// Check..
CheckType checkType ( & tokenizer , settings , this ) ;
checkType . runChecks ( & tokenizer , settings , this ) ;
}
2014-11-20 14:20:09 +01:00
void checkTooBigShift ( ) {
2014-09-11 18:10:19 +02:00
Settings settings ;
settings . platform ( Settings : : Unix32 ) ;
check ( " int foo(int x) { \n "
" return x << 32; \n "
" } " , & settings ) ;
ASSERT_EQUALS ( " [test.cpp:2]: (error) Shifting 32-bit value by 32 bits is undefined behaviour \n " , errout . str ( ) ) ;
check ( " int foo(int x) { \n "
" return x << 2; \n "
" } " , & settings ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2014-09-12 06:45:45 +02:00
check ( " int foo(int x) { \n "
" return (long long)x << 40; \n "
" } " , & settings ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2014-10-23 06:52:19 +02:00
check ( " void foo() { \n "
" QList<int> someList; \n "
" someList << 300; \n "
" } " , & settings ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2015-08-02 00:03:09 +02:00
// Ticket #6793
check ( " template<int I> int foo(int x) { return x << I; } \n "
2016-11-05 09:29:52 +01:00
" const int f = foo<31>(0); \n "
" const int g = foo<100>(0); \n "
2015-08-02 00:03:09 +02:00
" template<int I> int hoo(int x) { return x << 32; } \n "
2016-11-05 09:29:52 +01:00
" const int h = hoo<100>(0); " , & settings ) ;
2015-08-02 00:03:09 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (error) Shifting 32-bit value by 32 bits is undefined behaviour \n "
" [test.cpp:1]: (error) Shifting 32-bit value by 100 bits is undefined behaviour \n " , errout . str ( ) ) ;
2016-01-10 20:44:52 +01:00
// #7266: C++, shift in macro
check ( " void f(int x) { \n "
" UINFO(x << 1234); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2014-09-11 18:10:19 +02:00
}
2014-11-20 14:20:09 +01:00
void checkIntegerOverflow ( ) {
2014-09-11 18:10:19 +02:00
Settings settings ;
settings . platform ( Settings : : Unix32 ) ;
2015-12-31 12:05:23 +01:00
settings . addEnabled ( " warning " ) ;
2014-09-11 18:10:19 +02:00
2016-11-05 09:29:52 +01:00
check ( " void foo() { \n "
" int intmax = 0x7fffffff; \n "
" return intmax + 1; \n "
" } " , & settings ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (error) Signed integer overflow for expression 'intmax+1'. \n " , errout . str ( ) ) ;
2016-11-07 22:29:40 +01:00
check ( " void foo() { \n "
" int intmax = 0x7fffffff; \n "
" return intmax - 1; \n "
" } " , & settings ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2015-12-31 12:05:23 +01:00
check ( " int foo(signed int x) { \n "
2014-09-11 18:10:19 +02:00
" if (x==123456) {} \n "
" return x * x; \n "
" } " , & settings ) ;
2015-12-31 12:05:23 +01:00
ASSERT_EQUALS ( " [test.cpp:3]: (warning) Either the condition 'x==123456' is redundant or there is signed integer overflow for expression 'x*x'. \n " , errout . str ( ) ) ;
2014-09-11 18:10:19 +02:00
2015-12-31 12:05:23 +01:00
check ( " int foo(signed int x) { \n "
2014-09-11 18:10:19 +02:00
" if (x==123456) {} \n "
" return -123456 * x; \n "
" } " , & settings ) ;
2015-12-31 12:05:23 +01:00
ASSERT_EQUALS ( " [test.cpp:3]: (warning) Either the condition 'x==123456' is redundant or there is signed integer overflow for expression '-123456*x'. \n " , errout . str ( ) ) ;
2014-09-11 18:10:19 +02:00
2015-12-31 12:05:23 +01:00
check ( " int foo(signed int x) { \n "
2014-09-11 18:10:19 +02:00
" if (x==123456) {} \n "
" return 123456U * x; \n "
" } " , & settings ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void signConversion ( ) {
2014-09-12 16:18:42 +02:00
check ( " unsigned int f1(signed int x, unsigned int y) { " // x is signed
2014-09-11 18:10:19 +02:00
" return x * y; \n "
" } \n "
" void f2() { f1(-4,4); } " ) ;
ASSERT_EQUALS ( " [test.cpp:1]: (warning) Suspicious code: sign conversion of x in calculation, even though x can have a negative value \n " , errout . str ( ) ) ;
2014-09-12 16:18:42 +02:00
check ( " unsigned int f1(int x) { " // x has no signedness, but it can have the value -1 so assume it's signed
" return x * 5U; \n "
" } \n "
" void f2() { f1(-4); } " ) ;
ASSERT_EQUALS ( " [test.cpp:1]: (warning) Suspicious code: sign conversion of x in calculation, even though x can have a negative value \n " , errout . str ( ) ) ;
2014-09-12 18:58:31 +02:00
2014-09-14 10:29:58 +02:00
check ( " unsigned int f1(int x) { " // #6168: FP for inner calculation
" return 5U * (1234 - x); \n " // <- signed subtraction, x is not sign converted
" } \n "
" void f2() { f1(-4); } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2016-11-27 11:40:42 +01:00
// Don't warn for + and -
2014-09-12 18:58:31 +02:00
check ( " void f1(int x) { "
" a = x + 5U; \n "
" } \n "
" void f2() { f1(-4); } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2016-01-02 22:56:15 +01:00
check ( " size_t foo(size_t x) { \n "
" return -2 * x; \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:2]: (warning) Suspicious code: sign conversion of -2 in calculation because '-2' has a negative value \n " , errout . str ( ) ) ;
2014-09-11 18:10:19 +02:00
}
2015-05-25 10:02:17 +02:00
void longCastAssign ( ) {
Settings settings ;
settings . addEnabled ( " style " ) ;
2015-05-25 23:15:59 +02:00
settings . platform ( Settings : : Unix64 ) ;
2015-05-25 10:02:17 +02:00
check ( " long f(int x, int y) { \n "
" const long ret = x * y; \n "
" return ret; \n "
" } \n " , & settings ) ;
2015-06-01 21:22:47 +02:00
ASSERT_EQUALS ( " [test.cpp:2]: (style) int result is assigned to long variable. If the variable is long to avoid loss of information, then you have loss of information. \n " , errout . str ( ) ) ;
2015-05-25 10:02:17 +02:00
2015-05-25 18:19:40 +02:00
// typedef
check ( " long f(int x, int y) { \n "
" const size_t ret = x * y; \n "
" return ret; \n "
" } \n " , & settings ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2015-05-25 10:02:17 +02:00
// astIsIntResult
check ( " long f(int x, int y) { \n "
" const long ret = (long)x * y; \n "
" return ret; \n "
" } \n " , & settings ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
void longCastReturn ( ) {
Settings settings ;
settings . addEnabled ( " style " ) ;
check ( " long f(int x, int y) { \n "
" return x * y; \n "
" } \n " , & settings ) ;
2015-06-01 21:22:47 +02:00
ASSERT_EQUALS ( " [test.cpp:2]: (style) int result is returned as long value. If the return value is long to avoid loss of information, then you have loss of information. \n " , errout . str ( ) ) ;
2015-05-25 18:19:40 +02:00
// typedef
check ( " size_t f(int x, int y) { \n "
" return x * y; \n "
" } \n " , & settings ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2015-05-25 10:02:17 +02:00
}
2016-11-22 22:37:13 +01:00
// This function ensure that test works with different compilers. Floats can
// be stringified differently.
2016-12-05 14:48:16 +01:00
std : : string removeFloat ( const std : : string & msg ) {
std : : string : : size_type pos1 = msg . find ( " float ( " ) ;
std : : string : : size_type pos2 = msg . find ( " ) conversion " ) ;
2016-11-22 22:37:13 +01:00
if ( pos1 = = std : : string : : npos | | pos2 = = std : : string : : npos | | pos1 > pos2 )
2016-12-05 14:48:16 +01:00
return msg ;
return msg . substr ( 0 , pos1 + 7 ) + msg . substr ( pos2 ) ;
2016-11-22 22:37:13 +01:00
}
void checkFloatToIntegerOverflow ( ) {
check ( " void f(void) { \n "
" return (int)1E100; \n "
" } \n " ) ;
ASSERT_EQUALS ( " [test.cpp:2]: (error) Undefined behaviour: float () conversion overflow. \n " , removeFloat ( errout . str ( ) ) ) ;
check ( " void f(void) { \n "
" return (int)-1E100; \n "
" } \n " ) ;
ASSERT_EQUALS ( " [test.cpp:2]: (error) Undefined behaviour: float () conversion overflow. \n " , removeFloat ( errout . str ( ) ) ) ;
check ( " void f(void) { \n "
" return (short)1E6; \n "
" } \n " ) ;
ASSERT_EQUALS ( " [test.cpp:2]: (error) Undefined behaviour: float () conversion overflow. \n " , removeFloat ( errout . str ( ) ) ) ;
}
2014-09-11 18:10:19 +02:00
} ;
REGISTER_TEST ( TestType )