Replaced CheckNonReentrantFunctions and CheckObsoleteFunctions by generic CheckFunctions which is based on Library (#6529)

This commit is contained in:
PKEuS 2015-11-21 20:24:30 +01:00
parent 517922feb6
commit 57d1196386
18 changed files with 963 additions and 554 deletions

View File

@ -19,6 +19,8 @@
<leak-ignore/> <leak-ignore/>
<arg nr="1"> <arg nr="1">
<not-uninit/> <not-uninit/>
<!-- The behavior of l64a() is undefined when value is negative. -->
<!-- If value is zero, it returns an empty string. -->
<valid>0:</valid> <valid>0:</valid>
</arg> </arg>
</function> </function>
@ -213,11 +215,13 @@
<!-- int usleep(useconds_t useconds); --> <!-- int usleep(useconds_t useconds); -->
<function name="usleep"> <function name="usleep">
<noreturn>false</noreturn> <noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1"> <arg nr="1">
<not-bool/> <not-bool/>
<valid>0:999999</valid> <valid>0:999999</valid>
</arg> </arg>
<leak-ignore/>
<warn severity="style">Obsolescent function 'usleep' called. It is recommended to use 'nanosleep' or 'setitimer' instead.
The obsolescent function 'usleep' is called. POSIX.1-2001 declares usleep() function obsolescent and POSIX.1-2008 removes it. It is recommended that new applications use the 'nanosleep' or 'setitimer' function.</warn>
</function> </function>
<!-- void _exit(int status); --> <!-- void _exit(int status); -->
<function name="_exit"> <function name="_exit">
@ -277,23 +281,168 @@
<!-- unsigned int alarm(unsigned int seconds); --> <!-- unsigned int alarm(unsigned int seconds); -->
<function name="alarm"> <function name="alarm">
<noreturn>false</noreturn> <noreturn>false</noreturn>
<arg nr="1">
<not-uninit/>
</arg>
<leak-ignore/>
</function>
<!-- struct rpcent *getrpcent(void); -->
<function name="getrpcent">
<noreturn>false</noreturn>
<use-retval/>
<leak-ignore/>
<warn severity="portability">Non reentrant function 'getrpcent' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getrpcent_r'.</warn>
</function>
<!-- struct rpcent *getrpcbyname(char *name); -->
<function name="getrpcbyname">
<noreturn>false</noreturn>
<use-retval/>
<leak-ignore/>
<arg nr="1">
<not-uninit/>
<not-null/>
</arg>
<warn severity="portability">Non reentrant function 'getrpcbyname' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getrpcbyname_r'.</warn>
</function>
<!-- truct rpcent *getrpcbynumber(int number); -->
<function name="getrpcbynumber">
<noreturn>false</noreturn>
<use-retval/>
<leak-ignore/> <leak-ignore/>
<arg nr="1"> <arg nr="1">
<not-uninit/> <not-uninit/>
</arg> </arg>
<warn severity="portability">Non reentrant function 'getrpcbynumber' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getrpcbynumber_r'.</warn>
</function>
<!-- struct protoent *getprotoent(void); -->
<function name="getprotoent">
<noreturn>false</noreturn>
<use-retval/>
<leak-ignore/>
<warn severity="portability">Non reentrant function 'getprotoent' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getprotoent_r'.</warn>
</function>
<!-- struct protoent *getprotobyname(const char *name); -->
<function name="getprotobyname">
<noreturn>false</noreturn>
<use-retval/>
<leak-ignore/>
<arg nr="1">
<not-uninit/>
<not-null/>
</arg>
<warn severity="portability">Non reentrant function 'getprotobyname' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getprotobyname_r'.</warn>
</function>
<!-- struct protoent *getprotobynumber(int proto); -->
<function name="getservbyport">
<noreturn>false</noreturn>
<use-retval/>
<leak-ignore/>
<arg nr="1">
<not-uninit/>
</arg>
<warn severity="portability">Non reentrant function 'getprotobynumber' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getprotobynumber_r'.</warn>
</function>
<!-- struct servent *getservent(void); -->
<function name="getservent">
<noreturn>false</noreturn>
<use-retval/>
<leak-ignore/>
<warn severity="portability">Non reentrant function 'getservent' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getservent_r'.</warn>
</function>
<!-- struct servent *getservbyname(const char *name, const char *proto); -->
<function name="getservbyname">
<noreturn>false</noreturn>
<use-retval/>
<leak-ignore/>
<arg nr="1">
<not-uninit/>
<not-null/>
</arg>
<arg nr="2">
<not-uninit/>
</arg>
<warn severity="portability">Non reentrant function 'getservbyname' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getservbyname_r'.</warn>
</function>
<!-- struct servent *getservbyport(int port, const char *proto); -->
<function name="getservbyport">
<noreturn>false</noreturn>
<use-retval/>
<leak-ignore/>
<arg nr="1">
<not-uninit/>
</arg>
<arg nr="2">
<not-uninit/>
</arg>
<warn severity="portability">Non reentrant function 'getservbyport' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getservbyport_r'.</warn>
</function>
<!-- struct netent *getnetent(void); -->
<function name="getnetent">
<noreturn>false</noreturn>
<use-retval/>
<leak-ignore/>
<warn severity="portability">Non reentrant function 'getnetent' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getnetent_r'.</warn>
</function>
<!-- struct netent *getnetbyname(const char *name); -->
<function name="getnetbyname">
<noreturn>false</noreturn>
<use-retval/>
<arg nr="1">
<not-uninit/>
<not-null/>
</arg>
<leak-ignore/>
<warn severity="portability">Non reentrant function 'getnetbyname' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getnetbyname_r'.</warn>
</function>
<!-- struct netent *getnetbyaddr(uint32_t net, int type); -->
<function name="getnetbyaddr">
<noreturn>false</noreturn>
<use-retval/>
<arg nr="1">
<not-uninit/>
</arg>
<arg nr="2">
<not-uninit/>
</arg>
<leak-ignore/>
<warn severity="portability">Non reentrant function 'getnetbyaddr' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getnetbyaddr_r'.</warn>
</function>
<!-- struct hostent *gethostent(void); -->
<function name="gethostent">
<noreturn>false</noreturn>
<use-retval/>
<leak-ignore/>
<warn severity="portability">Non reentrant function 'gethostent' called. For threadsafe applications it is recommended to use the reentrant replacement function 'gethostent_r'.</warn>
</function> </function>
<!-- struct hostent *gethostbyname(const char *name); --> <!-- struct hostent *gethostbyname(const char *name); -->
<function name="gethostbyname"> <function name="gethostbyname">
<noreturn>false</noreturn> <noreturn>false</noreturn>
<leak-ignore/> <use-retval/>
<arg nr="1"> <arg nr="1">
<not-uninit/>
<not-null/> <not-null/>
</arg>
<leak-ignore/>
<warn severity="style" reason="Obsolescent" alternatives="getaddrinfo"/>
</function>
<!-- struct hostent *gethostbyname2(const char *name, int af); -->
<function name="gethostbyname2">
<noreturn>false</noreturn>
<use-retval/>
<arg nr="1">
<not-uninit/>
<not-null/>
</arg>
<arg nr="2">
<not-uninit/> <not-uninit/>
</arg> </arg>
<leak-ignore/>
<warn severity="portability">Non reentrant function 'gethostbyname2' called. For threadsafe applications it is recommended to use the reentrant replacement function 'gethostbyname2_r'.</warn>
</function> </function>
<!-- struct hostent *gethostbyaddr(const void *addr, socklen_t len, int type); --> <!-- struct hostent *gethostbyaddr(const void *addr, socklen_t len, int type); -->
<function name="gethostbyaddr"> <function name="gethostbyaddr">
<noreturn>false</noreturn> <noreturn>false</noreturn>
<use-retval/>
<leak-ignore/> <leak-ignore/>
<arg nr="1"> <arg nr="1">
<not-null/> <not-null/>
@ -305,6 +454,7 @@
<arg nr="3"> <arg nr="3">
<not-uninit/> <not-uninit/>
</arg> </arg>
<warn severity="style" reason="Obsolescent" alternatives="getnameinfo"/>
</function> </function>
<!-- int brk(void *addr); --> <!-- int brk(void *addr); -->
<function name="brk"> <function name="brk">
@ -560,6 +710,7 @@
<arg nr="2"> <arg nr="2">
<not-uninit/> <not-uninit/>
</arg> </arg>
<warn severity="style" reason="Obsolescent" alternatives="utimensat"/>
</function> </function>
<!-- int utimes(const char *filename, const struct timeval times[2]); --> <!-- int utimes(const char *filename, const struct timeval times[2]); -->
<function name="utimes"> <function name="utimes">
@ -735,6 +886,7 @@
<arg nr="1"> <arg nr="1">
<not-null/> <not-null/>
</arg> </arg>
<warn severity="style" reason="Obsolescent" alternatives="rand"/>
</function> </function>
<function name="memmem"> <function name="memmem">
<noreturn>false</noreturn> <noreturn>false</noreturn>
@ -1166,14 +1318,16 @@
<!-- pid_t setsid(void); --> <!-- pid_t setsid(void); -->
<function name="setsid"> <function name="setsid">
<noreturn>false</noreturn> <noreturn>false</noreturn>
<!-- it is a good idea to do: <use-retval/> -->
</function> </function>
<!-- char *getwd(char *path_name);--> <!-- char *getwd(char *path_name);-->
<function name="getwd"> <function name="getwd">
<noreturn>false</noreturn> <noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1"> <arg nr="1">
<not-null/> <not-null/>
</arg> </arg>
<leak-ignore/>
<warn severity="style" reason="Obsolescent" alternatives="getcwd"/>
</function> </function>
<!-- http://pubs.opengroup.org/onlinepubs/009695399/basedefs/arpa/inet.h.html --> <!-- http://pubs.opengroup.org/onlinepubs/009695399/basedefs/arpa/inet.h.html -->
<!-- uint32_t htonl(uint32_t); --> <!-- uint32_t htonl(uint32_t); -->
@ -1384,8 +1538,9 @@
<function name="freeaddrinfo"> <function name="freeaddrinfo">
<noreturn>false</noreturn> <noreturn>false</noreturn>
<arg nr="1"> <arg nr="1">
<not-null/>
<not-uninit/> <not-uninit/>
<not-null/>
<!-- not-null is not required by the resource above, but some systems will segfault -->
</arg> </arg>
</function> </function>
<!-- int getaddrinfo(const char * nodename, const char * servname, const struct addrinfo * hints, struct addrinfo ** res); --> <!-- int getaddrinfo(const char * nodename, const char * servname, const struct addrinfo * hints, struct addrinfo ** res); -->
@ -1433,21 +1588,38 @@
</function> </function>
<!--struct passwd *getpwent(void); --> <!--struct passwd *getpwent(void); -->
<function name="getpwent"> <function name="getpwent">
<use-retval/>
<noreturn>false</noreturn> <noreturn>false</noreturn>
<use-retval/>
<warn severity="portability">Non reentrant function 'getpwent' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getpwent_r'.</warn>
</function> </function>
<!--struct passwd *getpwnam(const char *); --> <!--struct passwd *getpwnam(const char *); -->
<function name="getpwnam"> <function name="getpwnam">
<use-retval/>
<noreturn>false</noreturn>
<arg nr="1"> <arg nr="1">
<not-uninit/> <not-uninit/>
</arg> </arg>
<noreturn>false</noreturn>
<use-retval/>
<warn severity="portability">Non reentrant function 'getpwnam' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getpwnam_r'.</warn>
</function>
<!-- char *strtok(char *s, const char *ct); -->
<function name="strtok,std::strtok">
<pure/>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1">
<not-uninit/>
</arg>
<arg nr="2">
<not-null/>
<not-uninit/>
</arg>
<warn severity="portability">Non reentrant function 'strtok' called. For threadsafe applications it is recommended to use the reentrant replacement function 'strtok_r'.</warn>
</function> </function>
<!-- char *strtok_r(char *str, const char *delim, char **saveptr); --> <!-- char *strtok_r(char *str, const char *delim, char **saveptr); -->
<function name="strtok_r"> <function name="strtok_r">
<pure/> <!-- strtok may modify the first argument, so using the return value is not mandatory -->
<noreturn>false</noreturn> <noreturn>false</noreturn>
<pure/>
<leak-ignore/> <leak-ignore/>
<arg nr="1"> <arg nr="1">
<not-uninit/> <not-uninit/>
@ -1470,11 +1642,12 @@
</function> </function>
<!-- struct passwd *getpwuid(uid_t uid); --> <!-- struct passwd *getpwuid(uid_t uid); -->
<function name="getpwuid"> <function name="getpwuid">
<use-retval/>
<noreturn>false</noreturn>
<arg nr="1"> <arg nr="1">
<not-uninit/> <not-uninit/>
</arg> </arg>
<noreturn>false</noreturn>
<use-retval/>
<warn severity="portability">Non reentrant function 'getpwuid' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getpwuid_r'.</warn>
</function> </function>
<!-- int getpwuid_r(uid_t, struct passwd *, char *, size_t, struct passwd **); --> <!-- int getpwuid_r(uid_t, struct passwd *, char *, size_t, struct passwd **); -->
<function name="getpwuid_r"> <function name="getpwuid_r">
@ -1672,6 +1845,7 @@
<arg nr="4"> <arg nr="4">
<not-null/> <not-null/>
</arg> </arg>
<warn severity="style" reason="Obsolescent" alternatives="sprintf"/>
</function> </function>
<!-- char *fcvt(double value, int ndigit, int *restrict decpt, int *restrict sign);--> <!-- char *fcvt(double value, int ndigit, int *restrict decpt, int *restrict sign);-->
<!-- LEGACY in POSIX.1-2001, removed in POSIX.1-2008--> <!-- LEGACY in POSIX.1-2001, removed in POSIX.1-2008-->
@ -1689,6 +1863,7 @@
<arg nr="4"> <arg nr="4">
<not-null/> <not-null/>
</arg> </arg>
<warn severity="style" reason="Obsolescent" alternatives="sprintf"/>
</function> </function>
<!-- char *gcvt(double value, int ndigit, char *buf);--> <!-- char *gcvt(double value, int ndigit, char *buf);-->
<!-- LEGACY in POSIX.1-2001, removed in POSIX.1-2008--> <!-- LEGACY in POSIX.1-2001, removed in POSIX.1-2008-->
@ -1703,6 +1878,7 @@
<arg nr="3"> <arg nr="3">
<not-null/> <not-null/>
</arg> </arg>
<warn severity="style" reason="Obsolescent" alternatives="sprintf"/>
</function> </function>
<!-- off_t lseek(int fildes, off_t offset, int whence); --> <!-- off_t lseek(int fildes, off_t offset, int whence); -->
<function name="lseek"> <function name="lseek">
@ -1777,22 +1953,42 @@
<function name="unsetenv"> <function name="unsetenv">
<noreturn>false</noreturn> <noreturn>false</noreturn>
<arg nr="1"> <arg nr="1">
<not-null/>
<not-uninit/> <not-uninit/>
<not-null/>
</arg> </arg>
</function> </function>
<!-- struct tm *localtime_r(const time_t *timep, struct tm *result); --> <!-- struct tm * localtime(const time_t *tp); -->
<function name="localtime_r"> <function name="localtime,std::localtime">
<noreturn>false</noreturn> <noreturn>false</noreturn>
<leak-ignore/> <leak-ignore/>
<arg nr="1"> <arg nr="1">
<not-null/> <not-null/>
<not-uninit/> <not-uninit/>
</arg> </arg>
<warn severity="portability">Non reentrant function 'localtime' called. For threadsafe applications it is recommended to use the reentrant replacement function 'localtime_r'.</warn>
</function>
<!-- struct tm *localtime_r(const time_t *timep, struct tm *result); -->
<function name="localtime_r">
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1">
<not-uninit/>
<not-null/>
</arg>
<arg nr="2"> <arg nr="2">
<not-null/> <not-null/>
</arg> </arg>
</function> </function>
<!-- struct dirent *readdir(DIR *dirp); -->
<function name="readdir">
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1">
<not-uninit/>
<not-null/>
</arg>
<warn severity="portability">Non reentrant function 'readdir' called. For threadsafe applications it is recommended to use the reentrant replacement function 'readdir_r'.</warn>
</function>
<!-- int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result); --> <!-- int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result); -->
<function name="readdir_r"> <function name="readdir_r">
<noreturn>false</noreturn> <noreturn>false</noreturn>
@ -1852,6 +2048,7 @@
<arg nr="2"> <arg nr="2">
<not-null/> <not-null/>
</arg> </arg>
<warn severity="style" reason="Obsolescent" alternatives="strftime"/>
</function> </function>
<!-- char *ctime_r(const time_t *timep, char *buf); --> <!-- char *ctime_r(const time_t *timep, char *buf); -->
<function name="ctime_r"> <function name="ctime_r">
@ -1864,6 +2061,7 @@
<arg nr="2"> <arg nr="2">
<not-null/> <not-null/>
</arg> </arg>
<warn severity="style" reason="Obsolescent" alternatives="strftime"/>
</function> </function>
<!-- struct tm *gmtime_r(const time_t *timep, struct tm *result); --> <!-- struct tm *gmtime_r(const time_t *timep, struct tm *result); -->
<function name="gmtime_r"> <function name="gmtime_r">
@ -1877,6 +2075,17 @@
<not-null/> <not-null/>
</arg> </arg>
</function> </function>
<!-- struct tm * gmtime(const time_t *tp); -->
<function name="gmtime">
<use-retval/>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1">
<not-null/>
<not-uninit/>
</arg>
<warn severity="portability">Non reentrant function 'gmtime' called. For threadsafe applications it is recommended to use the reentrant replacement function 'gmtime_r'.</warn>
</function>
<!-- http://pubs.opengroup.org/onlinepubs/007908799/xsh/time.h.html --> <!-- http://pubs.opengroup.org/onlinepubs/007908799/xsh/time.h.html -->
<!-- int clock_settime(clockid_t clock_id, const struct timespec *tp); --> <!-- int clock_settime(clockid_t clock_id, const struct timespec *tp); -->
<function name="clock_settime"> <function name="clock_settime">
@ -1926,6 +2135,380 @@
</arg> </arg>
<arg nr="2"/> <arg nr="2"/>
</function> </function>
<!-- char* tmpnam(char *s); -->
<function name="tmpnam,tmpnam_r">
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1">
<not-uninit/>
</arg>
<warn severity="style" alternatives="tmpfile,mkstemp,mkdtemp" reason="Obsolescent"/>
</function>
<!-- void makecontext(ucontext_t *ucp, void (*func)(), int argc, ...); -->
<function name="makecontext">
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1">
<not-null/>
</arg>
<arg nr="2">
<not-uninit/>
<not-null/>
</arg>
<arg nr="3">
<not-uninit/>
</arg>
<arg nr="any"/>
<warn severity="portability">Obsolescent function 'makecontext' called. Applications are recommended to be rewritten to use POSIX threads.</warn>
</function>
<!-- void swapcontext(ucontext_t *restrict oucp, const ucontext_t *restrict ucp); -->
<function name="swapcontext">
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1">
<not-null/>
</arg>
<arg nr="2">
<not-null/>
</arg>
<warn severity="portability">Obsolescent function 'swapcontext' called. Applications are recommended to be rewritten to use POSIX threads.</warn>
</function>
<!-- void getcontext(ucontext_t *ucp); -->
<function name="getcontext">
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1">
<not-null/>
</arg>
<warn severity="portability">Obsolescent function 'getcontext' called. Applications are recommended to be rewritten to use POSIX threads.</warn>
</function>
<!-- useconds_t ualarm(useconds_t useconds, useconds_t interval); -->
<function name="ualarm">
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1">
<not-uninit/>
</arg>
<arg nr="2">
<not-uninit/>
</arg>
<warn severity="style" reason="Obsolescent" alternatives="timer_create,timer_delete,timer_getoverrun,timer_gettime,timer_settime"/>
</function>
<!-- double scalb(double x, double n); -->
<function name="scalb">
<noreturn>false</noreturn>
<use-retval/>
<leak-ignore/>
<arg nr="1">
<not-uninit/>
</arg>
<arg nr="2">
<not-uninit/>
</arg>
<warn severity="style" reason="Obsolescent" alternatives="scalbln,scalblnf,scalbln,scalbn,scalbnf,scalbnl"/>
</function>
<!-- void bcopy(const void *s1, void *s2, size_t n); -->
<function name="bcopy">
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1">
<not-null/>
<not-uninit/>
</arg>
<arg nr="2">
<not-null/>
</arg>
<arg nr="3">
<not-uninit/>
</arg>
<warn severity="style" reason="Obsolescent" alternatives="memcpy,memmove"/>
</function>
<!-- int bcmp(const void *s1, void *s2, size_t n); -->
<function name="bcmp">
<noreturn>false</noreturn>
<leak-ignore/>
<use-retval/>
<arg nr="1">
<not-null/>
<not-uninit/>
</arg>
<arg nr="2">
<not-null/>
<not-uninit/>
</arg>
<arg nr="3">
<not-uninit/>
</arg>
<warn severity="style" reason="Obsolescent" alternatives="memcmp"/>
</function>
<!-- void bzero(void *s, size_t n); -->
<function name="bzero">
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1">
<not-null/>
</arg>
<arg nr="2">
<not-uninit/>
</arg>
<warn severity="style" reason="Obsolescent" alternatives="memset"/>
</function>
<!-- int ftime(struct timeb *tp); -->
<function name="ftime">
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1">
<not-uninit/>
</arg>
<warn severity="style" reason="Obsolescent" alternatives="time,gettimeofday,clock_gettime"/>
</function>
<!-- wchar_t *wcswcs(const wchar_t *ws1, const wchar_t *ws2); -->
<function name="wcswcs">
<noreturn>false</noreturn>
<leak-ignore/>
<use-retval/>
<arg nr="1">
<not-null/>
<not-uninit/>
</arg>
<arg nr="2">
<not-null/>
<not-uninit/>
</arg>
<warn severity="style" reason="Obsolescent" alternatives="wcsstr"/>
</function>
<!-- char *index(const char *s, int c); -->
<function name="index">
<noreturn>false</noreturn>
<leak-ignore/>
<use-retval/>
<arg nr="1">
<not-null/>
<not-uninit/>
</arg>
<arg nr="2">
<not-uninit/>
</arg>
<warn severity="style" reason="Obsolescent" alternatives="strchr"/>
</function>
<!-- char *rindex(const char *s, int c); -->
<function name="rindex">
<noreturn>false</noreturn>
<leak-ignore/>
<use-retval/>
<arg nr="1">
<not-null/>
<not-uninit/>
</arg>
<arg nr="2">
<not-uninit/>
</arg>
<warn severity="style" reason="Obsolescent" alternatives="strrchr"/>
</function>
<!-- sighandler_t bsd_signal(int signum, sighandler_t handler); -->
<function name="bsd_signal">
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1">
<not-uninit/>
</arg>
<arg nr="2">
<not-uninit/>
</arg>
<warn severity="style" reason="Obsolescent" alternatives="sigaction"/>
</function>
<!-- pid_t vfork(void); -->
<function name="vfork">
<noreturn>false</noreturn>
<leak-ignore/>
<warn severity="style" reason="Obsolescent" alternatives="fork"/>
</function>
<!-- int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr); -->
<function name="pthread_attr_setstackaddr">
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1">
<not-uninit/>
<not-null/>
</arg>
<arg nr="2">
<not-uninit/>
<not-null/>
</arg>
<warn severity="style" reason="Obsolescent" alternatives="pthread_attr_setstack"/>
</function>
<!-- int pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr); -->
<function name="pthread_attr_getstackaddr">
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1">
<not-uninit/>
<not-null/>
</arg>
<arg nr="2">
<not-null/>
</arg>
<warn severity="style" reason="Obsolescent" alternatives="pthread_attr_getstack"/>
</function>
<!-- char *tempnam(const char *dir, const char *pfx); -->
<function name="tempnam">
<noreturn>false</noreturn>
<leak-ignore/>
<use-retval/>
<arg nr="1">
<not-uninit/>
<not-null/>
</arg>
<arg nr="2">
<not-uninit/>
<not-null/>
</arg>
<warn severity="portability">Non reentrant function 'tempnam' called. For threadsafe applications it is recommended to use the reentrant replacement function 'tempnam_r'.</warn>
</function>
<!-- char *crypt(const char *key, const char *salt); -->
<function name="crypt">
<noreturn>false</noreturn>
<leak-ignore/>
<use-retval/>
<arg nr="1">
<not-uninit/>
<not-null/>
</arg>
<arg nr="2">
<not-uninit/>
<not-null/>
</arg>
<warn severity="portability">Non reentrant function 'crypt' called. For threadsafe applications it is recommended to use the reentrant replacement function 'crypt_r'.</warn>
</function>
<!-- char *ttyname(int fd); -->
<function name="ttyname">
<noreturn>false</noreturn>
<leak-ignore/>
<use-retval/>
<arg nr="1">
<not-uninit/>
</arg>
<warn severity="portability">Non reentrant function 'ttyname' called. For threadsafe applications it is recommended to use the reentrant replacement function 'ttyname_r'.</warn>
</function>
<!-- struct spwd *getspnam(const char *name); -->
<function name="getspnam">
<noreturn>false</noreturn>
<leak-ignore/>
<use-retval/>
<arg nr="1">
<not-uninit/>
<not-null/>
</arg>
<warn severity="portability">Non reentrant function 'getspnam' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getspnam_r'.</warn>
</function>
<!-- struct spwd *getspent(void); -->
<function name="getspent">
<noreturn>false</noreturn>
<leak-ignore/>
<use-retval/>
<warn severity="portability">Non reentrant function 'getspent' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getspent_r'.</warn>
</function>
<!-- struct spwd *fgetspent(FILE *fp); -->
<function name="fgetspent">
<noreturn>false</noreturn>
<leak-ignore/>
<use-retval/>
<arg nr="1">
<not-uninit/>
<not-null/>
</arg>
<warn severity="portability">Non reentrant function 'fgetspent' called. For threadsafe applications it is recommended to use the reentrant replacement function 'fgetspent_r'.</warn>
</function>
<!-- struct spwd *sgetspent(const char *s); -->
<function name="sgetspent">
<noreturn>false</noreturn>
<leak-ignore/>
<use-retval/>
<arg nr="1">
<not-uninit/>
<not-null/>
</arg>
<warn severity="portability">Non reentrant function 'sgetspent' called. For threadsafe applications it is recommended to use the reentrant replacement function 'sgetspent_r'.</warn>
</function>
<!-- struct passwd *fgetpwent(FILE *stream); -->
<function name="fgetpwent">
<noreturn>false</noreturn>
<leak-ignore/>
<use-retval/>
<arg nr="1">
<not-uninit/>
<not-null/>
</arg>
<warn severity="portability">Non reentrant function 'fgetpwent' called. For threadsafe applications it is recommended to use the reentrant replacement function 'fgetpwent_r'.</warn>
</function>
<!-- struct group *getgrent(void); -->
<function name="getgrent">
<noreturn>false</noreturn>
<leak-ignore/>
<use-retval/>
<warn severity="portability">Non reentrant function 'getgrent' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getgrent_r'.</warn>
</function>
<!-- struct group *fgetgrent(FILE *stream); -->
<function name="fgetgrent">
<noreturn>false</noreturn>
<leak-ignore/>
<use-retval/>
<arg nr="1">
<not-uninit/>
<not-null/>
</arg>
<warn severity="portability">Non reentrant function 'fgetgrent' called. For threadsafe applications it is recommended to use the reentrant replacement function 'fgetgrent_r'.</warn>
</function>
<!-- int getnetgrent(char **host, char **user, char **domain); -->
<function name="getnetgrent">
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1">
<not-null/>
</arg>
<arg nr="2">
<not-null/>
</arg>
<arg nr="3">
<not-null/>
</arg>
<warn severity="portability">Non reentrant function 'getnetgrent' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getnetgrent_r'.</warn>
</function>
<!-- struct group *getgrnam(const char *name); -->
<function name="getgrnam">
<noreturn>false</noreturn>
<leak-ignore/>
<use-retval/>
<arg nr="1">
<not-uninit/>
<not-null/>
</arg>
<warn severity="portability">Non reentrant function 'getgrnam' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getgrnam_r'.</warn>
</function>
<!-- struct group *getgrgid(gid_t gid); -->
<function name="getgrgid">
<noreturn>false</noreturn>
<leak-ignore/>
<use-retval/>
<arg nr="1">
<not-uninit/>
</arg>
<warn severity="portability">Non reentrant function 'getgrgid' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getgrgid_r'.</warn>
</function>
<!-- char *getlogin(void); -->
<function name="getlogin">
<noreturn>false</noreturn>
<leak-ignore/>
<use-retval/>
<warn severity="portability">Non reentrant function 'getlogin' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getlogin_r'.</warn>
</function>
<!-- char *ctermid(char *s); -->
<function name="ctermid">
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1"/>
<warn severity="portability">Non reentrant function 'ctermid' called. For threadsafe applications it is recommended to use the reentrant replacement function 'ctermid_r'.</warn>
</function>
<memory> <memory>
<alloc init="true">strdup</alloc> <alloc init="true">strdup</alloc>
<alloc init="true">strndup</alloc> <alloc init="true">strndup</alloc>
@ -1956,6 +2539,7 @@
<alloc init="true">popen</alloc> <alloc init="true">popen</alloc>
<dealloc>pclose</dealloc> <dealloc>pclose</dealloc>
</resource> </resource>
<!-- This type definitions refer to http://pubs.opengroup.org/onlinepubs/009695399/basedefs/sys/types.h.html-->
<podtype name="in_port_t" sign="u" size="2"/> <podtype name="in_port_t" sign="u" size="2"/>
<podtype name="in_addr_t" sign="u" size="4"/> <podtype name="in_addr_t" sign="u" size="4"/>
<podtype name="socklen_t" sign="u" size="4"/> <podtype name="socklen_t" sign="u" size="4"/>

View File

@ -92,6 +92,7 @@
<not-null/> <not-null/>
<not-uninit/> <not-uninit/>
</arg> </arg>
<warn severity="style" cstd="c99" alternatives="strftime" reason="Obsolete"/>
</function> </function>
<!-- void assert(int expression) --> <!-- void assert(int expression) -->
<function name="assert"> <function name="assert">
@ -1435,12 +1436,14 @@
</arg> </arg>
</function> </function>
<!-- char *gets(char *buffer); --> <!-- char *gets(char *buffer); -->
<function name="gets"> <function name="gets,std::gets">
<noreturn>false</noreturn> <noreturn>false</noreturn>
<leak-ignore/> <leak-ignore/>
<arg nr="1"> <arg nr="1">
<not-null/> <not-null/>
</arg> </arg>
<warn severity="warning">Obsolete function 'gets' called. It is recommended to use 'fgets' instead.
The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun if the input data exceeds the size of the buffer. It is recommended to use the function 'fgets' instead.</warn>
</function> </function>
<!-- struct tm * gmtime(const time_t *tp); --> <!-- struct tm * gmtime(const time_t *tp); -->
<function name="gmtime,std::gmtime"> <function name="gmtime,std::gmtime">

71
lib/checkfunctions.cpp Normal file
View File

@ -0,0 +1,71 @@
/*
* Cppcheck - A tool for static C/C++ code analysis
* Copyright (C) 2007-2015 Cppcheck team.
*
* 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/>.
*/
//---------------------------------------------------------------------------
// Check functions
//---------------------------------------------------------------------------
#include "checkfunctions.h"
#include "symboldatabase.h"
//---------------------------------------------------------------------------
// Register this check class (by creating a static instance of it)
namespace {
CheckFunctions instance;
}
void CheckFunctions::check()
{
const bool checkAlloca = (_settings->standards.c >= Standards::C99 && _tokenizer->isC()) || _settings->standards.cpp >= Standards::CPP11;
const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
for (unsigned int i = 0; i < symbolDatabase->functionScopes.size(); i++) {
const Scope* scope = symbolDatabase->functionScopes[i];
for (const Token* tok = scope->classStart; tok != scope->classEnd; tok = tok->next()) {
if (tok->isName() && tok->varId() == 0 && tok->strAt(1) == "(") {
// alloca() is special as it depends on the code being C or C++, so it is not in Library
if (checkAlloca && Token::Match(tok, "alloca (") && (!tok->function() || tok->function()->nestedIn->type == Scope::eGlobal)) {
if (_tokenizer->isC())
reportError(tok, Severity::warning, "allocaCalled",
"Obsolete function 'alloca' called. In C99 and later it is recommended to use a variable length array instead.\n"
"The obsolete function 'alloca' is called. In C99 and later it is recommended to use a variable length array or "
"a dynamically allocated array instead. The function 'alloca' is dangerous for many reasons "
"(http://stackoverflow.com/questions/1018853/why-is-alloca-not-considered-good-practice and http://linux.die.net/man/3/alloca).");
else
reportError(tok, Severity::warning, "allocaCalled",
"Obsolete function 'alloca' called. In C++11 and later it is recommended to use std::array<> instead.\n"
"The obsolete function 'alloca' is called. In C++11 and later it is recommended to use std::array<> or "
"a dynamically allocated array instead. The function 'alloca' is dangerous for many reasons "
"(http://stackoverflow.com/questions/1018853/why-is-alloca-not-considered-good-practice and http://linux.die.net/man/3/alloca).");
} else {
if (tok->function() && tok->function()->hasBody())
continue;
const Library::WarnInfo* wi = _settings->library.getWarnInfo(tok);
if (wi) {
if (_settings->isEnabled(Severity::toString(wi->severity)) && _settings->standards.c >= wi->standards.c && _settings->standards.cpp >= wi->standards.cpp) {
reportError(tok, wi->severity, tok->str() + "Called", wi->message);
}
}
}
}
}
}
}

View File

@ -16,55 +16,60 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#ifndef checknonreentrantfunctionsH #ifndef checkfunctionsH
#define checknonreentrantfunctionsH #define checkfunctionsH
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include "config.h" #include "config.h"
#include "check.h" #include "check.h"
#include <string> #include <string>
#include <map>
/// @addtogroup Checks /// @addtogroup Checks
/// @{ /// @{
/** /**
* @brief Using non reentrant functions that can be replaced by their reentrant versions * @brief Check for functions which should not be used
*/ */
class CPPCHECKLIB CheckNonReentrantFunctions : public Check { class CPPCHECKLIB CheckFunctions : public Check {
public: public:
/** This constructor is used when registering the CheckNonReentrantFunctions */ /** This constructor is used when registering the CheckFunctions */
CheckNonReentrantFunctions() : Check(myName()) { CheckFunctions() : Check(myName()) {
} }
/** This constructor is used when running checks. */ /** This constructor is used when running checks. */
CheckNonReentrantFunctions(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) CheckFunctions(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
: Check(myName(), tokenizer, settings, errorLogger) { : Check(myName(), tokenizer, settings, errorLogger) {
} }
void runSimplifiedChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) { void runSimplifiedChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) {
CheckNonReentrantFunctions checkNonReentrantFunctions(tokenizer, settings, errorLogger); CheckFunctions checkFunctions(tokenizer, settings, errorLogger);
checkNonReentrantFunctions.nonReentrantFunctions(); checkFunctions.check();
} }
/** Check for non reentrant functions */ /** Check for functions that should not be used */
void nonReentrantFunctions(); void check();
private: private:
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const {
CheckFunctions c(0, settings, errorLogger);
static std::string generateErrorMessage(const std::string& function); for (std::map<std::string, Library::WarnInfo>::const_iterator i = settings->library.functionwarn.cbegin(); i != settings->library.functionwarn.cend(); ++i) {
c.reportError(0, Severity::style, i->first+"Called", i->second.message);
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const; }
static std::string myName() {
return "Non reentrant functions";
} }
std::string classInfo() const; static std::string myName() {
return "Check function usage";
}
std::string classInfo() const {
return "Warn if a function is called whose usage is discouraged\n";
}
}; };
/// @} /// @}
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#endif // checknonreentrantfunctionsH #endif // checkfunctionsH

View File

@ -1,105 +0,0 @@
/*
* Cppcheck - A tool for static C/C++ code analysis
* Copyright (C) 2007-2015 Cppcheck team.
*
* 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/>.
*/
//---------------------------------------------------------------------------
// Find non reentrant functions
//---------------------------------------------------------------------------
#include "checknonreentrantfunctions.h"
#include "symboldatabase.h"
//---------------------------------------------------------------------------
// Register this check class (by creating a static instance of it)
namespace {
CheckNonReentrantFunctions instance;
}
namespace {
const std::set<std::string> _nonReentrantFunctions = make_container< std::set<std::string> > ()
<< "localtime" << "gmtime" << "strtok" << "gethostbyname" << "gethostbyaddr" << "getservbyname"
<< "getservbyport" << "crypt" << "ttyname" << "gethostbyname2"
<< "getprotobyname" << "getnetbyname" << "getnetbyaddr" << "getrpcbyname" << "getrpcbynumber" << "getrpcent"
<< "ctermid" << "readdir" << "getlogin" << "getpwent" << "getpwnam" << "getpwuid" << "getspent"
<< "fgetspent" << "getspnam" << "getgrnam" << "getgrgid" << "getnetgrent" << "tempnam" << "fgetpwent"
<< "fgetgrent" << "ecvt" << "gcvt" << "getservent" << "gethostent" << "getgrent" << "fcvt" ;
}
std::string CheckNonReentrantFunctions::generateErrorMessage(const std::string& function)
{
return std::string("Non reentrant function '") + function + "' called. " +
"For threadsafe applications it is recommended to use the reentrant replacement function '" + function + "_r'.";
}
void CheckNonReentrantFunctions::nonReentrantFunctions()
{
if (!_settings->standards.posix || !_settings->isEnabled("portability"))
return;
const SymbolDatabase * const symbolDatabase = _tokenizer->getSymbolDatabase();
const std::size_t functions = symbolDatabase->functionScopes.size();
for (std::size_t i = 0; i < functions; ++i) {
const Scope * scope = symbolDatabase->functionScopes[i];
for (const Token *tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
// Look for function invocations
if (tok->varId() != 0 || !tok->isName() || tok->strAt(1) != "(")
continue;
// Check for non-reentrant function name
std::set<std::string>::const_iterator it = _nonReentrantFunctions.find(tok->str());
if (it == _nonReentrantFunctions.end())
continue;
const Token *prev = tok->previous();
if (prev) {
// Ignore function definitions, class members or class definitions
if (prev->str() == ".")
continue;
// Check for "std" or global namespace, ignore other namespaces
if (_tokenizer->isCPP() && prev->str() == "::" && prev->previous() && prev->previous()->str() != "std" && prev->previous()->isName())
continue;
}
// Only affecting multi threaded code, therefore this is "portability"
reportError(tok, Severity::portability, "nonreentrantFunctions" + *it, generateErrorMessage(*it));
}
}
}
//---------------------------------------------------------------------------
void CheckNonReentrantFunctions::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const
{
CheckNonReentrantFunctions c(0, settings, errorLogger);
std::set<std::string>::const_iterator it(_nonReentrantFunctions.begin()), itend(_nonReentrantFunctions.end());
for (; it!=itend; ++it) {
c.reportError(0, Severity::portability, "nonreentrantFunctions"+*it, generateErrorMessage(*it));
}
}
std::string CheckNonReentrantFunctions::classInfo() const
{
std::string info = "Warn if any of these non reentrant functions are used:\n";
std::set<std::string>::const_iterator it(_nonReentrantFunctions.begin()), itend(_nonReentrantFunctions.end());
for (; it!=itend; ++it) {
info += "- " + *it + "\n";
}
return info;
}

View File

@ -1,76 +0,0 @@
/*
* Cppcheck - A tool for static C/C++ code analysis
* Copyright (C) 2007-2015 Cppcheck team.
*
* 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/>.
*/
//---------------------------------------------------------------------------
// Obsolete functions
//---------------------------------------------------------------------------
#include "checkobsolescentfunctions.h"
#include "symboldatabase.h"
//---------------------------------------------------------------------------
std::map<std::string, std::string> CheckObsoleteFunctions::_obsoleteStandardFunctions;
std::map<std::string, std::string> CheckObsoleteFunctions::_obsoletePosixFunctions;
std::map<std::string, std::string> CheckObsoleteFunctions::_obsoleteC99Functions;
// Register this check class (by creating a static instance of it)
namespace {
CheckObsoleteFunctions instance;
}
void CheckObsoleteFunctions::obsoleteFunctions()
{
if (!_settings->isEnabled("style"))
return;
const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
const bool cStandard = _settings->standards.c >= Standards::C99 ;
for (unsigned int i = 0; i < symbolDatabase->functionScopes.size(); i++) {
const Scope* scope = symbolDatabase->functionScopes[i];
for (const Token* tok = scope->classStart; tok != scope->classEnd; tok = tok->next()) {
if (tok->isName() && tok->varId()==0 && (!tok->function() || !tok->function()->hasBody()) && tok->strAt(1) == "(" &&
tok->strAt(-1) != "." && (!Token::Match(tok->tokAt(-2), "%name% ::") || Token::simpleMatch(tok->tokAt(-2), "std ::"))) {
std::map<std::string,std::string>::const_iterator it = _obsoleteStandardFunctions.find(tok->str());
if (it != _obsoleteStandardFunctions.end()) {
// If checking an old code base it might be uninteresting to update obsolete functions.
reportError(tok, Severity::style, "obsoleteFunctions"+it->first, it->second);
} else {
if (_settings->standards.posix) {
it = _obsoletePosixFunctions.find(tok->str());
if (it != _obsoletePosixFunctions.end()) {
// If checking an old code base it might be uninteresting to update obsolete functions.
reportError(tok, Severity::style, "obsoleteFunctions"+it->first, it->second);
}
}
if (cStandard) {
// alloca : this function is obsolete in C but not in C++ (#4382)
it = _obsoleteC99Functions.find(tok->str());
if (it != _obsoleteC99Functions.end() && !(tok->str() == "alloca" && _tokenizer->isCPP())) {
reportError(tok, Severity::style, "obsoleteFunctions"+it->first, it->second);
}
}
}
}
}
}
}
//---------------------------------------------------------------------------

View File

@ -1,152 +0,0 @@
/*
* Cppcheck - A tool for static C/C++ code analysis
* Copyright (C) 2007-2015 Cppcheck team.
*
* 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/>.
*/
//---------------------------------------------------------------------------
#ifndef checkobsoletefunctionsH
#define checkobsoletefunctionsH
//---------------------------------------------------------------------------
#include "config.h"
#include "check.h"
#include <string>
#include <map>
/// @addtogroup Checks
/// @{
/**
* @brief Using obsolete functions that are always insecure to use.
*/
class CPPCHECKLIB CheckObsoleteFunctions : public Check {
public:
/** This constructor is used when registering the CheckObsoleteFunctions */
CheckObsoleteFunctions() : Check(myName()) {
initObsoleteFunctions();
}
/** This constructor is used when running checks. */
CheckObsoleteFunctions(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
: Check(myName(), tokenizer, settings, errorLogger) {
}
void runSimplifiedChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) {
CheckObsoleteFunctions checkObsoleteFunctions(tokenizer, settings, errorLogger);
checkObsoleteFunctions.obsoleteFunctions();
}
/** Check for obsolete functions */
void obsoleteFunctions();
private:
/* function name / error message */
static std::map<std::string, std::string> _obsoleteStandardFunctions;
static std::map<std::string, std::string> _obsoletePosixFunctions;
static std::map<std::string, std::string> _obsoleteC99Functions;
/** init obsolete functions list ' */
static void initObsoleteFunctions() {
// Obsolete posix functions, which messages suggest only one alternative and doesn't contain additional information.
const struct {
const char* bad;
const char* good;
} posix_stdmsgs[] = {
{"bsd_signal", "sigaction"},
{"gethostbyaddr", "getnameinfo"},
{"gethostbyname", "getaddrinfo"},
{"bcmp", "memcmp"},
{"bzero", "memset"},
{"ecvt", "sprintf"},
{"fcvt", "sprintf"},
{"gcvt", "sprintf"},
{"getwd", "getcwd"},
{"index", "strchr"}, // See #2334 (using the Qt Model/View function 'index')
{"rindex", "strrchr"},
{"pthread_attr_getstackaddr", "pthread_attr_getstack"},
{"pthread_attr_setstackaddr", "pthread_attr_setstack"},
{"vfork", "fork"},
{"wcswcs", "wcsstr"},
{"rand_r", "rand"},
{"utime", "utimensat"},
{"asctime_r", "strftime"},
{"ctime_r", "strftime"}
};
for (std::size_t i = 0; i < (sizeof(posix_stdmsgs) / sizeof(*posix_stdmsgs)); ++i) {
_obsoletePosixFunctions[posix_stdmsgs[i].bad] = "Obsolete function '" + std::string(posix_stdmsgs[i].bad) + "' called. It is recommended to use the function '" + posix_stdmsgs[i].good + "' instead.";
}
_obsoletePosixFunctions["usleep"] = "Obsolete function 'usleep' called. It is recommended to use the 'nanosleep' or 'setitimer' function instead.\n"
"The obsolete function 'usleep' is called. POSIX.1-2001 declares usleep() function obsolete and POSIX.1-2008 removes it. It is recommended that new applications use the 'nanosleep' or 'setitimer' function.";
_obsoletePosixFunctions["bcopy"] = "Obsolete function 'bcopy' called. It is recommended to use the 'memmove' or 'memcpy' function instead.";
_obsoletePosixFunctions["ftime"] = "Obsolete function 'ftime' called. It is recommended to use time(), gettimeofday() or clock_gettime() instead.";
_obsoletePosixFunctions["getcontext"] = "Obsolete function 'getcontext' called. Due to portability issues, applications are recommended to be rewritten to use POSIX threads.";
_obsoletePosixFunctions["makecontext"] = "Obsolete function 'makecontext' called. Due to portability issues, applications are recommended to be rewritten to use POSIX threads.";
_obsoletePosixFunctions["swapcontext"] = "Obsolete function 'swapcontext' called. Due to portability issues, applications are recommended to be rewritten to use POSIX threads.";
_obsoletePosixFunctions["scalbln"] = "Obsolete function 'scalb' called. It is recommended to use 'scalbln', 'scalblnf' or 'scalblnl' instead.";
_obsoletePosixFunctions["ualarm"] = "Obsolete function 'ualarm' called. It is recommended to use 'timer_create', 'timer_delete', 'timer_getoverrun', 'timer_gettime' or 'timer_settime' instead.";
_obsoletePosixFunctions["tmpnam"] = "Obsolete function 'tmpnam' called. It is recommended to use 'tmpfile', 'mkstemp' or 'mkdtemp' instead.";
_obsoletePosixFunctions["tmpnam_r"] = "Obsolete function 'tmpnam_r' called. It is recommended to use 'tmpfile', 'mkstemp' or 'mkdtemp' instead.";
_obsoleteStandardFunctions["gets"] = "Obsolete function 'gets' called. It is recommended to use the function 'fgets' instead.\n"
"The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun if the input data exceeds the size of the buffer. It is recommended to use the function 'fgets' instead.";
_obsoleteC99Functions["alloca"] = "Obsolete function 'alloca' called. In C99 and later it is recommended to use a variable length array instead.\n"
"The obsolete function 'alloca' is called. In C99 and later it is recommended to use a variable length array or a dynamically allocated array instead. The function 'alloca' is dangerous for many reasons (http://stackoverflow.com/questions/1018853/why-is-alloca-not-considered-good-practice and http://linux.die.net/man/3/alloca).";
_obsoleteC99Functions["asctime"] = "Obsolete function 'asctime' called. It is recommended to use the function 'strftime' instead.";
// ctime is obsolete - it's not threadsafe. but there is no good replacement.
//_obsoleteC99Functions["ctime"] = "Obsolete function 'ctime' called. It is recommended to use the function 'strftime' instead.";
}
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const {
CheckObsoleteFunctions c(0, settings, errorLogger);
for (std::map<std::string, std::string>::const_iterator it = _obsoleteStandardFunctions.begin(); it != _obsoleteStandardFunctions.end(); ++it)
c.reportError(0, Severity::style, "obsoleteFunctions" + it->first, it->second);
for (std::map<std::string, std::string>::const_iterator it = _obsoleteC99Functions.begin(); it != _obsoleteC99Functions.end(); ++it)
c.reportError(0, Severity::style, "obsoleteFunctions" + it->first, it->second);
for (std::map<std::string, std::string>::const_iterator it = _obsoletePosixFunctions.begin(); it != _obsoletePosixFunctions.end(); ++it)
c.reportError(0, Severity::style, "obsoleteFunctions" + it->first, it->second);
}
static std::string myName() {
return "Obsolete functions";
}
std::string classInfo() const {
std::string info = "Warn if any of these obsolete functions are used:\n";
for (std::map<std::string, std::string>::const_iterator it = _obsoleteStandardFunctions.begin(); it != _obsoleteStandardFunctions.end(); ++it)
info += "- " + it->first + "\n";
for (std::map<std::string, std::string>::const_iterator it = _obsoleteC99Functions.begin(); it != _obsoleteC99Functions.end(); ++it)
info += "- " + it->first + "\n";
for (std::map<std::string, std::string>::const_iterator it = _obsoletePosixFunctions.begin(); it != _obsoletePosixFunctions.end(); ++it)
info += "- " + it->first + "\n";
return info;
}
};
/// @}
//---------------------------------------------------------------------------
#endif // checkobsoletefunctionsH

View File

@ -55,15 +55,14 @@
<ClCompile Include="checkbufferoverrun.cpp" /> <ClCompile Include="checkbufferoverrun.cpp" />
<ClCompile Include="checkclass.cpp" /> <ClCompile Include="checkclass.cpp" />
<ClCompile Include="checkcondition.cpp" /> <ClCompile Include="checkcondition.cpp" />
<ClCompile Include="checkfunctions.cpp" />
<ClCompile Include="checkstring.cpp" /> <ClCompile Include="checkstring.cpp" />
<ClCompile Include="checkexceptionsafety.cpp" /> <ClCompile Include="checkexceptionsafety.cpp" />
<ClCompile Include="checkinternal.cpp" /> <ClCompile Include="checkinternal.cpp" />
<ClCompile Include="checkio.cpp" /> <ClCompile Include="checkio.cpp" />
<ClCompile Include="checkleakautovar.cpp" /> <ClCompile Include="checkleakautovar.cpp" />
<ClCompile Include="checkmemoryleak.cpp" /> <ClCompile Include="checkmemoryleak.cpp" />
<ClCompile Include="checknonreentrantfunctions.cpp" />
<ClCompile Include="checknullpointer.cpp" /> <ClCompile Include="checknullpointer.cpp" />
<ClCompile Include="checkobsolescentfunctions.cpp" />
<ClCompile Include="checkother.cpp" /> <ClCompile Include="checkother.cpp" />
<ClCompile Include="checkpostfixoperator.cpp" /> <ClCompile Include="checkpostfixoperator.cpp" />
<ClCompile Include="checksizeof.cpp" /> <ClCompile Include="checksizeof.cpp" />
@ -101,15 +100,14 @@
<ClInclude Include="checkbufferoverrun.h" /> <ClInclude Include="checkbufferoverrun.h" />
<ClInclude Include="checkclass.h" /> <ClInclude Include="checkclass.h" />
<ClInclude Include="checkcondition.h" /> <ClInclude Include="checkcondition.h" />
<ClInclude Include="checkfunctions.h" />
<ClInclude Include="checkstring.h" /> <ClInclude Include="checkstring.h" />
<ClInclude Include="checkexceptionsafety.h" /> <ClInclude Include="checkexceptionsafety.h" />
<ClInclude Include="checkinternal.h" /> <ClInclude Include="checkinternal.h" />
<ClInclude Include="checkio.h" /> <ClInclude Include="checkio.h" />
<ClInclude Include="checkleakautovar.h" /> <ClInclude Include="checkleakautovar.h" />
<ClInclude Include="checkmemoryleak.h" /> <ClInclude Include="checkmemoryleak.h" />
<ClInclude Include="checknonreentrantfunctions.h" />
<ClInclude Include="checknullpointer.h" /> <ClInclude Include="checknullpointer.h" />
<ClInclude Include="checkobsolescentfunctions.h" />
<ClInclude Include="checkother.h" /> <ClInclude Include="checkother.h" />
<ClInclude Include="checkpostfixoperator.h" /> <ClInclude Include="checkpostfixoperator.h" />
<ClInclude Include="checksizeof.h" /> <ClInclude Include="checksizeof.h" />

View File

@ -32,15 +32,9 @@
<ClCompile Include="checkmemoryleak.cpp"> <ClCompile Include="checkmemoryleak.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="checknonreentrantfunctions.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="checknullpointer.cpp"> <ClCompile Include="checknullpointer.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="checkobsolescentfunctions.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="checkother.cpp"> <ClCompile Include="checkother.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
@ -143,6 +137,9 @@
<ClCompile Include="astutils.cpp"> <ClCompile Include="astutils.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="checkfunctions.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="checkbufferoverrun.h"> <ClInclude Include="checkbufferoverrun.h">
@ -157,15 +154,9 @@
<ClInclude Include="checkmemoryleak.h"> <ClInclude Include="checkmemoryleak.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="checknonreentrantfunctions.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="checknullpointer.h"> <ClInclude Include="checknullpointer.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="checkobsolescentfunctions.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="checkother.h"> <ClInclude Include="checkother.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
@ -286,6 +277,9 @@
<ClInclude Include="utils.h"> <ClInclude Include="utils.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="checkfunctions.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ResourceCompile Include="version.rc" /> <ResourceCompile Include="version.rc" />

View File

@ -621,6 +621,46 @@ Library::Error Library::loadFunction(const tinyxml2::XMLElement * const node, co
const tinyxml2::XMLAttribute* scan = functionnode->FindAttribute("scan"); const tinyxml2::XMLAttribute* scan = functionnode->FindAttribute("scan");
const tinyxml2::XMLAttribute* secure = functionnode->FindAttribute("secure"); const tinyxml2::XMLAttribute* secure = functionnode->FindAttribute("secure");
_formatstr[name] = std::make_pair(scan && scan->BoolValue(), secure && secure->BoolValue()); _formatstr[name] = std::make_pair(scan && scan->BoolValue(), secure && secure->BoolValue());
} else if (functionnodename == "warn") {
WarnInfo wi;
const char* const severity = functionnode->Attribute("severity");
if (severity == nullptr)
return Error(MISSING_ATTRIBUTE, "severity");
wi.severity = Severity::fromString(severity);
const char* const cstd = functionnode->Attribute("cstd");
if (cstd) {
if (!wi.standards.setC(cstd))
return Error(BAD_ATTRIBUTE_VALUE, cstd);
} else
wi.standards.c = Standards::C89;
const char* const cppstd = functionnode->Attribute("cppstd");
if (cppstd) {
if (!wi.standards.setCPP(cppstd))
return Error(BAD_ATTRIBUTE_VALUE, cppstd);
} else
wi.standards.cpp = Standards::CPP03;
const char* const reason = functionnode->Attribute("reason");
const char* const alternatives = functionnode->Attribute("alternatives");
if (reason && alternatives) {
// Construct message
wi.message = std::string(reason) + " function '" + name + "' called. It is recommended to use ";
std::vector<std::string> alt = getnames(alternatives);
for (std::size_t i = 0; i < alt.size(); ++i) {
wi.message += "'" + alt[i] + "'";
if (i == alt.size() - 1)
wi.message += " instead.";
else if (i == alt.size() - 2)
wi.message += " or ";
else
wi.message += ", ";
}
} else
wi.message = functionnode->GetText();
functionwarn[name] = wi;
} else } else
unknown_elements.insert(functionnodename); unknown_elements.insert(functionnodename);
} }
@ -852,6 +892,16 @@ bool Library::isNotLibraryFunction(const Token *ftok) const
return args != callargs; return args != callargs;
} }
const Library::WarnInfo* Library::getWarnInfo(const Token* ftok) const
{
if (isNotLibraryFunction(ftok))
return nullptr;
std::map<std::string, WarnInfo>::const_iterator i = functionwarn.find(functionName(ftok));
if (i == functionwarn.cend())
return nullptr;
return &i->second;
}
bool Library::isUseRetVal(const Token* ftok) const bool Library::isUseRetVal(const Token* ftok) const
{ {
return (!isNotLibraryFunction(ftok) && return (!isNotLibraryFunction(ftok) &&

View File

@ -24,6 +24,8 @@
#include "config.h" #include "config.h"
#include "mathlib.h" #include "mathlib.h"
#include "token.h" #include "token.h"
#include "standards.h"
#include "errorlogger.h"
#include <map> #include <map>
#include <set> #include <set>
@ -120,6 +122,15 @@ public:
std::set<std::string> functionconst; std::set<std::string> functionconst;
std::set<std::string> functionpure; std::set<std::string> functionpure;
struct WarnInfo {
std::string message;
Standards standards;
Severity::SeverityType severity;
};
std::map<std::string, WarnInfo> functionwarn;
const WarnInfo* getWarnInfo(const Token* ftok) const;
// returns true if ftok is not a library function // returns true if ftok is not a library function
bool isNotLibraryFunction(const Token *ftok) const; bool isNotLibraryFunction(const Token *ftok) const;

View File

@ -41,6 +41,33 @@ struct Standards {
/** This constructor clear all the variables **/ /** This constructor clear all the variables **/
Standards() : c(C11), cpp(CPP11), posix(false) {} Standards() : c(C11), cpp(CPP11), posix(false) {}
bool setC(const std::string& str) {
if (str == "c89" || str == "C89") {
c = C89;
return true;
}
if (str == "c99" || str == "C99") {
c = C99;
return true;
}
if (str == "c11" || str == "C11") {
c = C11;
return true;
}
return false;
}
bool setCPP(const std::string& str) {
if (str == "c++03" || str == "C++03") {
cpp = CPP03;
return true;
}
if (str == "c++11" || str == "C++11") {
cpp = CPP11;
return true;
}
return false;
}
}; };
/// @} /// @}

View File

@ -17,13 +17,13 @@
*/ */
#include "tokenize.h" #include "tokenize.h"
#include "checkobsolescentfunctions.h" #include "checkfunctions.h"
#include "testsuite.h" #include "testsuite.h"
class TestObsoleteFunctions : public TestFixture { class TestFunctions : public TestFixture {
public: public:
TestObsoleteFunctions() : TestFixture("TestObsoleteFunctions") { TestFunctions() : TestFixture("TestFunctions") {
} }
private: private:
@ -31,8 +31,13 @@ private:
void run() { void run() {
settings.addEnabled("style"); settings.addEnabled("style");
settings.addEnabled("warning");
settings.addEnabled("portability");
settings.standards.posix = true; settings.standards.posix = true;
settings.standards.c = Standards::C11; settings.standards.c = Standards::C11;
settings.standards.cpp = Standards::CPP11;
LOAD_LIB_2(settings.library, "std.cfg");
LOAD_LIB_2(settings.library, "posix.cfg");
TEST_CASE(testbsd_signal); TEST_CASE(testbsd_signal);
TEST_CASE(testgethostbyname); TEST_CASE(testgethostbyname);
@ -65,8 +70,9 @@ private:
// function with body // function with body
TEST_CASE(test_function_with_body); TEST_CASE(test_function_with_body);
// null pointer dereference in obsoleteFunctions // Non-reentrant functions
TEST_CASE(ticket3238); TEST_CASE(test_crypt);
TEST_CASE(test_namespace_handling);
} }
void check(const char code[], const char filename[]="test.cpp") { void check(const char code[], const char filename[]="test.cpp") {
@ -79,9 +85,9 @@ private:
tokenizer.tokenize(istr, filename); tokenizer.tokenize(istr, filename);
tokenizer.simplifyTokenList2(); tokenizer.simplifyTokenList2();
// Check for obsolete functions.. // Check...
CheckObsoleteFunctions checkObsoleteFunctions(&tokenizer, &settings, this); CheckFunctions checkFunctions(&tokenizer, &settings, this);
checkObsoleteFunctions.obsoleteFunctions(); checkFunctions.check();
} }
void testbsd_signal() { void testbsd_signal() {
@ -89,7 +95,7 @@ private:
"{\n" "{\n"
" bsd_signal(SIGABRT, SIG_IGN);\n" " bsd_signal(SIGABRT, SIG_IGN);\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:3]: (style) Obsolete function 'bsd_signal' called. It is recommended to use the function 'sigaction' instead.\n", errout.str()); ASSERT_EQUALS("[test.cpp:3]: (style) Obsolescent function 'bsd_signal' called. It is recommended to use 'sigaction' instead.\n", errout.str());
check("int f()\n" check("int f()\n"
"{\n" "{\n"
@ -108,7 +114,7 @@ private:
" exit(1);\n" " exit(1);\n"
" }\n" " }\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:4]: (style) Obsolete function 'gethostbyname' called. It is recommended to use the function 'getaddrinfo' instead.\n", errout.str()); ASSERT_EQUALS("[test.cpp:4]: (style) Obsolescent function 'gethostbyname' called. It is recommended to use 'getaddrinfo' instead.\n", errout.str());
} }
void testgethostbyaddr() { void testgethostbyaddr() {
@ -120,7 +126,7 @@ private:
" exit(1);\n" " exit(1);\n"
" }\n" " }\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:5]: (style) Obsolete function 'gethostbyaddr' called. It is recommended to use the function 'getnameinfo' instead.\n", errout.str()); ASSERT_EQUALS("[test.cpp:5]: (style) Obsolescent function 'gethostbyaddr' called. It is recommended to use 'getnameinfo' instead.\n", errout.str());
} }
void testusleep() { void testusleep() {
@ -128,7 +134,7 @@ private:
"{\n" "{\n"
" usleep( 1000 );\n" " usleep( 1000 );\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:3]: (style) Obsolete function 'usleep' called. It is recommended to use the 'nanosleep' or 'setitimer' function instead.\n", errout.str()); ASSERT_EQUALS("[test.cpp:3]: (style) Obsolescent function 'usleep' called. It is recommended to use 'nanosleep' or 'setitimer' instead.\n", errout.str());
} }
void testindex() { void testindex() {
@ -168,7 +174,7 @@ private:
" const char i = index(var, 0);\n" " const char i = index(var, 0);\n"
" return i;\n" " return i;\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:4]: (style) Obsolete function 'index' called. It is recommended to use the function 'strchr' instead.\n", ASSERT_EQUALS("[test.cpp:4]: (style) Obsolescent function 'index' called. It is recommended to use 'strchr' instead.\n",
errout.str()); errout.str());
} }
@ -176,7 +182,7 @@ private:
check("void TDataModel::forceRowRefresh(int row) {\n" check("void TDataModel::forceRowRefresh(int row) {\n"
" emit dataChanged(index(row, 0), index(row, columnCount() - 1));\n" " emit dataChanged(index(row, 0), index(row, columnCount() - 1));\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:2]: (style) Obsolete function 'index' called. It is recommended to use the function 'strchr' instead.\n", errout.str()); ASSERT_EQUALS("[test.cpp:2]: (style) Obsolescent function 'index' called. It is recommended to use 'strchr' instead.\n", errout.str());
} }
void testrindex() { void testrindex() {
@ -191,7 +197,7 @@ private:
" const char var[7] = \"rindex\";\n" " const char var[7] = \"rindex\";\n"
" print(rindex(var, 0));\n" " print(rindex(var, 0));\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:4]: (style) Obsolete function 'rindex' called. It is recommended to use the function 'strrchr' instead.\n", errout.str()); ASSERT_EQUALS("[test.cpp:4]: (style) Obsolescent function 'rindex' called. It is recommended to use 'strrchr' instead.\n", errout.str());
} }
@ -207,29 +213,45 @@ private:
void testgets() { void testgets() {
check("void f()\n" check("void f()\n"
"{\n" "{\n"
" char *x = gets();\n" " char *x = gets(a);\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:3]: (style) Obsolete function 'gets' called. It is recommended to use the function 'fgets' instead.\n", errout.str()); ASSERT_EQUALS("[test.cpp:3]: (warning) Obsolete function 'gets' called. It is recommended to use 'fgets' instead.\n", errout.str());
check("void f()\n" check("void f()\n"
"{\n" "{\n"
" foo(x, gets());\n" " foo(x, gets(a));\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:3]: (style) Obsolete function 'gets' called. It is recommended to use the function 'fgets' instead.\n", errout.str()); ASSERT_EQUALS("[test.cpp:3]: (warning) Obsolete function 'gets' called. It is recommended to use 'fgets' instead.\n", errout.str());
} }
void testalloca() { void testalloca() {
check("void f()\n" check("void f()\n"
"{\n" "{\n"
" char *x = alloca(10);\n" " char *x = alloca(10);\n"
"}\n", "test.cpp"); // #4382 - there are no VLAs in C++ "}", "test.cpp"); // #4382 - there are no VLAs in C++
ASSERT_EQUALS("[test.cpp:3]: (warning) Obsolete function 'alloca' called. In C++11 and later it is recommended to use std::array<> instead.\n", errout.str());
check("void f()\n"
"{\n"
" char *x = alloca(10);\n"
"}", "test.c");
ASSERT_EQUALS("[test.c:3]: (warning) Obsolete function 'alloca' called. In C99 and later it is recommended to use a variable length array instead.\n", errout.str());
settings.standards.c = Standards::C89;
settings.standards.cpp = Standards::CPP03;
check("void f()\n"
"{\n"
" char *x = alloca(10);\n"
"}", "test.cpp"); // #4382 - there are no VLAs in C++
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
check("void f()\n" check("void f()\n"
"{\n" "{\n"
" char *x = alloca(10);\n" " char *x = alloca(10);\n"
"}\n", "test.c"); "}", "test.c");
ASSERT_EQUALS("[test.c:3]: (style) Obsolete function 'alloca' called. In C99 and later it is recommended to use a variable length array instead.\n", errout.str()); ASSERT_EQUALS("", errout.str());
settings.standards.c = Standards::C11;
settings.standards.cpp = Standards::CPP11;
} }
// ticket #3121 // ticket #3121
@ -253,8 +275,8 @@ private:
" char *x = std::gets(str);\n" " char *x = std::gets(str);\n"
" char *y = gets(str);\n" " char *y = gets(str);\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:3]: (style) Obsolete function 'gets' called. It is recommended to use the function 'fgets' instead.\n" ASSERT_EQUALS("[test.cpp:3]: (warning) Obsolete function 'gets' called. It is recommended to use 'fgets' instead.\n"
"[test.cpp:4]: (style) Obsolete function 'gets' called. It is recommended to use the function 'fgets' instead.\n", errout.str()); "[test.cpp:4]: (warning) Obsolete function 'gets' called. It is recommended to use 'fgets' instead.\n", errout.str());
} }
// multiple use // multiple use
@ -264,8 +286,8 @@ private:
" char *x = std::gets(str);\n" " char *x = std::gets(str);\n"
" usleep( 1000 );\n" " usleep( 1000 );\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:3]: (style) Obsolete function 'gets' called. It is recommended to use the function 'fgets' instead.\n" ASSERT_EQUALS("[test.cpp:3]: (warning) Obsolete function 'gets' called. It is recommended to use 'fgets' instead.\n"
"[test.cpp:4]: (style) Obsolete function 'usleep' called. It is recommended to use the 'nanosleep' or 'setitimer' function instead.\n", errout.str()); "[test.cpp:4]: (style) Obsolescent function 'usleep' called. It is recommended to use 'nanosleep' or 'setitimer' instead.\n", errout.str());
} }
void test_c_declaration() { void test_c_declaration() {
@ -275,14 +297,14 @@ private:
" char s [ 10 ] ;\n" " char s [ 10 ] ;\n"
" gets ( s ) ;\n" " gets ( s ) ;\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:5]: (style) Obsolete function 'gets' called. It is recommended to use the function 'fgets' instead.\n", errout.str()); ASSERT_EQUALS("[test.cpp:5]: (warning) Obsolete function 'gets' called. It is recommended to use 'fgets' instead.\n", errout.str());
check("int getcontext(ucontext_t *ucp);\n" check("int getcontext(ucontext_t *ucp);\n"
"int f (ucontext_t *ucp)\n" "int f (ucontext_t *ucp)\n"
"{\n" "{\n"
" getcontext ( ucp ) ;\n" " getcontext ( ucp ) ;\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:4]: (style) Obsolete function 'getcontext' called. Due to portability issues, applications are recommended to be rewritten to use POSIX threads.\n", errout.str()); ASSERT_EQUALS("[test.cpp:4]: (portability) Obsolescent function 'getcontext' called. Applications are recommended to be rewritten to use POSIX threads.\n", errout.str());
} }
void test_function_with_body() { void test_function_with_body() {
@ -295,11 +317,81 @@ private:
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
} }
void ticket3238() { void test_crypt() {
check("__FBSDID(\"...\");\n"); check("void f(char *pwd)\n"
"{\n"
" char *cpwd;"
" crypt(pwd, cpwd);\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (portability) Non reentrant function 'crypt' called. For threadsafe applications it is recommended to use the reentrant replacement function 'crypt_r'.\n", errout.str());
check("void f()\n"
"{\n"
" char *pwd = getpass(\"Password:\");"
" char *cpwd;"
" crypt(pwd, cpwd);\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (portability) Non reentrant function 'crypt' called. For threadsafe applications it is recommended to use the reentrant replacement function 'crypt_r'.\n", errout.str());
check("int f()\n"
"{\n"
" int crypt = 0;"
" return crypt;\n"
"}");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
} }
void test_namespace_handling() {
check("int f()\n"
"{\n"
" time_t t = 0;"
" std::localtime(&t);\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (portability) Non reentrant function 'localtime' called. For threadsafe applications it is recommended to use the reentrant replacement function 'localtime_r'.\n", errout.str());
// Passed as function argument
check("int f()\n"
"{\n"
" printf(\"Magic guess: %d\n\", getpwent());\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (portability) Non reentrant function 'getpwent' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getpwent_r'.\n", errout.str());
// Pass return value
check("int f()\n"
"{\n"
" time_t t = 0;"
" struct tm *foo = localtime(&t);\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (portability) Non reentrant function 'localtime' called. For threadsafe applications it is recommended to use the reentrant replacement function 'localtime_r'.\n", errout.str());
// Access via global namespace
check("int f()\n"
"{\n"
" ::getpwent();\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (portability) Non reentrant function 'getpwent' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getpwent_r'.\n", errout.str());
// Be quiet on function definitions
check("int getpwent()\n"
"{\n"
" return 123;\n"
"}");
ASSERT_EQUALS("", errout.str());
// Be quiet on other namespaces
check("int f()\n"
"{\n"
" foobar::getpwent();\n"
"}");
ASSERT_EQUALS("", errout.str());
// Be quiet on class member functions
check("int f()\n"
"{\n"
" foobar.getpwent();\n"
"}");
ASSERT_EQUALS("", errout.str());
}
}; };
REGISTER_TEST(TestObsoleteFunctions) REGISTER_TEST(TestFunctions)

View File

@ -206,6 +206,7 @@ private:
TEST_CASE(garbageCode155); // #7118 TEST_CASE(garbageCode155); // #7118
TEST_CASE(garbageCode156); // #7120 TEST_CASE(garbageCode156); // #7120
TEST_CASE(garbageCode157); // #7131 TEST_CASE(garbageCode157); // #7131
TEST_CASE(garbageCode158); // #3238
TEST_CASE(garbageValueFlow); TEST_CASE(garbageValueFlow);
TEST_CASE(garbageSymbolDatabase); TEST_CASE(garbageSymbolDatabase);
@ -1241,6 +1242,11 @@ private:
"template std::swap\n"), InternalError); "template std::swap\n"), InternalError);
} }
void garbageCode158() { // #3238
checkCode("__FBSDID(\"...\");\n");
}
void garbageValueFlow() { void garbageValueFlow() {
// #6089 // #6089
const char* code = "{} int foo(struct, x1, struct x2, x3, int, x5, x6, x7)\n" const char* code = "{} int foo(struct, x1, struct x2, x3, int, x5, x6, x7)\n"

View File

@ -40,6 +40,7 @@ private:
TEST_CASE(function_arg_valid); TEST_CASE(function_arg_valid);
TEST_CASE(function_arg_minsize); TEST_CASE(function_arg_minsize);
TEST_CASE(function_namespace); TEST_CASE(function_namespace);
TEST_CASE(function_warn);
TEST_CASE(memory); TEST_CASE(memory);
TEST_CASE(memory2); // define extra "free" allocation functions TEST_CASE(memory2); // define extra "free" allocation functions
TEST_CASE(resource); TEST_CASE(resource);
@ -305,6 +306,42 @@ private:
} }
} }
void function_warn() const {
const char xmldata[] = "<?xml version=\"1.0\"?>\n"
"<def>\n"
" <function name=\"a\">\n"
" <warn severity=\"style\" cstd=\"c99\">Message</warn>\n"
" </function>\n"
" <function name=\"b\">\n"
" <warn severity=\"performance\" cppstd=\"c++11\" reason=\"Obsolescent\" alternatives=\"c,d,e\"/>\n"
" </function>\n"
"</def>";
Library library;
readLibrary(library, xmldata);
TokenList tokenList(nullptr);
std::istringstream istr("a(); b();");
tokenList.createTokens(istr);
const Library::WarnInfo* a = library.getWarnInfo(tokenList.front());
const Library::WarnInfo* b = library.getWarnInfo(tokenList.front()->tokAt(4));
ASSERT_EQUALS(2, library.functionwarn.size());
ASSERT(a && b);
if (a && b) {
ASSERT_EQUALS("Message", a->message);
ASSERT_EQUALS(Severity::style, a->severity);
ASSERT_EQUALS(Standards::C99, a->standards.c);
ASSERT_EQUALS(Standards::CPP03, a->standards.cpp);
ASSERT_EQUALS("Obsolescent function 'b' called. It is recommended to use 'c', 'd' or 'e' instead.", b->message);
ASSERT_EQUALS(Severity::performance, b->severity);
ASSERT_EQUALS(Standards::C89, b->standards.c);
ASSERT_EQUALS(Standards::CPP11, b->standards.cpp);
}
}
void memory() const { void memory() const {
const char xmldata[] = "<?xml version=\"1.0\"?>\n" const char xmldata[] = "<?xml version=\"1.0\"?>\n"
"<def>\n" "<def>\n"

View File

@ -1,132 +0,0 @@
/*
* Cppcheck - A tool for static C/C++ code analysis
* Copyright (C) 2007-2015 Cppcheck team.
*
* 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 "tokenize.h"
#include "checknonreentrantfunctions.h"
#include "testsuite.h"
class TestNonReentrantFunctions : public TestFixture {
public:
TestNonReentrantFunctions() : TestFixture("TestNonReentrantFunctions") {
}
private:
Settings settings;
void run() {
settings.standards.posix = true;
settings.addEnabled("portability");
TEST_CASE(test_crypt);
TEST_CASE(test_namespace_handling);
}
void check(const char code[]) {
// Clear the error buffer..
errout.str("");
// Tokenize..
Tokenizer tokenizer(&settings, this);
std::istringstream istr(code);
tokenizer.tokenize(istr, "test.cpp");
tokenizer.simplifyTokenList2();
// Check for non reentrant functions..
CheckNonReentrantFunctions checkNonReentrantFunctions(&tokenizer, &settings, this);
checkNonReentrantFunctions.nonReentrantFunctions();
}
void test_crypt() {
check("void f(char *pwd)\n"
"{\n"
" char *cpwd;"
" crypt(pwd, cpwd);\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (portability) Non reentrant function 'crypt' called. For threadsafe applications it is recommended to use the reentrant replacement function 'crypt_r'.\n", errout.str());
check("void f()\n"
"{\n"
" char *pwd = getpass(\"Password:\");"
" char *cpwd;"
" crypt(pwd, cpwd);\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (portability) Non reentrant function 'crypt' called. For threadsafe applications it is recommended to use the reentrant replacement function 'crypt_r'.\n", errout.str());
check("int f()\n"
"{\n"
" int crypt = 0;"
" return crypt;\n"
"}");
ASSERT_EQUALS("", errout.str());
}
void test_namespace_handling() {
check("int f()\n"
"{\n"
" time_t t = 0;"
" std::localtime(&t);\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (portability) Non reentrant function 'localtime' called. For threadsafe applications it is recommended to use the reentrant replacement function 'localtime_r'.\n", errout.str());
// Passed as function argument
check("int f()\n"
"{\n"
" printf(\"Magic guess: %d\n\", getpwent());\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (portability) Non reentrant function 'getpwent' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getpwent_r'.\n", errout.str());
// Pass return value
check("int f()\n"
"{\n"
" time_t t = 0;"
" struct tm *foo = localtime(&t);\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (portability) Non reentrant function 'localtime' called. For threadsafe applications it is recommended to use the reentrant replacement function 'localtime_r'.\n", errout.str());
// Access via global namespace
check("int f()\n"
"{\n"
" ::getpwent();\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (portability) Non reentrant function 'getpwent' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getpwent_r'.\n", errout.str());
// Be quiet on function definitions
check("int getpwent()\n"
"{\n"
" return 123;\n"
"}");
ASSERT_EQUALS("", errout.str());
// Be quiet on other namespaces
check("int f()\n"
"{\n"
" foobar::getpwent();\n"
"}");
ASSERT_EQUALS("", errout.str());
// Be quiet on class member functions
check("int f()\n"
"{\n"
" foobar.getpwent();\n"
"}");
ASSERT_EQUALS("", errout.str());
}
};
REGISTER_TEST(TestNonReentrantFunctions)

View File

@ -53,9 +53,8 @@
<ClCompile Include="testlibrary.cpp" /> <ClCompile Include="testlibrary.cpp" />
<ClCompile Include="testmathlib.cpp" /> <ClCompile Include="testmathlib.cpp" />
<ClCompile Include="testmemleak.cpp" /> <ClCompile Include="testmemleak.cpp" />
<ClCompile Include="testnonreentrantfunctions.cpp" />
<ClCompile Include="testnullpointer.cpp" /> <ClCompile Include="testnullpointer.cpp" />
<ClCompile Include="testobsolescentfunctions.cpp" /> <ClCompile Include="testfunctions.cpp" />
<ClCompile Include="testoptions.cpp" /> <ClCompile Include="testoptions.cpp" />
<ClCompile Include="testother.cpp" /> <ClCompile Include="testother.cpp" />
<ClCompile Include="testpath.cpp" /> <ClCompile Include="testpath.cpp" />

View File

@ -64,15 +64,9 @@
<ClCompile Include="testmemleak.cpp"> <ClCompile Include="testmemleak.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="testnonreentrantfunctions.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="testnullpointer.cpp"> <ClCompile Include="testnullpointer.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="testobsolescentfunctions.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="testoptions.cpp"> <ClCompile Include="testoptions.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
@ -205,6 +199,9 @@
<ClCompile Include="testtokenlist.cpp"> <ClCompile Include="testtokenlist.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="testfunctions.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="options.h"> <ClInclude Include="options.h">