chk.c revision 91586
191586Smarkm/* $NetBSD: chk.c,v 1.15 2002/01/21 19:49:52 tv Exp $ */ 212099Sjoerg 312099Sjoerg/* 491586Smarkm * Copyright (c) 1996 Christopher G. Demetriou. All Rights Reserved. 512099Sjoerg * Copyright (c) 1994, 1995 Jochen Pohl 612099Sjoerg * All Rights Reserved. 712099Sjoerg * 812099Sjoerg * Redistribution and use in source and binary forms, with or without 912099Sjoerg * modification, are permitted provided that the following conditions 1012099Sjoerg * are met: 1112099Sjoerg * 1. Redistributions of source code must retain the above copyright 1212099Sjoerg * notice, this list of conditions and the following disclaimer. 1312099Sjoerg * 2. Redistributions in binary form must reproduce the above copyright 1412099Sjoerg * notice, this list of conditions and the following disclaimer in the 1512099Sjoerg * documentation and/or other materials provided with the distribution. 1612099Sjoerg * 3. All advertising materials mentioning features or use of this software 1712099Sjoerg * must display the following acknowledgement: 1812099Sjoerg * This product includes software developed by Jochen Pohl for 1912099Sjoerg * The NetBSD Project. 2012099Sjoerg * 4. The name of the author may not be used to endorse or promote products 2112099Sjoerg * derived from this software without specific prior written permission. 2212099Sjoerg * 2312099Sjoerg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2412099Sjoerg * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2512099Sjoerg * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2612099Sjoerg * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2712099Sjoerg * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2812099Sjoerg * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2912099Sjoerg * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3012099Sjoerg * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3112099Sjoerg * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3212099Sjoerg * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3312099Sjoerg */ 3412099Sjoerg 3591586Smarkm#include <sys/cdefs.h> 3691586Smarkm#if defined(__RCSID) && !defined(lint) 3791586Smarkm__RCSID("$NetBSD: chk.c,v 1.15 2002/01/21 19:49:52 tv Exp $"); 3812099Sjoerg#endif 3912099Sjoerg 4012099Sjoerg#include <ctype.h> 4112099Sjoerg#include <limits.h> 4291586Smarkm#include <stdlib.h> 4312099Sjoerg 4412099Sjoerg#include "lint2.h" 4512099Sjoerg 4691586Smarkmstatic void chkund(hte_t *); 4791586Smarkmstatic void chkdnu(hte_t *); 4891586Smarkmstatic void chkdnud(hte_t *); 4991586Smarkmstatic void chkmd(hte_t *); 5091586Smarkmstatic void chkvtui(hte_t *, sym_t *, sym_t *); 5191586Smarkmstatic void chkvtdi(hte_t *, sym_t *, sym_t *); 5291586Smarkmstatic void chkfaui(hte_t *, sym_t *, sym_t *); 5391586Smarkmstatic void chkau(hte_t *, int, sym_t *, sym_t *, pos_t *, 5491586Smarkm fcall_t *, fcall_t *, type_t *, type_t *); 5591586Smarkmstatic void chkrvu(hte_t *, sym_t *); 5691586Smarkmstatic void chkadecl(hte_t *, sym_t *, sym_t *); 5791586Smarkmstatic void printflike(hte_t *,fcall_t *, int, const char *, type_t **); 5891586Smarkmstatic void scanflike(hte_t *, fcall_t *, int, const char *, type_t **); 5991586Smarkmstatic void badfmt(hte_t *, fcall_t *); 6091586Smarkmstatic void inconarg(hte_t *, fcall_t *, int); 6191586Smarkmstatic void tofewarg(hte_t *, fcall_t *); 6291586Smarkmstatic void tomanyarg(hte_t *, fcall_t *); 6391586Smarkmstatic int eqtype(type_t *, type_t *, int, int, int, int *); 6491586Smarkmstatic int eqargs(type_t *, type_t *, int *); 6591586Smarkmstatic int mnoarg(type_t *, int *); 6612099Sjoerg 6712099Sjoerg 6812099Sjoerg/* 6912099Sjoerg * If there is a symbol named "main", mark it as used. 7012099Sjoerg */ 7112099Sjoergvoid 7291586Smarkmmainused(void) 7312099Sjoerg{ 7412099Sjoerg hte_t *hte; 7512099Sjoerg 7612099Sjoerg if ((hte = hsearch("main", 0)) != NULL) 7712099Sjoerg hte->h_used = 1; 7812099Sjoerg} 7912099Sjoerg 8012099Sjoerg/* 8112099Sjoerg * Performs all tests for a single name 8212099Sjoerg */ 8312099Sjoergvoid 8491586Smarkmchkname(hte_t *hte) 8512099Sjoerg{ 8612099Sjoerg sym_t *sym, *def, *pdecl, *decl; 8712099Sjoerg 8812099Sjoerg if (uflag) { 8912099Sjoerg chkund(hte); 9012099Sjoerg chkdnu(hte); 9112099Sjoerg if (xflag) 9212099Sjoerg chkdnud(hte); 9312099Sjoerg } 9412099Sjoerg chkmd(hte); 9512099Sjoerg 9612099Sjoerg /* Get definition, prototype declaration and declaration */ 9712099Sjoerg def = pdecl = decl = NULL; 9812099Sjoerg for (sym = hte->h_syms; sym != NULL; sym = sym->s_nxt) { 9912099Sjoerg if (def == NULL && (sym->s_def == DEF || sym->s_def == TDEF)) 10012099Sjoerg def = sym; 10112099Sjoerg if (pdecl == NULL && sym->s_def == DECL && 10212099Sjoerg TP(sym->s_type)->t_tspec == FUNC && 10312099Sjoerg TP(sym->s_type)->t_proto) { 10412099Sjoerg pdecl = sym; 10512099Sjoerg } 10612099Sjoerg if (decl == NULL && sym->s_def == DECL) 10712099Sjoerg decl = sym; 10812099Sjoerg } 10912099Sjoerg 11012099Sjoerg /* A prototype is better than an old style declaration. */ 11112099Sjoerg if (pdecl != NULL) 11212099Sjoerg decl = pdecl; 11312099Sjoerg 11412099Sjoerg chkvtui(hte, def, decl); 11512099Sjoerg 11612099Sjoerg chkvtdi(hte, def, decl); 11712099Sjoerg 11812099Sjoerg chkfaui(hte, def, decl); 11912099Sjoerg 12012099Sjoerg chkrvu(hte, def); 12112099Sjoerg 12212099Sjoerg chkadecl(hte, def, decl); 12312099Sjoerg} 12412099Sjoerg 12512099Sjoerg/* 12612099Sjoerg * Print a warning if the name has been used, but not defined. 12712099Sjoerg */ 12812099Sjoergstatic void 12991586Smarkmchkund(hte_t *hte) 13012099Sjoerg{ 13112099Sjoerg fcall_t *fcall; 13212099Sjoerg usym_t *usym; 13312099Sjoerg 13412099Sjoerg if (!hte->h_used || hte->h_def) 13512099Sjoerg return; 13612099Sjoerg 13712099Sjoerg if ((fcall = hte->h_calls) != NULL) { 13812099Sjoerg /* %s used( %s ), but not defined */ 13912099Sjoerg msg(0, hte->h_name, mkpos(&fcall->f_pos)); 14012099Sjoerg } else if ((usym = hte->h_usyms) != NULL) { 14112099Sjoerg /* %s used( %s ), but not defined */ 14212099Sjoerg msg(0, hte->h_name, mkpos(&usym->u_pos)); 14312099Sjoerg } 14412099Sjoerg} 14512099Sjoerg 14612099Sjoerg/* 14712099Sjoerg * Print a warning if the name has been defined, but never used. 14812099Sjoerg */ 14912099Sjoergstatic void 15091586Smarkmchkdnu(hte_t *hte) 15112099Sjoerg{ 15212099Sjoerg sym_t *sym; 15312099Sjoerg 15412099Sjoerg if (!hte->h_def || hte->h_used) 15512099Sjoerg return; 15612099Sjoerg 15712099Sjoerg for (sym = hte->h_syms; sym != NULL; sym = sym->s_nxt) { 15812099Sjoerg if (sym->s_def == DEF || sym->s_def == TDEF) { 15912099Sjoerg /* %s defined( %s ), but never used */ 16012099Sjoerg msg(1, hte->h_name, mkpos(&sym->s_pos)); 16112099Sjoerg break; 16212099Sjoerg } 16312099Sjoerg } 16412099Sjoerg} 16512099Sjoerg 16612099Sjoerg/* 16791586Smarkm * Print a warning if the variable has been declared, but is not used 16812099Sjoerg * or defined. 16912099Sjoerg */ 17012099Sjoergstatic void 17191586Smarkmchkdnud(hte_t *hte) 17212099Sjoerg{ 17312099Sjoerg sym_t *sym; 17412099Sjoerg 17512099Sjoerg if (hte->h_syms == NULL || hte->h_used || hte->h_def) 17612099Sjoerg return; 17791586Smarkm 17891586Smarkm sym = hte->h_syms; 17991586Smarkm if (TP(sym->s_type)->t_tspec == FUNC) 18091586Smarkm return; 18191586Smarkm 18291586Smarkm if (sym->s_def != DECL) 18391586Smarkm errx(1, "internal error: chkdnud() 1"); 18491586Smarkm /* %s declared( %s ), but never used or defined */ 18591586Smarkm msg(2, hte->h_name, mkpos(&sym->s_pos)); 18612099Sjoerg} 18712099Sjoerg 18812099Sjoerg/* 18991586Smarkm * Print a warning if there is more than one definition for 19012099Sjoerg * this name. 19112099Sjoerg */ 19212099Sjoergstatic void 19391586Smarkmchkmd(hte_t *hte) 19412099Sjoerg{ 19512099Sjoerg sym_t *sym, *def1; 19612099Sjoerg char *pos1; 19712099Sjoerg 19812099Sjoerg if (!hte->h_def) 19912099Sjoerg return; 20012099Sjoerg 20112099Sjoerg def1 = NULL; 20212099Sjoerg for (sym = hte->h_syms; sym != NULL; sym = sym->s_nxt) { 20312099Sjoerg /* 20412099Sjoerg * ANSI C allows tentative definitions of the same name in 20512099Sjoerg * only one compilation unit. 20612099Sjoerg */ 20712099Sjoerg if (sym->s_def != DEF && (!sflag || sym->s_def != TDEF)) 20812099Sjoerg continue; 20912099Sjoerg if (def1 == NULL) { 21012099Sjoerg def1 = sym; 21112099Sjoerg continue; 21212099Sjoerg } 21312099Sjoerg pos1 = xstrdup(mkpos(&def1->s_pos)); 21412099Sjoerg /* %s multiply defined\t%s :: %s */ 21512099Sjoerg msg(3, hte->h_name, pos1, mkpos(&sym->s_pos)); 21612099Sjoerg free(pos1); 21712099Sjoerg } 21812099Sjoerg} 21912099Sjoerg 22012099Sjoerg/* 22112099Sjoerg * Print a warning if the return value assumed for a function call 22212099Sjoerg * differs from the return value of the function definition or 22312099Sjoerg * function declaration. 22412099Sjoerg * 22512099Sjoerg * If no definition/declaration can be found, the assumed return values 22612099Sjoerg * are always int. So there is no need to compare with another function 22712099Sjoerg * call as it's done for function arguments. 22812099Sjoerg */ 22912099Sjoergstatic void 23091586Smarkmchkvtui(hte_t *hte, sym_t *def, sym_t *decl) 23112099Sjoerg{ 23212099Sjoerg fcall_t *call; 23312099Sjoerg char *pos1; 23412099Sjoerg type_t *tp1, *tp2; 23512099Sjoerg /* LINTED (automatic hides external declaration: warn) */ 23612099Sjoerg int warn, eq; 23712099Sjoerg tspec_t t1; 23812099Sjoerg 23912099Sjoerg if (hte->h_calls == NULL) 24012099Sjoerg return; 24112099Sjoerg 24212099Sjoerg if (def == NULL) 24312099Sjoerg def = decl; 24412099Sjoerg if (def == NULL) 24512099Sjoerg return; 24612099Sjoerg 24712099Sjoerg t1 = (tp1 = TP(def->s_type)->t_subt)->t_tspec; 24812099Sjoerg for (call = hte->h_calls; call != NULL; call = call->f_nxt) { 24912099Sjoerg tp2 = TP(call->f_type)->t_subt; 25012099Sjoerg eq = eqtype(tp1, tp2, 1, 0, 0, (warn = 0, &warn)); 25112099Sjoerg if (!call->f_rused) { 25212099Sjoerg /* no return value used */ 25312099Sjoerg if ((t1 == STRUCT || t1 == UNION) && !eq) { 25412099Sjoerg /* 25512099Sjoerg * If a function returns a struct or union it 25612099Sjoerg * must be declared to return a struct or 25712099Sjoerg * union, also if the return value is ignored. 25812099Sjoerg * This is necessary because the caller must 25912099Sjoerg * allocate stack space for the return value. 26012099Sjoerg * If it does not, the return value would over- 26112099Sjoerg * write other data. 26212099Sjoerg * XXX Following massage may be confusing 26312099Sjoerg * because it appears also if the return value 26412099Sjoerg * was declared inconsistently. But this 26512099Sjoerg * behaviour matches pcc based lint, so it is 26612099Sjoerg * accepted for now. 26712099Sjoerg */ 26812099Sjoerg pos1 = xstrdup(mkpos(&def->s_pos)); 26912099Sjoerg /* %s value must be decl. before use %s :: %s */ 27012099Sjoerg msg(17, hte->h_name, 27112099Sjoerg pos1, mkpos(&call->f_pos)); 27212099Sjoerg free(pos1); 27312099Sjoerg } 27412099Sjoerg continue; 27512099Sjoerg } 27612099Sjoerg if (!eq || (sflag && warn)) { 27712099Sjoerg pos1 = xstrdup(mkpos(&def->s_pos)); 27812099Sjoerg /* %s value used inconsistenty\t%s :: %s */ 27912099Sjoerg msg(4, hte->h_name, pos1, mkpos(&call->f_pos)); 28012099Sjoerg free(pos1); 28112099Sjoerg } 28212099Sjoerg } 28312099Sjoerg} 28412099Sjoerg 28512099Sjoerg/* 28612099Sjoerg * Print a warning if a definition/declaration does not match another 28712099Sjoerg * definition/declaration of the same name. For functions, only the 28812099Sjoerg * types of return values are tested. 28912099Sjoerg */ 29012099Sjoergstatic void 29191586Smarkmchkvtdi(hte_t *hte, sym_t *def, sym_t *decl) 29212099Sjoerg{ 29312099Sjoerg sym_t *sym; 29412099Sjoerg type_t *tp1, *tp2; 29512099Sjoerg /* LINTED (automatic hides external declaration: warn) */ 29612099Sjoerg int eq, warn; 29712099Sjoerg char *pos1; 29812099Sjoerg 29912099Sjoerg if (def == NULL) 30012099Sjoerg def = decl; 30112099Sjoerg if (def == NULL) 30212099Sjoerg return; 30312099Sjoerg 30412099Sjoerg tp1 = TP(def->s_type); 30512099Sjoerg for (sym = hte->h_syms; sym != NULL; sym = sym->s_nxt) { 30612099Sjoerg if (sym == def) 30712099Sjoerg continue; 30812099Sjoerg tp2 = TP(sym->s_type); 30912099Sjoerg warn = 0; 31012099Sjoerg if (tp1->t_tspec == FUNC && tp2->t_tspec == FUNC) { 31112099Sjoerg eq = eqtype(tp1->t_subt, tp2->t_subt, 1, 0, 0, &warn); 31212099Sjoerg } else { 31312099Sjoerg eq = eqtype(tp1, tp2, 0, 0, 0, &warn); 31412099Sjoerg } 31512099Sjoerg if (!eq || (sflag && warn)) { 31612099Sjoerg pos1 = xstrdup(mkpos(&def->s_pos)); 31712099Sjoerg /* %s value declared inconsistently\t%s :: %s */ 31812099Sjoerg msg(5, hte->h_name, pos1, mkpos(&sym->s_pos)); 31912099Sjoerg free(pos1); 32012099Sjoerg } 32112099Sjoerg } 32212099Sjoerg} 32312099Sjoerg 32412099Sjoerg/* 32512099Sjoerg * Print a warning if a function is called with arguments which does 32612099Sjoerg * not match the function definition, declaration or another call 32712099Sjoerg * of the same function. 32812099Sjoerg */ 32912099Sjoergstatic void 33091586Smarkmchkfaui(hte_t *hte, sym_t *def, sym_t *decl) 33112099Sjoerg{ 33212099Sjoerg type_t *tp1, *tp2, **ap1, **ap2; 33391586Smarkm pos_t *pos1p = NULL; 33412099Sjoerg fcall_t *calls, *call, *call1; 33512099Sjoerg int n, as; 33612099Sjoerg char *pos1; 33712099Sjoerg arginf_t *ai; 33812099Sjoerg 33912099Sjoerg if ((calls = hte->h_calls) == NULL) 34012099Sjoerg return; 34112099Sjoerg 34212099Sjoerg /* 34391586Smarkm * If we find a function definition, we use this for comparison, 34412099Sjoerg * otherwise the first prototype we can find. If there is no 34512099Sjoerg * definition or prototype declaration, the first function call 34612099Sjoerg * is used. 34712099Sjoerg */ 34812099Sjoerg tp1 = NULL; 34912099Sjoerg call1 = NULL; 35012099Sjoerg if (def != NULL) { 35112099Sjoerg if ((tp1 = TP(def->s_type))->t_tspec != FUNC) 35212099Sjoerg return; 35312099Sjoerg pos1p = &def->s_pos; 35412099Sjoerg } else if (decl != NULL && TP(decl->s_type)->t_proto) { 35512099Sjoerg if ((tp1 = TP(decl->s_type))->t_tspec != FUNC) 35612099Sjoerg return; 35712099Sjoerg pos1p = &decl->s_pos; 35812099Sjoerg } 35912099Sjoerg if (tp1 == NULL) { 36012099Sjoerg call1 = calls; 36112099Sjoerg calls = calls->f_nxt; 36212099Sjoerg if ((tp1 = TP(call1->f_type))->t_tspec != FUNC) 36312099Sjoerg return; 36412099Sjoerg pos1p = &call1->f_pos; 36512099Sjoerg } 36612099Sjoerg 36712099Sjoerg n = 1; 36812099Sjoerg for (call = calls; call != NULL; call = call->f_nxt) { 36912099Sjoerg if ((tp2 = TP(call->f_type))->t_tspec != FUNC) 37012099Sjoerg continue; 37112099Sjoerg ap1 = tp1->t_args; 37212099Sjoerg ap2 = tp2->t_args; 37312099Sjoerg n = 0; 37412099Sjoerg while (*ap1 != NULL && *ap2 != NULL) { 37512099Sjoerg if (def != NULL && def->s_va && n >= def->s_nva) 37612099Sjoerg break; 37712099Sjoerg n++; 37812099Sjoerg chkau(hte, n, def, decl, pos1p, call1, call, 37912099Sjoerg *ap1, *ap2); 38012099Sjoerg ap1++; 38112099Sjoerg ap2++; 38212099Sjoerg } 38312099Sjoerg if (*ap1 == *ap2) { 38412099Sjoerg /* equal # of arguments */ 38512099Sjoerg } else if (def != NULL && def->s_va && n >= def->s_nva) { 38612099Sjoerg /* 38712099Sjoerg * function definition with VARARGS; The # of 38812099Sjoerg * arguments of the call must be at least as large 38912099Sjoerg * as the parameter of VARARGS. 39012099Sjoerg */ 39112099Sjoerg } else if (*ap2 != NULL && tp1->t_proto && tp1->t_vararg) { 39212099Sjoerg /* 39312099Sjoerg * prototype with ... and function call with 39412099Sjoerg * at least the same # of arguments as declared 39512099Sjoerg * in the prototype. 39612099Sjoerg */ 39712099Sjoerg } else { 39812099Sjoerg pos1 = xstrdup(mkpos(pos1p)); 39912099Sjoerg /* %s: variable # of args\t%s :: %s */ 40012099Sjoerg msg(7, hte->h_name, pos1, mkpos(&call->f_pos)); 40112099Sjoerg free(pos1); 40212099Sjoerg continue; 40312099Sjoerg } 40412099Sjoerg 40512099Sjoerg /* perform SCANFLIKE/PRINTFLIKE tests */ 40612099Sjoerg if (def == NULL || (!def->s_prfl && !def->s_scfl)) 40712099Sjoerg continue; 40812099Sjoerg as = def->s_prfl ? def->s_nprfl : def->s_nscfl; 40912099Sjoerg for (ai = call->f_args; ai != NULL; ai = ai->a_nxt) { 41012099Sjoerg if (ai->a_num == as) 41112099Sjoerg break; 41212099Sjoerg } 41312099Sjoerg if (ai == NULL || !ai->a_fmt) 41412099Sjoerg continue; 41512099Sjoerg if (def->s_prfl) { 41612099Sjoerg printflike(hte, call, n, ai->a_fstrg, ap2); 41712099Sjoerg } else { 41812099Sjoerg scanflike(hte, call, n, ai->a_fstrg, ap2); 41912099Sjoerg } 42012099Sjoerg } 42112099Sjoerg} 42212099Sjoerg 42312099Sjoerg/* 42412099Sjoerg * Check a single argument in a function call. 42512099Sjoerg * 42612099Sjoerg * hte a pointer to the hash table entry of the function 42712099Sjoerg * n the number of the argument (1..) 42812099Sjoerg * def the function definition or NULL 42912099Sjoerg * decl prototype declaration, old style declaration or NULL 43012099Sjoerg * pos1p position of definition, declaration of first call 43112099Sjoerg * call1 first call, if both def and decl are old style def/decl 43212099Sjoerg * call checked call 43312099Sjoerg * arg1 currently checked argument of def/decl/call1 43412099Sjoerg * arg2 currently checked argument of call 43512099Sjoerg * 43612099Sjoerg */ 43712099Sjoergstatic void 43891586Smarkmchkau(hte_t *hte, int n, sym_t *def, sym_t *decl, pos_t *pos1p, 43991586Smarkm fcall_t *call1, fcall_t *call, type_t *arg1, type_t *arg2) 44012099Sjoerg{ 44112099Sjoerg /* LINTED (automatic hides external declaration: warn) */ 44212099Sjoerg int promote, asgn, warn; 44312099Sjoerg tspec_t t1, t2; 44412099Sjoerg arginf_t *ai, *ai1; 44512099Sjoerg char *pos1; 44612099Sjoerg 44712099Sjoerg /* 44812099Sjoerg * If a function definition is available (def != NULL), we compair the 44912099Sjoerg * function call (call) with the definition. Otherwise, if a function 45012099Sjoerg * definition is available and it is not an old style definition 45112099Sjoerg * (decl != NULL && TP(decl->s_type)->t_proto), we compair the call 45212099Sjoerg * with this declaration. Otherwise we compair it with the first 45312099Sjoerg * call we have found (call1). 45412099Sjoerg */ 45512099Sjoerg 45612099Sjoerg /* arg1 must be promoted if it stems from an old style definition */ 45712099Sjoerg promote = def != NULL && def->s_osdef; 45812099Sjoerg 45912099Sjoerg /* 46012099Sjoerg * If we compair with a definition or declaration, we must perform 46112099Sjoerg * the same checks for qualifiers in indirected types as in 46212099Sjoerg * assignments. 46312099Sjoerg */ 46412099Sjoerg asgn = def != NULL || (decl != NULL && TP(decl->s_type)->t_proto); 46512099Sjoerg 46612099Sjoerg warn = 0; 46712099Sjoerg if (eqtype(arg1, arg2, 1, promote, asgn, &warn) && (!sflag || !warn)) 46812099Sjoerg return; 46912099Sjoerg 47012099Sjoerg /* 47112099Sjoerg * Other lint implementations print warnings as soon as the type 47212099Sjoerg * of an argument does not match exactly the expected type. The 47391586Smarkm * result are lots of warnings which are really not necessary. 47412099Sjoerg * We print a warning only if 47512099Sjoerg * (0) at least one type is not an interger type and types differ 47612099Sjoerg * (1) hflag is set and types differ 47712099Sjoerg * (2) types differ, except in signedness 47812099Sjoerg * If the argument is an integer constant whose msb is not set, 47912099Sjoerg * signedness is ignored (e.g. 0 matches both signed and unsigned 48012099Sjoerg * int). This is with and without hflag. 48112099Sjoerg * If the argument is an integer constant with value 0 and the 48212099Sjoerg * expected argument is of type pointer and the width of the 48312099Sjoerg * interger constant is the same as the width of the pointer, 48412099Sjoerg * no warning is printed. 48512099Sjoerg */ 48612099Sjoerg t1 = arg1->t_tspec; 48712099Sjoerg t2 = arg2->t_tspec; 48812099Sjoerg if (isityp(t1) && isityp(t2) && !arg1->t_isenum && !arg2->t_isenum) { 48912099Sjoerg if (promote) { 49012099Sjoerg /* 49112099Sjoerg * XXX Here is a problem: Althrough it is possible to 49212099Sjoerg * pass an int where a char/short it expected, there 49312099Sjoerg * may be loss in significant digits. We should first 49412099Sjoerg * check for const arguments if they can be converted 49512099Sjoerg * into the original parameter type. 49612099Sjoerg */ 49712099Sjoerg if (t1 == FLOAT) { 49812099Sjoerg t1 = DOUBLE; 49912099Sjoerg } else if (t1 == CHAR || t1 == SCHAR) { 50012099Sjoerg t1 = INT; 50112099Sjoerg } else if (t1 == UCHAR) { 50212099Sjoerg t1 = tflag ? UINT : INT; 50312099Sjoerg } else if (t1 == SHORT) { 50412099Sjoerg t1 = INT; 50512099Sjoerg } else if (t1 == USHORT) { 50612099Sjoerg /* CONSTCOND */ 50712099Sjoerg t1 = INT_MAX < USHRT_MAX || tflag ? UINT : INT; 50812099Sjoerg } 50912099Sjoerg } 51012099Sjoerg 51112099Sjoerg if (styp(t1) == styp(t2)) { 51212099Sjoerg 51312099Sjoerg /* 51412099Sjoerg * types differ only in signedness; get information 51512099Sjoerg * about arguments 51612099Sjoerg */ 51712099Sjoerg 51812099Sjoerg /* 51912099Sjoerg * treat a definition like a call with variable 52012099Sjoerg * arguments 52112099Sjoerg */ 52212099Sjoerg ai1 = call1 != NULL ? call1->f_args : NULL; 52312099Sjoerg 52412099Sjoerg /* 52512099Sjoerg * if two calls are compared, ai1 is set to the 52612099Sjoerg * information for the n-th argument, if this was 52712099Sjoerg * a constant, otherwise to NULL 52812099Sjoerg */ 52912099Sjoerg for ( ; ai1 != NULL; ai1 = ai1->a_nxt) { 53012099Sjoerg if (ai1->a_num == n) 53112099Sjoerg break; 53212099Sjoerg } 53312099Sjoerg /* 53412099Sjoerg * ai is set to the information of the n-th arg 53512099Sjoerg * of the (second) call, if this was a constant, 53612099Sjoerg * otherwise to NULL 53712099Sjoerg */ 53812099Sjoerg for (ai = call->f_args; ai != NULL; ai = ai->a_nxt) { 53912099Sjoerg if (ai->a_num == n) 54012099Sjoerg break; 54112099Sjoerg } 54212099Sjoerg 54312099Sjoerg if (ai1 == NULL && ai == NULL) { 54412099Sjoerg /* no constant at all */ 54512099Sjoerg if (!hflag) 54612099Sjoerg return; 54712099Sjoerg } else if (ai1 == NULL || ai == NULL) { 54812099Sjoerg /* one constant */ 54912099Sjoerg if (ai == NULL) 55012099Sjoerg ai = ai1; 55112099Sjoerg if (ai->a_zero || ai->a_pcon) 55212099Sjoerg /* same value in signed and unsigned */ 55312099Sjoerg return; 55412099Sjoerg /* value (not representation) differently */ 55512099Sjoerg } else { 55612099Sjoerg /* 55712099Sjoerg * two constants, one signed, one unsigned; 55812099Sjoerg * if the msb of one of the constants is set, 55912099Sjoerg * the argument is used inconsistently. 56012099Sjoerg */ 56112099Sjoerg if (!ai1->a_ncon && !ai->a_ncon) 56212099Sjoerg return; 56312099Sjoerg } 56412099Sjoerg } 56512099Sjoerg 56691586Smarkm } else if (t1 == PTR && isityp(t2)) { 56712099Sjoerg for (ai = call->f_args; ai != NULL; ai = ai->a_nxt) { 56812099Sjoerg if (ai->a_num == n) 56912099Sjoerg break; 57012099Sjoerg } 57191586Smarkm /* 57291586Smarkm * Vendor implementations of lint (e.g. HP-UX, Digital UNIX) 57391586Smarkm * don't care about the size of the integer argument, 57491586Smarkm * only whether or not it is zero. We do the same. 57591586Smarkm */ 57612099Sjoerg if (ai != NULL && ai->a_zero) 57712099Sjoerg return; 57812099Sjoerg } 57912099Sjoerg 58012099Sjoerg pos1 = xstrdup(mkpos(pos1p)); 58112099Sjoerg /* %s, arg %d used inconsistently\t%s :: %s */ 58212099Sjoerg msg(6, hte->h_name, n, pos1, mkpos(&call->f_pos)); 58312099Sjoerg free(pos1); 58412099Sjoerg} 58512099Sjoerg 58612099Sjoerg/* 58712099Sjoerg * Compare the types in the NULL-terminated array ap with the format 58812099Sjoerg * string fmt. 58912099Sjoerg */ 59012099Sjoergstatic void 59191586Smarkmprintflike(hte_t *hte, fcall_t *call, int n, const char *fmt, type_t **ap) 59212099Sjoerg{ 59312099Sjoerg const char *fp; 59412099Sjoerg int fc; 59512099Sjoerg int fwidth, prec, left, sign, space, alt, zero; 59691586Smarkm tspec_t sz, t1, t2 = NOTSPEC; 59712099Sjoerg type_t *tp; 59812099Sjoerg 59912099Sjoerg fp = fmt; 60012099Sjoerg fc = *fp++; 60112099Sjoerg 60212099Sjoerg for ( ; ; ) { 60312099Sjoerg if (fc == '\0') { 60412099Sjoerg if (*ap != NULL) 60512099Sjoerg tomanyarg(hte, call); 60612099Sjoerg break; 60712099Sjoerg } 60812099Sjoerg if (fc != '%') { 60912099Sjoerg badfmt(hte, call); 61012099Sjoerg break; 61112099Sjoerg } 61212099Sjoerg fc = *fp++; 61312099Sjoerg fwidth = prec = left = sign = space = alt = zero = 0; 61412099Sjoerg sz = NOTSPEC; 61512099Sjoerg 61612099Sjoerg /* Flags */ 61712099Sjoerg for ( ; ; ) { 61812099Sjoerg if (fc == '-') { 61912099Sjoerg if (left) 62012099Sjoerg break; 62112099Sjoerg left = 1; 62212099Sjoerg } else if (fc == '+') { 62312099Sjoerg if (sign) 62412099Sjoerg break; 62512099Sjoerg sign = 1; 62612099Sjoerg } else if (fc == ' ') { 62712099Sjoerg if (space) 62812099Sjoerg break; 62912099Sjoerg space = 1; 63012099Sjoerg } else if (fc == '#') { 63112099Sjoerg if (alt) 63212099Sjoerg break; 63312099Sjoerg alt = 1; 63412099Sjoerg } else if (fc == '0') { 63512099Sjoerg if (zero) 63612099Sjoerg break; 63712099Sjoerg zero = 1; 63812099Sjoerg } else { 63912099Sjoerg break; 64012099Sjoerg } 64112099Sjoerg fc = *fp++; 64212099Sjoerg } 64312099Sjoerg 64412099Sjoerg /* field width */ 64512099Sjoerg if (isdigit(fc)) { 64612099Sjoerg fwidth = 1; 64712099Sjoerg do { fc = *fp++; } while (isdigit(fc)) ; 64812099Sjoerg } else if (fc == '*') { 64912099Sjoerg fwidth = 1; 65012099Sjoerg fc = *fp++; 65112099Sjoerg if ((tp = *ap++) == NULL) { 65212099Sjoerg tofewarg(hte, call); 65312099Sjoerg break; 65412099Sjoerg } 65512099Sjoerg n++; 65612099Sjoerg if ((t1 = tp->t_tspec) != INT && (hflag || t1 != UINT)) 65712099Sjoerg inconarg(hte, call, n); 65812099Sjoerg } 65912099Sjoerg 66012099Sjoerg /* precision */ 66112099Sjoerg if (fc == '.') { 66212099Sjoerg fc = *fp++; 66312099Sjoerg prec = 1; 66412099Sjoerg if (isdigit(fc)) { 66512099Sjoerg do { fc = *fp++; } while (isdigit(fc)); 66612099Sjoerg } else if (fc == '*') { 66712099Sjoerg fc = *fp++; 66812099Sjoerg if ((tp = *ap++) == NULL) { 66912099Sjoerg tofewarg(hte, call); 67012099Sjoerg break; 67112099Sjoerg } 67212099Sjoerg n++; 67312099Sjoerg if (tp->t_tspec != INT) 67412099Sjoerg inconarg(hte, call, n); 67512099Sjoerg } else { 67612099Sjoerg badfmt(hte, call); 67712099Sjoerg break; 67812099Sjoerg } 67912099Sjoerg } 68012099Sjoerg 68112099Sjoerg if (fc == 'h') { 68212099Sjoerg sz = SHORT; 68312099Sjoerg } else if (fc == 'l') { 68412099Sjoerg sz = LONG; 68512099Sjoerg } else if (fc == 'q') { 68612099Sjoerg sz = QUAD; 68712099Sjoerg } else if (fc == 'L') { 68812099Sjoerg sz = LDOUBLE; 68912099Sjoerg } 69012099Sjoerg if (sz != NOTSPEC) 69112099Sjoerg fc = *fp++; 69212099Sjoerg 69312099Sjoerg if (fc == '%') { 69412099Sjoerg if (sz != NOTSPEC || left || sign || space || 69512099Sjoerg alt || zero || prec || fwidth) { 69612099Sjoerg badfmt(hte, call); 69712099Sjoerg } 69812099Sjoerg fc = *fp++; 69912099Sjoerg continue; 70012099Sjoerg } 70112099Sjoerg 70212099Sjoerg if (fc == '\0') { 70312099Sjoerg badfmt(hte, call); 70412099Sjoerg break; 70512099Sjoerg } 70612099Sjoerg 70712099Sjoerg if ((tp = *ap++) == NULL) { 70812099Sjoerg tofewarg(hte, call); 70912099Sjoerg break; 71012099Sjoerg } 71112099Sjoerg n++; 71212099Sjoerg if ((t1 = tp->t_tspec) == PTR) 71312099Sjoerg t2 = tp->t_subt->t_tspec; 71412099Sjoerg 71512099Sjoerg if (fc == 'd' || fc == 'i') { 71612099Sjoerg if (alt || sz == LDOUBLE) { 71712099Sjoerg badfmt(hte, call); 71812099Sjoerg break; 71912099Sjoerg } 72012099Sjoerg int_conv: 72112099Sjoerg if (sz == LONG) { 72212099Sjoerg if (t1 != LONG && (hflag || t1 != ULONG)) 72312099Sjoerg inconarg(hte, call, n); 72412099Sjoerg } else if (sz == QUAD) { 72512099Sjoerg if (t1 != QUAD && (hflag || t1 != UQUAD)) 72612099Sjoerg inconarg(hte, call, n); 72712099Sjoerg } else { 72812099Sjoerg /* 72912099Sjoerg * SHORT is always promoted to INT, USHORT 73012099Sjoerg * to INT or UINT. 73112099Sjoerg */ 73212099Sjoerg if (t1 != INT && (hflag || t1 != UINT)) 73312099Sjoerg inconarg(hte, call, n); 73412099Sjoerg } 73512099Sjoerg } else if (fc == 'o' || fc == 'u' || fc == 'x' || fc == 'X') { 73612099Sjoerg if ((alt && fc == 'u') || sz == LDOUBLE) 73712099Sjoerg badfmt(hte, call); 73812099Sjoerg uint_conv: 73912099Sjoerg if (sz == LONG) { 74012099Sjoerg if (t1 != ULONG && (hflag || t1 != LONG)) 74112099Sjoerg inconarg(hte, call, n); 74212099Sjoerg } else if (sz == QUAD) { 74312099Sjoerg if (t1 != UQUAD && (hflag || t1 != QUAD)) 74412099Sjoerg inconarg(hte, call, n); 74512099Sjoerg } else if (sz == SHORT) { 74612099Sjoerg /* USHORT was promoted to INT or UINT */ 74712099Sjoerg if (t1 != UINT && t1 != INT) 74812099Sjoerg inconarg(hte, call, n); 74912099Sjoerg } else { 75012099Sjoerg if (t1 != UINT && (hflag || t1 != INT)) 75112099Sjoerg inconarg(hte, call, n); 75212099Sjoerg } 75312099Sjoerg } else if (fc == 'D' || fc == 'O' || fc == 'U') { 75412099Sjoerg if ((alt && fc != 'O') || sz != NOTSPEC || !tflag) 75512099Sjoerg badfmt(hte, call); 75612099Sjoerg sz = LONG; 75712099Sjoerg if (fc == 'D') { 75812099Sjoerg goto int_conv; 75912099Sjoerg } else { 76012099Sjoerg goto uint_conv; 76112099Sjoerg } 76212099Sjoerg } else if (fc == 'f' || fc == 'e' || fc == 'E' || 76312099Sjoerg fc == 'g' || fc == 'G') { 76412099Sjoerg if (sz == NOTSPEC) 76512099Sjoerg sz = DOUBLE; 76612099Sjoerg if (sz != DOUBLE && sz != LDOUBLE) 76712099Sjoerg badfmt(hte, call); 76812099Sjoerg if (t1 != sz) 76912099Sjoerg inconarg(hte, call, n); 77012099Sjoerg } else if (fc == 'c') { 77112099Sjoerg if (sz != NOTSPEC || alt || zero) 77212099Sjoerg badfmt(hte, call); 77312099Sjoerg if (t1 != INT) 77412099Sjoerg inconarg(hte, call, n); 77512099Sjoerg } else if (fc == 's') { 77612099Sjoerg if (sz != NOTSPEC || alt || zero) 77712099Sjoerg badfmt(hte, call); 77812099Sjoerg if (t1 != PTR || 77912099Sjoerg (t2 != CHAR && t2 != UCHAR && t2 != SCHAR)) { 78012099Sjoerg inconarg(hte, call, n); 78112099Sjoerg } 78212099Sjoerg } else if (fc == 'p') { 78312099Sjoerg if (fwidth || prec || sz != NOTSPEC || alt || zero) 78412099Sjoerg badfmt(hte, call); 78512099Sjoerg if (t1 != PTR || (hflag && t2 != VOID)) 78612099Sjoerg inconarg(hte, call, n); 78712099Sjoerg } else if (fc == 'n') { 78812099Sjoerg if (fwidth || prec || alt || zero || sz == LDOUBLE) 78912099Sjoerg badfmt(hte, call); 79012099Sjoerg if (t1 != PTR) { 79112099Sjoerg inconarg(hte, call, n); 79212099Sjoerg } else if (sz == LONG) { 79312099Sjoerg if (t2 != LONG && t2 != ULONG) 79412099Sjoerg inconarg(hte, call, n); 79512099Sjoerg } else if (sz == SHORT) { 79612099Sjoerg if (t2 != SHORT && t2 != USHORT) 79712099Sjoerg inconarg(hte, call, n); 79812099Sjoerg } else { 79912099Sjoerg if (t2 != INT && t2 != UINT) 80012099Sjoerg inconarg(hte, call, n); 80112099Sjoerg } 80212099Sjoerg } else { 80312099Sjoerg badfmt(hte, call); 80412099Sjoerg break; 80512099Sjoerg } 80612099Sjoerg 80712099Sjoerg fc = *fp++; 80812099Sjoerg } 80912099Sjoerg} 81012099Sjoerg 81112099Sjoerg/* 81212099Sjoerg * Compare the types in the NULL-terminated array ap with the format 81312099Sjoerg * string fmt. 81412099Sjoerg */ 81512099Sjoergstatic void 81691586Smarkmscanflike(hte_t *hte, fcall_t *call, int n, const char *fmt, type_t **ap) 81712099Sjoerg{ 81812099Sjoerg const char *fp; 81912099Sjoerg int fc; 82012099Sjoerg int noasgn, fwidth; 82191586Smarkm tspec_t sz, t1 = NOTSPEC, t2 = NOTSPEC; 82291586Smarkm type_t *tp = NULL; 82312099Sjoerg 82412099Sjoerg fp = fmt; 82512099Sjoerg fc = *fp++; 82612099Sjoerg 82712099Sjoerg for ( ; ; ) { 82812099Sjoerg if (fc == '\0') { 82912099Sjoerg if (*ap != NULL) 83012099Sjoerg tomanyarg(hte, call); 83112099Sjoerg break; 83212099Sjoerg } 83312099Sjoerg if (fc != '%') { 83412099Sjoerg badfmt(hte, call); 83512099Sjoerg break; 83612099Sjoerg } 83712099Sjoerg fc = *fp++; 83812099Sjoerg 83912099Sjoerg noasgn = fwidth = 0; 84012099Sjoerg sz = NOTSPEC; 84112099Sjoerg 84212099Sjoerg if (fc == '*') { 84312099Sjoerg noasgn = 1; 84412099Sjoerg fc = *fp++; 84512099Sjoerg } 84691586Smarkm 84712099Sjoerg if (isdigit(fc)) { 84812099Sjoerg fwidth = 1; 84912099Sjoerg do { fc = *fp++; } while (isdigit(fc)); 85012099Sjoerg } 85112099Sjoerg 85212099Sjoerg if (fc == 'h') { 85312099Sjoerg sz = SHORT; 85412099Sjoerg } else if (fc == 'l') { 85512099Sjoerg sz = LONG; 85612099Sjoerg } else if (fc == 'q') { 85712099Sjoerg sz = QUAD; 85812099Sjoerg } else if (fc == 'L') { 85912099Sjoerg sz = LDOUBLE; 86012099Sjoerg } 86112099Sjoerg if (sz != NOTSPEC) 86212099Sjoerg fc = *fp++; 86312099Sjoerg 86412099Sjoerg if (fc == '%') { 86512099Sjoerg if (sz != NOTSPEC || noasgn || fwidth) 86612099Sjoerg badfmt(hte, call); 86712099Sjoerg fc = *fp++; 86812099Sjoerg continue; 86912099Sjoerg } 87012099Sjoerg 87112099Sjoerg if (!noasgn) { 87212099Sjoerg if ((tp = *ap++) == NULL) { 87312099Sjoerg tofewarg(hte, call); 87412099Sjoerg break; 87512099Sjoerg } 87612099Sjoerg n++; 87712099Sjoerg if ((t1 = tp->t_tspec) == PTR) 87812099Sjoerg t2 = tp->t_subt->t_tspec; 87912099Sjoerg } 88012099Sjoerg 88112099Sjoerg if (fc == 'd' || fc == 'i' || fc == 'n') { 88212099Sjoerg if (sz == LDOUBLE) 88312099Sjoerg badfmt(hte, call); 88412099Sjoerg if (sz != SHORT && sz != LONG && sz != QUAD) 88512099Sjoerg sz = INT; 88612099Sjoerg conv: 88712099Sjoerg if (!noasgn) { 88812099Sjoerg if (t1 != PTR) { 88912099Sjoerg inconarg(hte, call, n); 89012099Sjoerg } else if (t2 != styp(sz)) { 89112099Sjoerg inconarg(hte, call, n); 89212099Sjoerg } else if (hflag && t2 != sz) { 89312099Sjoerg inconarg(hte, call, n); 89412099Sjoerg } else if (tp->t_subt->t_const) { 89512099Sjoerg inconarg(hte, call, n); 89612099Sjoerg } 89712099Sjoerg } 89812099Sjoerg } else if (fc == 'o' || fc == 'u' || fc == 'x') { 89912099Sjoerg if (sz == LDOUBLE) 90012099Sjoerg badfmt(hte, call); 90112099Sjoerg if (sz == SHORT) { 90212099Sjoerg sz = USHORT; 90312099Sjoerg } else if (sz == LONG) { 90412099Sjoerg sz = ULONG; 90512099Sjoerg } else if (sz == QUAD) { 90612099Sjoerg sz = UQUAD; 90712099Sjoerg } else { 90812099Sjoerg sz = UINT; 90912099Sjoerg } 91012099Sjoerg goto conv; 91112099Sjoerg } else if (fc == 'D') { 91212099Sjoerg if (sz != NOTSPEC || !tflag) 91312099Sjoerg badfmt(hte, call); 91412099Sjoerg sz = LONG; 91512099Sjoerg goto conv; 91612099Sjoerg } else if (fc == 'O') { 91712099Sjoerg if (sz != NOTSPEC || !tflag) 91812099Sjoerg badfmt(hte, call); 91912099Sjoerg sz = ULONG; 92012099Sjoerg goto conv; 92112099Sjoerg } else if (fc == 'X') { 92212099Sjoerg /* 92312099Sjoerg * XXX valid in ANSI C, but in NetBSD's libc imple- 92412099Sjoerg * mented as "lx". Thats why it should be avoided. 92512099Sjoerg */ 92612099Sjoerg if (sz != NOTSPEC || !tflag) 92712099Sjoerg badfmt(hte, call); 92812099Sjoerg sz = ULONG; 92912099Sjoerg goto conv; 93012099Sjoerg } else if (fc == 'E') { 93112099Sjoerg /* 93212099Sjoerg * XXX valid in ANSI C, but in NetBSD's libc imple- 93312099Sjoerg * mented as "lf". Thats why it should be avoided. 93412099Sjoerg */ 93512099Sjoerg if (sz != NOTSPEC || !tflag) 93612099Sjoerg badfmt(hte, call); 93712099Sjoerg sz = DOUBLE; 93812099Sjoerg goto conv; 93912099Sjoerg } else if (fc == 'F') { 94012099Sjoerg /* XXX only for backward compatibility */ 94112099Sjoerg if (sz != NOTSPEC || !tflag) 94212099Sjoerg badfmt(hte, call); 94312099Sjoerg sz = DOUBLE; 94412099Sjoerg goto conv; 94512099Sjoerg } else if (fc == 'G') { 94612099Sjoerg /* 94712099Sjoerg * XXX valid in ANSI C, but in NetBSD's libc not 94812099Sjoerg * implemented 94912099Sjoerg */ 95012099Sjoerg if (sz != NOTSPEC && sz != LONG && sz != LDOUBLE) 95112099Sjoerg badfmt(hte, call); 95212099Sjoerg goto fconv; 95312099Sjoerg } else if (fc == 'e' || fc == 'f' || fc == 'g') { 95412099Sjoerg fconv: 95512099Sjoerg if (sz == NOTSPEC) { 95612099Sjoerg sz = FLOAT; 95712099Sjoerg } else if (sz == LONG) { 95812099Sjoerg sz = DOUBLE; 95912099Sjoerg } else if (sz != LDOUBLE) { 96012099Sjoerg badfmt(hte, call); 96112099Sjoerg sz = FLOAT; 96212099Sjoerg } 96312099Sjoerg goto conv; 96412099Sjoerg } else if (fc == 's' || fc == '[' || fc == 'c') { 96512099Sjoerg if (sz != NOTSPEC) 96612099Sjoerg badfmt(hte, call); 96712099Sjoerg if (fc == '[') { 96812099Sjoerg if ((fc = *fp++) == '-') { 96912099Sjoerg badfmt(hte, call); 97012099Sjoerg fc = *fp++; 97112099Sjoerg } 97212099Sjoerg if (fc != ']') { 97312099Sjoerg badfmt(hte, call); 97412099Sjoerg if (fc == '\0') 97512099Sjoerg break; 97612099Sjoerg } 97712099Sjoerg } 97812099Sjoerg if (!noasgn) { 97912099Sjoerg if (t1 != PTR) { 98012099Sjoerg inconarg(hte, call, n); 98112099Sjoerg } else if (t2 != CHAR && t2 != UCHAR && 98212099Sjoerg t2 != SCHAR) { 98312099Sjoerg inconarg(hte, call, n); 98412099Sjoerg } 98512099Sjoerg } 98612099Sjoerg } else if (fc == 'p') { 98712099Sjoerg if (sz != NOTSPEC) 98812099Sjoerg badfmt(hte, call); 98912099Sjoerg if (!noasgn) { 99012099Sjoerg if (t1 != PTR || t2 != PTR) { 99112099Sjoerg inconarg(hte, call, n); 99212099Sjoerg } else if (tp->t_subt->t_subt->t_tspec!=VOID) { 99312099Sjoerg if (hflag) 99412099Sjoerg inconarg(hte, call, n); 99512099Sjoerg } 99612099Sjoerg } 99712099Sjoerg } else { 99812099Sjoerg badfmt(hte, call); 99912099Sjoerg break; 100012099Sjoerg } 100112099Sjoerg 100212099Sjoerg fc = *fp++; 100312099Sjoerg } 100412099Sjoerg} 100512099Sjoerg 100612099Sjoergstatic void 100791586Smarkmbadfmt(hte_t *hte, fcall_t *call) 100812099Sjoerg{ 100991586Smarkm 101012099Sjoerg /* %s: malformed format string\t%s */ 101112099Sjoerg msg(13, hte->h_name, mkpos(&call->f_pos)); 101212099Sjoerg} 101312099Sjoerg 101412099Sjoergstatic void 101591586Smarkminconarg(hte_t *hte, fcall_t *call, int n) 101612099Sjoerg{ 101791586Smarkm 101812099Sjoerg /* %s, arg %d inconsistent with format\t%s(%d) */ 101912099Sjoerg msg(14, hte->h_name, n, mkpos(&call->f_pos)); 102012099Sjoerg} 102112099Sjoerg 102212099Sjoergstatic void 102391586Smarkmtofewarg(hte_t *hte, fcall_t *call) 102412099Sjoerg{ 102591586Smarkm 102612099Sjoerg /* %s: too few args for format \t%s */ 102712099Sjoerg msg(15, hte->h_name, mkpos(&call->f_pos)); 102812099Sjoerg} 102912099Sjoerg 103012099Sjoergstatic void 103191586Smarkmtomanyarg(hte_t *hte, fcall_t *call) 103212099Sjoerg{ 103391586Smarkm 103412099Sjoerg /* %s: too many args for format \t%s */ 103512099Sjoerg msg(16, hte->h_name, mkpos(&call->f_pos)); 103612099Sjoerg} 103712099Sjoerg 103812099Sjoerg 103912099Sjoerg/* 104012099Sjoerg * Print warnings for return values which are used, but not returned, 104112099Sjoerg * or return values which are always or sometimes ignored. 104212099Sjoerg */ 104312099Sjoergstatic void 104491586Smarkmchkrvu(hte_t *hte, sym_t *def) 104512099Sjoerg{ 104612099Sjoerg fcall_t *call; 104712099Sjoerg int used, ignored; 104812099Sjoerg 104912099Sjoerg if (def == NULL) 105012099Sjoerg /* don't know wheter or not the functions returns a value */ 105112099Sjoerg return; 105212099Sjoerg 105312099Sjoerg if (hte->h_calls == NULL) 105412099Sjoerg return; 105512099Sjoerg 105612099Sjoerg if (def->s_rval) { 105712099Sjoerg /* function has return value */ 105812099Sjoerg used = ignored = 0; 105912099Sjoerg for (call = hte->h_calls; call != NULL; call = call->f_nxt) { 106091586Smarkm used |= call->f_rused || call->f_rdisc; 106112099Sjoerg ignored |= !call->f_rused && !call->f_rdisc; 106212099Sjoerg } 106312099Sjoerg /* 106412099Sjoerg * XXX as soon as we are able to disable single warnings 106512099Sjoerg * the following dependencies from hflag should be removed. 106612099Sjoerg * but for now I do'nt want to be botherd by this warnings 106712099Sjoerg * which are almost always useless. 106812099Sjoerg */ 106912099Sjoerg if (!used && ignored) { 107012099Sjoerg if (hflag) 107112099Sjoerg /* %s returns value which is always ignored */ 107212099Sjoerg msg(8, hte->h_name); 107312099Sjoerg } else if (used && ignored) { 107412099Sjoerg if (hflag) 107512099Sjoerg /* %s returns value which is sometimes ign. */ 107612099Sjoerg msg(9, hte->h_name); 107712099Sjoerg } 107812099Sjoerg } else { 107912099Sjoerg /* function has no return value */ 108012099Sjoerg for (call = hte->h_calls; call != NULL; call = call->f_nxt) { 108112099Sjoerg if (call->f_rused) 108212099Sjoerg /* %s value is used( %s ), but none ret. */ 108312099Sjoerg msg(10, hte->h_name, mkpos(&call->f_pos)); 108412099Sjoerg } 108512099Sjoerg } 108612099Sjoerg} 108712099Sjoerg 108812099Sjoerg/* 108912099Sjoerg * Print warnings for inconsistent argument declarations. 109012099Sjoerg */ 109112099Sjoergstatic void 109291586Smarkmchkadecl(hte_t *hte, sym_t *def, sym_t *decl) 109312099Sjoerg{ 109412099Sjoerg /* LINTED (automatic hides external declaration: warn) */ 109512099Sjoerg int osdef, eq, warn, n; 109612099Sjoerg sym_t *sym1, *sym; 109712099Sjoerg type_t **ap1, **ap2, *tp1, *tp2; 109812099Sjoerg char *pos1; 109912099Sjoerg const char *pos2; 110012099Sjoerg 110112099Sjoerg osdef = 0; 110212099Sjoerg if (def != NULL) { 110312099Sjoerg osdef = def->s_osdef; 110412099Sjoerg sym1 = def; 110512099Sjoerg } else if (decl != NULL && TP(decl->s_type)->t_proto) { 110612099Sjoerg sym1 = decl; 110712099Sjoerg } else { 110812099Sjoerg return; 110912099Sjoerg } 111012099Sjoerg if (TP(sym1->s_type)->t_tspec != FUNC) 111112099Sjoerg return; 111212099Sjoerg 111312099Sjoerg /* 111412099Sjoerg * XXX Prototypes should also be compared with old style function 111512099Sjoerg * declarations. 111612099Sjoerg */ 111712099Sjoerg 111812099Sjoerg for (sym = hte->h_syms; sym != NULL; sym = sym->s_nxt) { 111912099Sjoerg if (sym == sym1 || !TP(sym->s_type)->t_proto) 112012099Sjoerg continue; 112112099Sjoerg ap1 = TP(sym1->s_type)->t_args; 112212099Sjoerg ap2 = TP(sym->s_type)->t_args; 112312099Sjoerg n = 0; 112412099Sjoerg while (*ap1 != NULL && *ap2 != NULL) { 112512099Sjoerg warn = 0; 112612099Sjoerg eq = eqtype(*ap1, *ap2, 1, osdef, 0, &warn); 112712099Sjoerg if (!eq || warn) { 112812099Sjoerg pos1 = xstrdup(mkpos(&sym1->s_pos)); 112912099Sjoerg pos2 = mkpos(&sym->s_pos); 113012099Sjoerg /* %s, arg %d declared inconsistently ... */ 113112099Sjoerg msg(11, hte->h_name, n + 1, pos1, pos2); 113212099Sjoerg free(pos1); 113312099Sjoerg } 113412099Sjoerg n++; 113512099Sjoerg ap1++; 113612099Sjoerg ap2++; 113712099Sjoerg } 113812099Sjoerg if (*ap1 == *ap2) { 113912099Sjoerg tp1 = TP(sym1->s_type); 114012099Sjoerg tp2 = TP(sym->s_type); 114112099Sjoerg if (tp1->t_vararg == tp2->t_vararg) 114212099Sjoerg continue; 114312099Sjoerg if (tp2->t_vararg && 114412099Sjoerg sym1->s_va && sym1->s_nva == n && !sflag) { 114512099Sjoerg continue; 114612099Sjoerg } 114712099Sjoerg } 114812099Sjoerg /* %s: variable # of args declared\t%s :: %s */ 114912099Sjoerg pos1 = xstrdup(mkpos(&sym1->s_pos)); 115012099Sjoerg msg(12, hte->h_name, pos1, mkpos(&sym->s_pos)); 115112099Sjoerg free(pos1); 115212099Sjoerg } 115312099Sjoerg} 115412099Sjoerg 115512099Sjoerg 115612099Sjoerg/* 115712099Sjoerg * Check compatibility of two types. Returns 1 if types are compatible, 115812099Sjoerg * otherwise 0. 115912099Sjoerg * 116012099Sjoerg * ignqual if set, ignore qualifiers of outhermost type; used for 116112099Sjoerg * function arguments 116291586Smarkm * promote if set, promote left type before comparison; used for 116391586Smarkm * comparisons of arguments with parameters of old style 116412099Sjoerg * definitions 116512099Sjoerg * asgn left indirected type must have at least the same qualifiers 116612099Sjoerg * like right indirected type (for assignments and function 116712099Sjoerg * arguments) 116812099Sjoerg * *warn set to 1 if an old style declaration was compared with 116912099Sjoerg * an incompatible prototype declaration 117012099Sjoerg */ 117112099Sjoergstatic int 117291586Smarkmeqtype(type_t *tp1, type_t *tp2, int ignqual, int promot, int asgn, int *warn) 117312099Sjoerg{ 117412099Sjoerg tspec_t t, to; 117512099Sjoerg int indir; 117612099Sjoerg 117712099Sjoerg to = NOTSPEC; 117812099Sjoerg indir = 0; 117912099Sjoerg 118012099Sjoerg while (tp1 != NULL && tp2 != NULL) { 118112099Sjoerg 118212099Sjoerg t = tp1->t_tspec; 118312099Sjoerg if (promot) { 118412099Sjoerg if (t == FLOAT) { 118512099Sjoerg t = DOUBLE; 118612099Sjoerg } else if (t == CHAR || t == SCHAR) { 118712099Sjoerg t = INT; 118812099Sjoerg } else if (t == UCHAR) { 118912099Sjoerg t = tflag ? UINT : INT; 119012099Sjoerg } else if (t == SHORT) { 119112099Sjoerg t = INT; 119212099Sjoerg } else if (t == USHORT) { 119312099Sjoerg /* CONSTCOND */ 119412099Sjoerg t = INT_MAX < USHRT_MAX || tflag ? UINT : INT; 119512099Sjoerg } 119612099Sjoerg } 119712099Sjoerg 119812099Sjoerg if (asgn && to == PTR) { 119912099Sjoerg if (indir == 1 && (t == VOID || tp2->t_tspec == VOID)) 120012099Sjoerg return (1); 120112099Sjoerg } 120291586Smarkm 120312099Sjoerg if (t != tp2->t_tspec) { 120412099Sjoerg /* 120512099Sjoerg * Give pointer to types which differ only in 120612099Sjoerg * signedness a chance if not sflag and not hflag. 120712099Sjoerg */ 120812099Sjoerg if (sflag || hflag || to != PTR) 120912099Sjoerg return (0); 121012099Sjoerg if (styp(t) != styp(tp2->t_tspec)) 121112099Sjoerg return (0); 121212099Sjoerg } 121312099Sjoerg 121412099Sjoerg if (tp1->t_isenum && tp2->t_isenum) { 121512099Sjoerg if (tp1->t_istag && tp2->t_istag) { 121612099Sjoerg return (tp1->t_tag == tp2->t_tag); 121712099Sjoerg } else if (tp1->t_istynam && tp2->t_istynam) { 121812099Sjoerg return (tp1->t_tynam == tp2->t_tynam); 121991586Smarkm } else if (tp1->t_isuniqpos && tp2->t_isuniqpos) { 122091586Smarkm return (tp1->t_uniqpos.p_line == 122191586Smarkm tp2->t_uniqpos.p_line && 122291586Smarkm tp1->t_uniqpos.p_file == 122391586Smarkm tp2->t_uniqpos.p_file && 122491586Smarkm tp1->t_uniqpos.p_uniq == 122591586Smarkm tp2->t_uniqpos.p_uniq); 122612099Sjoerg } else { 122712099Sjoerg return (0); 122812099Sjoerg } 122912099Sjoerg } 123012099Sjoerg 123112099Sjoerg /* 123212099Sjoerg * XXX Handle combinations of enum and int if eflag is set. 123312099Sjoerg * But note: enum and 0 should be allowed. 123412099Sjoerg */ 123512099Sjoerg 123612099Sjoerg if (asgn && indir == 1) { 123712099Sjoerg if (!tp1->t_const && tp2->t_const) 123812099Sjoerg return (0); 123912099Sjoerg if (!tp1->t_volatile && tp2->t_volatile) 124012099Sjoerg return (0); 124112099Sjoerg } else if (!ignqual && !tflag) { 124212099Sjoerg if (tp1->t_const != tp2->t_const) 124312099Sjoerg return (0); 124412099Sjoerg if (tp1->t_const != tp2->t_const) 124512099Sjoerg return (0); 124612099Sjoerg } 124712099Sjoerg 124812099Sjoerg if (t == STRUCT || t == UNION) { 124912099Sjoerg if (tp1->t_istag && tp2->t_istag) { 125012099Sjoerg return (tp1->t_tag == tp2->t_tag); 125112099Sjoerg } else if (tp1->t_istynam && tp2->t_istynam) { 125212099Sjoerg return (tp1->t_tynam == tp2->t_tynam); 125391586Smarkm } else if (tp1->t_isuniqpos && tp2->t_isuniqpos) { 125491586Smarkm return (tp1->t_uniqpos.p_line == 125591586Smarkm tp2->t_uniqpos.p_line && 125691586Smarkm tp1->t_uniqpos.p_file == 125791586Smarkm tp2->t_uniqpos.p_file && 125891586Smarkm tp1->t_uniqpos.p_uniq == 125991586Smarkm tp2->t_uniqpos.p_uniq); 126012099Sjoerg } else { 126112099Sjoerg return (0); 126212099Sjoerg } 126312099Sjoerg } 126412099Sjoerg 126512099Sjoerg if (t == ARRAY && tp1->t_dim != tp2->t_dim) { 126612099Sjoerg if (tp1->t_dim != 0 && tp2->t_dim != 0) 126712099Sjoerg return (0); 126812099Sjoerg } 126912099Sjoerg 127012099Sjoerg if (t == FUNC) { 127112099Sjoerg if (tp1->t_proto && tp2->t_proto) { 127212099Sjoerg if (!eqargs(tp1, tp2, warn)) 127312099Sjoerg return (0); 127412099Sjoerg } else if (tp1->t_proto) { 127512099Sjoerg if (!mnoarg(tp1, warn)) 127612099Sjoerg return (0); 127712099Sjoerg } else if (tp2->t_proto) { 127812099Sjoerg if (!mnoarg(tp2, warn)) 127912099Sjoerg return (0); 128012099Sjoerg } 128112099Sjoerg } 128212099Sjoerg 128312099Sjoerg tp1 = tp1->t_subt; 128412099Sjoerg tp2 = tp2->t_subt; 128512099Sjoerg ignqual = promot = 0; 128612099Sjoerg to = t; 128712099Sjoerg indir++; 128812099Sjoerg 128912099Sjoerg } 129012099Sjoerg 129112099Sjoerg return (tp1 == tp2); 129212099Sjoerg} 129312099Sjoerg 129412099Sjoerg/* 129512099Sjoerg * Compares arguments of two prototypes 129612099Sjoerg */ 129712099Sjoergstatic int 129891586Smarkmeqargs(type_t *tp1, type_t *tp2, int *warn) 129912099Sjoerg{ 130012099Sjoerg type_t **a1, **a2; 130112099Sjoerg 130212099Sjoerg if (tp1->t_vararg != tp2->t_vararg) 130312099Sjoerg return (0); 130412099Sjoerg 130512099Sjoerg a1 = tp1->t_args; 130612099Sjoerg a2 = tp2->t_args; 130712099Sjoerg 130812099Sjoerg while (*a1 != NULL && *a2 != NULL) { 130912099Sjoerg 131012099Sjoerg if (eqtype(*a1, *a2, 1, 0, 0, warn) == 0) 131112099Sjoerg return (0); 131212099Sjoerg 131312099Sjoerg a1++; 131412099Sjoerg a2++; 131512099Sjoerg 131612099Sjoerg } 131712099Sjoerg 131812099Sjoerg return (*a1 == *a2); 131912099Sjoerg} 132012099Sjoerg 132112099Sjoerg/* 132212099Sjoerg * mnoarg() (matches functions with no argument type information) 132312099Sjoerg * returns 1 if all parameters of a prototype are compatible with 132412099Sjoerg * and old style function declaration. 132512099Sjoerg * This is the case if following conditions are met: 132612099Sjoerg * 1. the prototype must have a fixed number of parameters 132712099Sjoerg * 2. no parameter is of type float 132812099Sjoerg * 3. no parameter is converted to another type if integer promotion 132912099Sjoerg * is applied on it 133012099Sjoerg */ 133112099Sjoergstatic int 133291586Smarkmmnoarg(type_t *tp, int *warn) 133312099Sjoerg{ 133412099Sjoerg type_t **arg; 133512099Sjoerg tspec_t t; 133612099Sjoerg 133712099Sjoerg if (tp->t_vararg && warn != NULL) 133812099Sjoerg *warn = 1; 133912099Sjoerg for (arg = tp->t_args; *arg != NULL; arg++) { 134012099Sjoerg if ((t = (*arg)->t_tspec) == FLOAT) 134112099Sjoerg return (0); 134212099Sjoerg if (t == CHAR || t == SCHAR || t == UCHAR) 134312099Sjoerg return (0); 134412099Sjoerg if (t == SHORT || t == USHORT) 134512099Sjoerg return (0); 134612099Sjoerg } 134712099Sjoerg return (1); 134812099Sjoerg} 1349