2014-09-11 18:10:19 +02:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2023-01-28 10:16:34 +01:00
* Copyright ( C ) 2007 - 2023 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 "checktype.h"
2022-01-27 19:03:20 +01:00
# include "errortypes.h"
2023-10-21 17:21:12 +02:00
# include "helpers.h"
2017-05-27 04:33:47 +02:00
# include "platform.h"
2023-10-21 17:21:12 +02:00
# include "preprocessor.h"
2017-05-27 04:33:47 +02:00
# include "settings.h"
2022-01-27 19:03:20 +01:00
# include "standards.h"
2023-01-27 08:18:32 +01:00
# include "fixture.h"
2017-05-27 04:33:47 +02:00
# include "tokenize.h"
2014-09-11 18:10:19 +02:00
2023-11-02 17:42:41 +01:00
# include <list>
2022-09-16 07:15:49 +02:00
# include <sstream> // IWYU pragma: keep
2017-05-27 04:33:47 +02:00
# include <string>
2023-11-02 17:42:41 +01:00
# include <vector>
2014-09-11 18:10:19 +02:00
2023-10-21 17:21:12 +02:00
# include <simplecpp.h>
2014-09-11 18:10:19 +02:00
class TestType : public TestFixture {
public :
2021-08-07 20:51:18 +02:00
TestType ( ) : TestFixture ( " TestType " ) { }
2014-09-11 18:10:19 +02:00
private :
2022-02-10 23:02:24 +01:00
void run ( ) override {
2017-05-22 14:46:19 +02:00
TEST_CASE ( checkTooBigShift_Unix32 ) ;
2014-09-11 18:10:19 +02:00
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 ) ;
2023-10-21 17:21:12 +02:00
TEST_CASE ( integerOverflow ) ; // #11794
2014-09-11 18:10:19 +02:00
}
2021-11-29 07:34:39 +01:00
# define check(...) check_(__FILE__, __LINE__, __VA_ARGS__)
2023-05-02 15:54:19 +02:00
void check_ ( const char * file , int line , const char code [ ] , const Settings & settings , const char filename [ ] = " test.cpp " , Standards : : cppstd_t standard = Standards : : cppstd_t : : CPP11 ) {
2014-09-11 18:10:19 +02:00
// Clear the error buffer..
errout . str ( " " ) ;
2023-05-02 15:54:19 +02:00
const Settings settings1 = settingsBuilder ( settings ) . severity ( Severity : : warning ) . severity ( Severity : : portability ) . cpp ( standard ) . build ( ) ;
2014-09-11 18:10:19 +02:00
// Tokenize..
2023-05-02 15:54:19 +02:00
Tokenizer tokenizer ( & settings1 , this ) ;
2014-09-11 18:10:19 +02:00
std : : istringstream istr ( code ) ;
2021-11-29 07:34:39 +01:00
ASSERT_LOC ( tokenizer . tokenize ( istr , filename ) , file , line ) ;
2014-09-11 18:10:19 +02:00
// Check..
2023-08-18 12:03:50 +02:00
runChecks < CheckType > ( tokenizer , this ) ;
2014-09-11 18:10:19 +02:00
}
2023-10-21 17:21:12 +02:00
# define checkP(...) checkP_(__FILE__, __LINE__, __VA_ARGS__)
void checkP_ ( const char * file , int line , const char code [ ] , const Settings & settings , const char filename [ ] = " test.cpp " , const simplecpp : : DUI & dui = simplecpp : : DUI ( ) ) {
// Clear the error buffer..
errout . str ( " " ) ;
const Settings settings1 = settingsBuilder ( settings ) . severity ( Severity : : warning ) . severity ( Severity : : portability ) . build ( ) ;
Preprocessor preprocessor ( settings1 ) ;
std : : vector < std : : string > files ( 1 , filename ) ;
Tokenizer tokenizer ( & settings1 , this , & preprocessor ) ;
PreprocessorHelper : : preprocess ( preprocessor , code , files , tokenizer , dui ) ;
// Tokenizer..
ASSERT_LOC ( tokenizer . simplifyTokens1 ( " " ) , file , line ) ;
// Check..
runChecks < CheckType > ( tokenizer , this ) ;
}
2017-05-22 14:46:19 +02:00
void checkTooBigShift_Unix32 ( ) {
2023-05-02 15:54:19 +02:00
const Settings settings0 ;
2023-10-13 16:02:04 +02:00
const Settings settings = settingsBuilder ( ) . platform ( Platform : : Type : : Unix32 ) . build ( ) ;
2014-09-11 18:10:19 +02:00
2018-02-19 23:55:38 +01:00
// unsigned types getting promoted to int sizeof(int) = 4 bytes
// and unsigned types having already a size of 4 bytes
2018-02-18 21:09:19 +01:00
{
2021-08-07 20:51:18 +02:00
const std : : string types [ ] = { " unsigned char " , /*[unsigned]*/ " char " , " bool " , " unsigned short " , " unsigned int " , " unsigned long " } ;
2019-05-02 06:53:07 +02:00
for ( const std : : string & type : types ) {
2023-05-02 15:54:19 +02:00
check ( ( type + " f( " + type + " x) { return x << 31; } " ) . c_str ( ) , settings ) ;
2019-09-25 20:16:04 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2023-05-02 15:54:19 +02:00
check ( ( type + " f( " + type + " x) { return x << 33; } " ) . c_str ( ) , settings ) ;
2018-02-19 23:55:38 +01:00
ASSERT_EQUALS ( " [test.cpp:1]: (error) Shifting 32-bit value by 33 bits is undefined behaviour \n " , errout . str ( ) ) ;
2023-05-02 15:54:19 +02:00
check ( ( type + " f(int x) { return (x = ( " + type + " )x << 32); } " ) . c_str ( ) , settings ) ;
2018-02-19 23:55:38 +01:00
ASSERT_EQUALS ( " [test.cpp:1]: (error) Shifting 32-bit value by 32 bits is undefined behaviour \n " , errout . str ( ) ) ;
2023-05-02 15:54:19 +02:00
check ( ( type + " foo( " + type + " x) { return x << 31; } " ) . c_str ( ) , settings ) ;
2018-02-19 23:55:38 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2018-02-18 21:09:19 +01:00
}
2018-02-19 23:55:38 +01:00
// signed types getting promoted to int sizeof(int) = 4 bytes
// and signed types having already a size of 4 bytes
2018-02-18 21:09:19 +01:00
{
2021-08-07 20:51:18 +02:00
const std : : string types [ ] = { " signed char " , " signed short " , /*[signed]*/ " short " , " wchar_t " , /*[signed]*/ " int " , " signed int " , /*[signed]*/ " long " , " signed long " } ;
2019-05-02 06:53:07 +02:00
for ( const std : : string & type : types ) {
2019-09-25 20:16:04 +02:00
// c++11
2023-05-02 15:54:19 +02:00
check ( ( type + " f( " + type + " x) { return x << 33; } " ) . c_str ( ) , settings ) ;
2018-02-19 23:55:38 +01:00
ASSERT_EQUALS ( " [test.cpp:1]: (error) Shifting 32-bit value by 33 bits is undefined behaviour \n " , errout . str ( ) ) ;
2023-05-02 15:54:19 +02:00
check ( ( type + " f(int x) { return (x = ( " + type + " )x << 32); } " ) . c_str ( ) , settings ) ;
2018-02-19 23:55:38 +01:00
ASSERT_EQUALS ( " [test.cpp:1]: (error) Shifting 32-bit value by 32 bits is undefined behaviour \n " , errout . str ( ) ) ;
2023-05-02 15:54:19 +02:00
check ( ( type + " foo( " + type + " x) { return x << 31; } " ) . c_str ( ) , settings ) ;
2018-02-19 23:55:38 +01:00
ASSERT_EQUALS ( " [test.cpp:1]: (error) Shifting signed 32-bit value by 31 bits is undefined behaviour \n " , errout . str ( ) ) ;
2023-05-02 15:54:19 +02:00
check ( ( type + " foo( " + type + " x) { return x << 30; } " ) . c_str ( ) , settings ) ;
2018-02-19 23:55:38 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2019-09-25 20:16:04 +02:00
// c++14
2023-05-02 15:54:19 +02:00
check ( ( type + " foo( " + type + " x) { return x << 31; } " ) . c_str ( ) , settings , " test.cpp " , Standards : : cppstd_t : : CPP14 ) ;
2019-09-25 20:16:04 +02:00
ASSERT_EQUALS ( " [test.cpp:1]: (portability) Shifting signed 32-bit value by 31 bits is implementation-defined behaviour \n " , errout . str ( ) ) ;
2023-05-02 15:54:19 +02:00
check ( ( type + " f(int x) { return (x = ( " + type + " )x << 32); } " ) . c_str ( ) , settings , " test.cpp " , Standards : : cppstd_t : : CPP14 ) ;
2019-09-25 20:16:04 +02:00
ASSERT_EQUALS ( " [test.cpp:1]: (error) Shifting 32-bit value by 32 bits is undefined behaviour \n " , errout . str ( ) ) ;
2018-02-19 23:55:38 +01:00
}
2018-02-18 21:09:19 +01:00
}
// 64 bit width types
{
// unsigned long long
2023-05-02 15:54:19 +02:00
check ( " unsigned long long foo(unsigned long long x) { return x << 64; } " , settings ) ;
2018-02-18 21:09:19 +01:00
ASSERT_EQUALS ( " [test.cpp:1]: (error) Shifting 64-bit value by 64 bits is undefined behaviour \n " , errout . str ( ) ) ;
2023-05-02 15:54:19 +02:00
check ( " unsigned long long f(int x) { return (x = (unsigned long long)x << 64); } " , settings ) ;
2018-02-18 21:09:19 +01:00
ASSERT_EQUALS ( " [test.cpp:1]: (error) Shifting 64-bit value by 64 bits is undefined behaviour \n " , errout . str ( ) ) ;
2023-05-02 15:54:19 +02:00
check ( " unsigned long long f(unsigned long long x) { return x << 63; } " , settings ) ;
2018-02-18 21:09:19 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// [signed] long long
2023-05-02 15:54:19 +02:00
check ( " long long foo(long long x) { return x << 64; } " , settings ) ;
2018-02-18 21:09:19 +01:00
ASSERT_EQUALS ( " [test.cpp:1]: (error) Shifting 64-bit value by 64 bits is undefined behaviour \n " , errout . str ( ) ) ;
2023-05-02 15:54:19 +02:00
check ( " long long f(int x) { return (x = (long long)x << 64); } " , settings ) ;
2018-02-18 21:09:19 +01:00
ASSERT_EQUALS ( " [test.cpp:1]: (error) Shifting 64-bit value by 64 bits is undefined behaviour \n " , errout . str ( ) ) ;
2023-05-02 15:54:19 +02:00
check ( " long long f(long long x) { return x << 63; } " , settings ) ;
2018-02-18 21:09:19 +01:00
ASSERT_EQUALS ( " [test.cpp:1]: (error) Shifting signed 64-bit value by 63 bits is undefined behaviour \n " , errout . str ( ) ) ;
2023-05-02 15:54:19 +02:00
check ( " long long f(long long x) { return x << 62; } " , settings ) ;
2018-02-18 21:09:19 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// signed long long
2023-05-02 15:54:19 +02:00
check ( " signed long long foo(signed long long x) { return x << 64; } " , settings ) ;
2018-02-18 21:09:19 +01:00
ASSERT_EQUALS ( " [test.cpp:1]: (error) Shifting 64-bit value by 64 bits is undefined behaviour \n " , errout . str ( ) ) ;
2023-05-02 15:54:19 +02:00
check ( " signed long long f(long long x) { return (x = (signed long long)x << 64); } " , settings ) ;
2018-02-18 21:09:19 +01:00
ASSERT_EQUALS ( " [test.cpp:1]: (error) Shifting 64-bit value by 64 bits is undefined behaviour \n " , errout . str ( ) ) ;
2023-05-02 15:54:19 +02:00
check ( " signed long long f(signed long long x) { return x << 63; } " , settings ) ;
2018-02-18 21:09:19 +01:00
ASSERT_EQUALS ( " [test.cpp:1]: (error) Shifting signed 64-bit value by 63 bits is undefined behaviour \n " , errout . str ( ) ) ;
2023-05-02 15:54:19 +02:00
check ( " signed long long f(signed long long x) { return x << 62; } " , settings ) ;
2018-02-18 21:09:19 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2019-09-25 20:16:04 +02:00
// c++14
2023-05-02 15:54:19 +02:00
check ( " signed long long foo(signed long long x) { return x << 64; } " , settings , " test.cpp " , Standards : : cppstd_t : : CPP14 ) ;
2019-09-25 20:16:04 +02:00
ASSERT_EQUALS ( " [test.cpp:1]: (error) Shifting 64-bit value by 64 bits is undefined behaviour \n " , errout . str ( ) ) ;
2023-05-02 15:54:19 +02:00
check ( " signed long long f(long long x) { return (x = (signed long long)x << 64); } " , settings , " test.cpp " , Standards : : cppstd_t : : CPP14 ) ;
2019-09-25 20:16:04 +02:00
ASSERT_EQUALS ( " [test.cpp:1]: (error) Shifting 64-bit value by 64 bits is undefined behaviour \n " , errout . str ( ) ) ;
2023-05-02 15:54:19 +02:00
check ( " signed long long f(signed long long x) { return x << 63; } " , settings , " test.cpp " , Standards : : cppstd_t : : CPP14 ) ;
2019-09-25 20:16:04 +02:00
ASSERT_EQUALS ( " [test.cpp:1]: (portability) Shifting signed 64-bit value by 63 bits is implementation-defined behaviour \n " , errout . str ( ) ) ;
2023-05-02 15:54:19 +02:00
check ( " signed long long f(signed long long x) { return x << 62; } " , settings ) ;
2019-09-25 20:16:04 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2018-02-18 21:09:19 +01:00
}
2014-10-23 06:52:19 +02:00
2023-05-02 15:54:19 +02:00
check ( " void f() { int x; x = 1 >> 64; } " , settings ) ;
2021-04-28 11:57:28 +02:00
ASSERT_EQUALS ( " [test.cpp:1]: (error) Shifting 32-bit value by 64 bits is undefined behaviour \n " , errout . str ( ) ) ;
2014-10-23 06:52:19 +02:00
check ( " void foo() { \n "
" QList<int> someList; \n "
" someList << 300; \n "
2023-05-02 15:54:19 +02:00
" } " , settings ) ;
2014-10-23 06:52:19 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2015-08-02 00:03:09 +02:00
// Ticket #6793
2017-09-19 09:08:44 +02:00
check ( " template<unsigned int I> int foo(unsigned int x) { return x << I; } \n "
" const unsigned int f = foo<31>(0); \n "
" const unsigned int g = foo<100>(0); \n "
" template<unsigned int I> int hoo(unsigned int x) { return x << 32; } \n "
2023-05-02 15:54:19 +02:00
" const unsigned 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
2017-09-19 09:08:44 +02:00
check ( " void f(unsigned int x) { \n "
2016-01-10 20:44:52 +01:00
" UINFO(x << 1234); \n "
2023-05-02 15:54:19 +02:00
" } " , settings0 ) ;
2016-01-10 20:44:52 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2019-09-20 15:06:37 +02:00
2021-12-19 17:43:32 +01:00
// #8640
check ( " int f (void) \n "
" { \n "
" constexpr const int a = 1; \n "
" constexpr const int shift[1] = {32}; \n "
" constexpr const int ret = a << shift[0]; \n " // shift too many bits
" return ret; \n "
2023-05-02 15:54:19 +02:00
" } " , settings0 ) ;
2021-12-19 17:43:32 +01:00
ASSERT_EQUALS ( " [test.cpp:5]: (error) Shifting 32-bit value by 32 bits is undefined behaviour \n "
" [test.cpp:5]: (error) Signed integer overflow for expression 'a<<shift[0]'. \n " , errout . str ( ) ) ;
2019-09-20 15:06:37 +02:00
// #8885
check ( " int f(int k, int rm) { \n "
" if (k == 32) \n "
" return 0; \n "
" if (k > 32) \n "
" return 0; \n "
" return rm>> k; \n "
2023-05-02 15:54:19 +02:00
" } " , settings0 ) ;
2019-09-20 15:06:37 +02:00
ASSERT_EQUALS (
" [test.cpp:4] -> [test.cpp:6]: (warning) Shifting signed 32-bit value by 31 bits is undefined behaviour. See condition at line 4. \n " ,
errout . str ( ) ) ;
check ( " int f(int k, int rm) { \n "
" if (k == 0 || k == 32) \n "
" return 0; \n "
" else if (k > 32) \n "
" return 0; \n "
" else \n "
" return rm>> k; \n "
2023-05-02 15:54:19 +02:00
" } " , settings0 ) ;
2019-09-20 15:06:37 +02:00
ASSERT_EQUALS (
" [test.cpp:4] -> [test.cpp:7]: (warning) Shifting signed 32-bit value by 31 bits is undefined behaviour. See condition at line 4. \n " ,
errout . str ( ) ) ;
check ( " int f(int k, int rm) { \n "
" if (k == 0 || k == 32 || k == 31) \n "
" return 0; \n "
" else if (k > 32) \n "
" return 0; \n "
" else \n "
" return rm>> k; \n "
2023-05-02 15:54:19 +02:00
" } " , settings0 ) ;
2019-09-20 15:06:37 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " static long long f(int x, long long y) { \n "
" if (x >= 64) \n "
" return 0; \n "
" return -(y << (x-1)); \n "
2023-05-02 15:54:19 +02:00
" } " , settings0 ) ;
2019-09-20 15:06:37 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2021-03-11 08:16:25 +01:00
check ( " bool f() { \n "
" std::ofstream outfile; \n "
" outfile << vec_points[0](0) << static_cast<int>(d) << ' '; \n "
2023-05-02 15:54:19 +02:00
" } " , settings0 ) ;
2021-03-11 08:16:25 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2022-04-30 08:20:00 +02:00
check ( " void f(unsigned b, int len, unsigned char rem) { \n " // #10773
" int bits = 0; \n "
" while (len > 8) { \n "
" b = b >> rem; \n "
" bits += 8 - rem; \n "
" if (bits == 512) \n "
" len -= 8; \n "
" } \n "
2023-05-02 15:54:19 +02:00
" } \n " , settings0 ) ;
2022-04-30 08:20:00 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2014-09-11 18:10:19 +02:00
}
2014-11-20 14:20:09 +01:00
void checkIntegerOverflow ( ) {
2023-10-13 16:02:04 +02:00
const Settings settings = settingsBuilder ( ) . severity ( Severity : : warning ) . platform ( Platform : : Type : : Unix32 ) . build ( ) ;
2014-09-11 18:10:19 +02:00
2023-05-02 15:54:19 +02:00
check ( " x = (int)0x10000 * (int)0x10000; " , settings ) ;
2020-02-19 07:51:39 +01:00
ASSERT_EQUALS ( " [test.cpp:1]: (error) Signed integer overflow for expression '(int)0x10000*(int)0x10000'. \n " , errout . str ( ) ) ;
2017-09-19 14:43:48 +02:00
2023-05-02 15:54:19 +02:00
check ( " x = (long)0x10000 * (long)0x10000; " , settings ) ;
2020-02-19 07:51:39 +01:00
ASSERT_EQUALS ( " [test.cpp:1]: (error) Signed integer overflow for expression '(long)0x10000*(long)0x10000'. \n " , errout . str ( ) ) ;
2017-09-19 19:14:29 +02:00
2016-11-05 09:29:52 +01:00
check ( " void foo() { \n "
" int intmax = 0x7fffffff; \n "
" return intmax + 1; \n "
2023-05-02 15:54:19 +02:00
" } " , settings ) ;
2016-11-05 09:29:52 +01:00
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 "
2023-05-02 15:54:19 +02:00
" } " , settings ) ;
2016-11-07 22:29:40 +01:00
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 "
2023-05-02 15:54:19 +02:00
" } " , settings ) ;
2017-05-22 10:10:56 +02:00
ASSERT_EQUALS ( " [test.cpp:2] -> [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 "
2023-05-02 15:54:19 +02:00
" } " , settings ) ;
2017-05-22 10:10:56 +02:00
ASSERT_EQUALS ( " [test.cpp:2] -> [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 "
2023-05-02 15:54:19 +02:00
" } " , settings ) ;
2014-09-11 18:10:19 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2023-10-28 16:47:57 +02:00
check ( " int f(int i) { \n " // #12117
" return (i == 31) ? 1 << i : 0; \n "
" } " , settings ) ;
ASSERT_EQUALS ( " [test.cpp:2] -> [test.cpp:2]: (warning) Shifting signed 32-bit value by 31 bits is undefined behaviour. See condition at line 2. \n " , errout . str ( ) ) ;
2014-09-11 18:10:19 +02:00
}
2014-11-20 14:20:09 +01:00
void signConversion ( ) {
2023-05-02 15:54:19 +02:00
const Settings settings0 ;
2023-10-13 16:02:04 +02:00
const Settings settings = settingsBuilder ( ) . platform ( Platform : : Type : : Unix64 ) . build ( ) ;
2023-05-02 15:54:19 +02:00
check ( " x = -4 * (unsigned)y; " , settings0 ) ;
2019-07-17 22:41:24 +02:00
ASSERT_EQUALS ( " [test.cpp:1]: (warning) Expression '-4' has a negative value. That is converted to an unsigned value and used in an unsigned calculation. \n " , errout . str ( ) ) ;
2018-12-23 12:42:18 +01:00
2023-05-02 15:54:19 +02:00
check ( " x = (unsigned)y * -4; " , settings0 ) ;
2020-07-20 11:15:18 +02:00
ASSERT_EQUALS ( " [test.cpp:1]: (warning) Expression '-4' has a negative value. That is converted to an unsigned value and used in an unsigned calculation. \n " , errout . str ( ) ) ;
2018-12-23 12:42:18 +01:00
check ( " unsigned int dostuff(int x) { \n " // x is signed
" if (x==0) {} \n "
" return (x-1)*sizeof(int); \n "
2023-05-02 15:54:19 +02:00
" } " , settings ) ;
2019-08-05 12:41:08 +02:00
ASSERT_EQUALS ( " [test.cpp:2] -> [test.cpp:3]: (warning) Expression 'x-1' can have a negative value. That is converted to an unsigned value and used in an unsigned calculation. \n " , errout . str ( ) ) ;
2017-09-19 19:30:24 +02:00
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 "
2023-05-02 15:54:19 +02:00
" void f2() { f1(-4,4); } " , settings0 ) ;
2019-08-05 16:26:32 +02:00
ASSERT_EQUALS (
" [test.cpp:1]: (warning) Expression 'x' can have a negative value. That is converted to an unsigned value and used in an unsigned calculation. \n " ,
errout . str ( ) ) ;
2014-09-12 16:18:42 +02:00
2019-07-17 22:41:24 +02:00
check ( " unsigned int f1(int x) { "
2014-09-12 16:18:42 +02:00
" return x * 5U; \n "
" } \n "
2023-05-02 15:54:19 +02:00
" void f2() { f1(-4); } " , settings0 ) ;
2019-08-05 16:26:32 +02:00
ASSERT_EQUALS (
" [test.cpp:1]: (warning) Expression 'x' can have a negative value. That is converted to an unsigned value and used in an unsigned calculation. \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 "
2023-05-02 15:54:19 +02:00
" void f2() { f1(-4); } " , settings0 ) ;
2014-09-14 10:29:58 +02:00
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 "
2023-05-02 15:54:19 +02:00
" void f2() { f1(-4); } " , settings0 ) ;
2014-09-12 18:58:31 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2016-01-02 22:56:15 +01:00
check ( " size_t foo(size_t x) { \n "
" return -2 * x; \n "
2023-05-02 15:54:19 +02:00
" } " , settings0 ) ;
2019-07-17 22:41:24 +02:00
ASSERT_EQUALS ( " [test.cpp:2]: (warning) Expression '-2' has a negative value. That is converted to an unsigned value and used in an unsigned calculation. \n " , errout . str ( ) ) ;
2014-09-11 18:10:19 +02:00
}
2015-05-25 10:02:17 +02:00
void longCastAssign ( ) {
2023-10-13 16:02:04 +02:00
const Settings settings = settingsBuilder ( ) . severity ( Severity : : style ) . platform ( Platform : : Type : : Unix64 ) . build ( ) ;
const Settings settingsWin = settingsBuilder ( ) . severity ( Severity : : style ) . platform ( Platform : : Type : : Win64 ) . build ( ) ;
2023-08-02 12:27:29 +02:00
const char code [ ] = " long f(int x, int y) { \n "
" const long ret = x * y; \n "
" return ret; \n "
" } \n " ;
check ( code , settings ) ;
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 ( ) ) ;
check ( code , settingsWin ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2015-05-25 10:02:17 +02:00
check ( " long f(int x, int y) { \n "
2023-08-02 12:27:29 +02:00
" long ret = x * y; \n "
2015-05-25 10:02:17 +02:00
" return ret; \n "
2023-05-02 15:54:19 +02:00
" } \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
2018-06-04 22:51:21 +02:00
check ( " long f() { \n "
" const long long ret = 256 * (1 << 10); \n "
" return ret; \n "
2023-05-02 15:54:19 +02:00
" } \n " , settings ) ;
2018-06-04 22:51:21 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
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 "
2023-05-02 15:54:19 +02:00
" } \n " , settings ) ;
2015-05-25 18:19:40 +02:00
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 "
2023-05-02 15:54:19 +02:00
" } \n " , settings ) ;
2015-05-25 10:02:17 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2023-08-02 12:27:29 +02:00
check ( " double g(float f) { \n "
" return f * f; \n "
" } \n " , settings ) ;
ASSERT_EQUALS ( " [test.cpp:2]: (style) float result is returned as double value. If the return value is double to avoid loss of information, then you have loss of information. \n " ,
errout . str ( ) ) ;
2023-08-03 13:49:11 +02:00
check ( " void f(int* p) { \n " // #11862
" long long j = *(p++); \n "
" } \n " , settings ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2015-05-25 10:02:17 +02:00
}
void longCastReturn ( ) {
2023-10-13 16:02:04 +02:00
const Settings settings = settingsBuilder ( ) . severity ( Severity : : style ) . platform ( Platform : : Type : : Unix64 ) . build ( ) ;
const Settings settingsWin = settingsBuilder ( ) . severity ( Severity : : style ) . platform ( Platform : : Type : : Win64 ) . build ( ) ;
2015-05-25 10:02:17 +02:00
2023-08-02 12:27:29 +02:00
const char code [ ] = " long f(int x, int y) { \n "
" return x * y; \n "
" } \n " ;
check ( code , 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 ( ) ) ;
2023-08-02 12:27:29 +02:00
check ( code , settingsWin ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
const char code2 [ ] = " long long f(int x, int y) { \n "
" return x * y; \n "
" } \n " ;
check ( code2 , settings ) ;
ASSERT_EQUALS ( " [test.cpp:2]: (style) int result is returned as long long value. If the return value is long long to avoid loss of information, then you have loss of information. \n " , errout . str ( ) ) ;
check ( code2 , settingsWin ) ;
ASSERT_EQUALS ( " [test.cpp:2]: (style) int result is returned as long long value. If the return value is long 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 "
2023-05-02 15:54:19 +02:00
" } \n " , settings ) ;
2023-08-02 12:27:29 +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 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.
2017-04-09 16:59:41 +02:00
static std : : string removeFloat ( const std : : string & msg ) {
2018-09-24 15:08:16 +02:00
const std : : string : : size_type pos1 = msg . find ( " float ( " ) ;
const std : : string : : size_type pos2 = msg . find ( " ) to integer 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 ( ) {
2023-05-02 15:54:19 +02:00
const Settings settings ;
check ( " x = (int)1E100; " , settings ) ;
2017-09-19 19:30:24 +02:00
ASSERT_EQUALS ( " [test.cpp:1]: (error) Undefined behaviour: float () to integer conversion overflow. \n " , removeFloat ( errout . str ( ) ) ) ;
2016-11-22 22:37:13 +01:00
check ( " void f(void) { \n "
" return (int)1E100; \n "
2023-05-02 15:54:19 +02:00
" } " , settings ) ;
2017-05-22 11:04:24 +02:00
ASSERT_EQUALS ( " [test.cpp:2]: (error) Undefined behaviour: float () to integer conversion overflow. \n " , removeFloat ( errout . str ( ) ) ) ;
2016-11-22 22:37:13 +01:00
check ( " void f(void) { \n "
" return (int)-1E100; \n "
2023-05-02 15:54:19 +02:00
" } " , settings ) ;
2017-05-22 11:04:24 +02:00
ASSERT_EQUALS ( " [test.cpp:2]: (error) Undefined behaviour: float () to integer conversion overflow. \n " , removeFloat ( errout . str ( ) ) ) ;
2016-11-22 22:37:13 +01:00
check ( " void f(void) { \n "
" return (short)1E6; \n "
2023-05-02 15:54:19 +02:00
" } " , settings ) ;
2017-05-22 11:04:24 +02:00
ASSERT_EQUALS ( " [test.cpp:2]: (error) Undefined behaviour: float () to integer conversion overflow. \n " , removeFloat ( errout . str ( ) ) ) ;
2016-12-10 23:14:40 +01:00
check ( " void f(void) { \n "
" return (unsigned char)256.0; \n "
2023-05-02 15:54:19 +02:00
" } " , settings ) ;
2017-05-22 11:04:24 +02:00
ASSERT_EQUALS ( " [test.cpp:2]: (error) Undefined behaviour: float () to integer conversion overflow. \n " , removeFloat ( errout . str ( ) ) ) ;
2016-12-10 23:14:40 +01:00
check ( " void f(void) { \n "
" return (unsigned char)255.5; \n "
2023-05-02 15:54:19 +02:00
" } " , settings ) ;
2016-12-10 23:14:40 +01:00
ASSERT_EQUALS ( " " , removeFloat ( errout . str ( ) ) ) ;
2017-08-23 05:34:47 +02:00
check ( " void f(void) { \n "
" char c = 1234.5; \n "
2023-05-02 15:54:19 +02:00
" } " , settings ) ;
2017-08-23 05:34:47 +02:00
ASSERT_EQUALS ( " [test.cpp:2]: (error) Undefined behaviour: float () to integer conversion overflow. \n " , removeFloat ( errout . str ( ) ) ) ;
2019-07-24 16:17:52 +02:00
check ( " char f(void) { \n "
" return 1234.5; \n "
2023-05-02 15:54:19 +02:00
" } " , settings ) ;
2019-07-24 16:17:52 +02:00
ASSERT_EQUALS ( " [test.cpp:2]: (error) Undefined behaviour: float () to integer conversion overflow. \n " , removeFloat ( errout . str ( ) ) ) ;
2016-11-22 22:37:13 +01:00
}
2023-10-21 17:21:12 +02:00
void integerOverflow ( ) { // #11794
const Settings settings ;
// TODO: needs to use preprocessing production code
simplecpp : : DUI dui ;
dui . std = " c++11 " ;
// this is set by the production code via cppcheck::Platform::getLimitDefines()
dui . defines . emplace_back ( " INT_MIN=-2147483648 " ) ;
checkP ( " int fun(int x) \n "
" { \n "
" if(x < 0) x = -x; \n "
" return x >= 0; \n "
" } \n "
" int f() \n "
" { \n "
" fun(INT_MIN); \n "
" } " , settings , " test.cpp " , dui ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (error) Signed integer overflow for expression '-x'. \n " , errout . str ( ) ) ;
}
2014-09-11 18:10:19 +02:00
} ;
REGISTER_TEST ( TestType )