lint: warn about 'char * = strchr(const char *, int)'
Found in findcc.c, there are about 25 other instances of this incongruency in the whole source tree. For more examples of functions from the C Standard Library that implicitly remove the 'const' qualifier from an argument, see the C++ include file 'cstring'.
This commit is contained in:
parent
d7fca1ab3d
commit
9cea3ffa32
|
@ -1,4 +1,4 @@
|
|||
# $NetBSD: mi,v 1.1108 2021/08/08 00:02:02 rillig Exp $
|
||||
# $NetBSD: mi,v 1.1109 2021/08/09 20:07:23 rillig Exp $
|
||||
#
|
||||
# Note: don't delete entries from here - mark them as "obsolete" instead.
|
||||
#
|
||||
|
@ -7004,6 +7004,8 @@
|
|||
./usr/tests/usr.bin/xlint/lint1/msg_344.exp tests-usr.bin-tests compattestfile,atf
|
||||
./usr/tests/usr.bin/xlint/lint1/msg_345.c tests-usr.bin-tests compattestfile,atf
|
||||
./usr/tests/usr.bin/xlint/lint1/msg_345.exp tests-usr.bin-tests compattestfile,atf
|
||||
./usr/tests/usr.bin/xlint/lint1/msg_346.c tests-usr.bin-tests compattestfile,atf
|
||||
./usr/tests/usr.bin/xlint/lint1/msg_346.exp tests-usr.bin-tests compattestfile,atf
|
||||
./usr/tests/usr.bin/xlint/lint1/op_colon.c tests-usr.bin-tests compattestfile,atf
|
||||
./usr/tests/usr.bin/xlint/lint1/op_colon.exp tests-usr.bin-tests compattestfile,atf
|
||||
./usr/tests/usr.bin/xlint/lint1/op_shl_lp64.c tests-usr.bin-tests compattestfile,atf
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# $NetBSD: Makefile,v 1.102 2021/08/05 06:34:43 rillig Exp $
|
||||
# $NetBSD: Makefile,v 1.103 2021/08/09 20:07:24 rillig Exp $
|
||||
|
||||
NOMAN= # defined
|
||||
MAX_MESSAGE= 345 # see lint1/err.c
|
||||
MAX_MESSAGE= 346 # see lint1/err.c
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/* $NetBSD: msg_346.c,v 1.1 2021/08/09 20:07:24 rillig Exp $ */
|
||||
# 3 "msg_346.c"
|
||||
|
||||
// Test for message: call to '%s' effectively discards 'const' from argument [346]
|
||||
|
||||
char *strchr(const char *, int);
|
||||
|
||||
void take_const_char_ptr(const char *);
|
||||
void take_char_ptr(char *);
|
||||
|
||||
void
|
||||
example(void)
|
||||
{
|
||||
const char *ccp = "const char *";
|
||||
char *cp = "char *";
|
||||
|
||||
ccp = strchr(ccp, 'c');
|
||||
ccp = strchr(cp, 'c');
|
||||
/* expect+1: warning: call to 'strchr' effectively discards 'const' from argument [346] */
|
||||
cp = strchr(ccp, 'c');
|
||||
cp = strchr(cp, 'c');
|
||||
|
||||
take_const_char_ptr(strchr(ccp, 'c'));
|
||||
take_const_char_ptr(strchr(cp, 'c'));
|
||||
/* expect+1: warning: call to 'strchr' effectively discards 'const' from argument [346] */
|
||||
take_char_ptr(strchr(ccp, 'c'));
|
||||
take_char_ptr(strchr(cp, 'c'));
|
||||
|
||||
take_const_char_ptr(strchr("literal", 'c'));
|
||||
/* expect+1: warning: call to 'strchr' effectively discards 'const' from argument [346] */
|
||||
take_char_ptr(strchr("literal", 'c'));
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
msg_346.c(20): warning: call to 'strchr' effectively discards 'const' from argument [346]
|
||||
msg_346.c(26): warning: call to 'strchr' effectively discards 'const' from argument [346]
|
||||
msg_346.c(31): warning: call to 'strchr' effectively discards 'const' from argument [346]
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: err.c,v 1.134 2021/08/03 20:57:06 rillig Exp $ */
|
||||
/* $NetBSD: err.c,v 1.135 2021/08/09 20:07:23 rillig Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1994, 1995 Jochen Pohl
|
||||
|
@ -37,7 +37,7 @@
|
|||
|
||||
#include <sys/cdefs.h>
|
||||
#if defined(__RCSID) && !defined(lint)
|
||||
__RCSID("$NetBSD: err.c,v 1.134 2021/08/03 20:57:06 rillig Exp $");
|
||||
__RCSID("$NetBSD: err.c,v 1.135 2021/08/09 20:07:23 rillig Exp $");
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
|
@ -400,6 +400,7 @@ const char *const msgs[] = {
|
|||
"static array size is a C11 extension", /* 343 */
|
||||
"bit-field of type plain 'int' has implementation-defined signedness", /* 344 */
|
||||
"generic selection requires C11 or later", /* 345 */
|
||||
"call to '%s' effectively discards 'const' from argument", /* 346 */
|
||||
};
|
||||
|
||||
static struct include_level {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: tree.c,v 1.330 2021/08/03 21:09:26 rillig Exp $ */
|
||||
/* $NetBSD: tree.c,v 1.331 2021/08/09 20:07:23 rillig Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1994, 1995 Jochen Pohl
|
||||
|
@ -37,7 +37,7 @@
|
|||
|
||||
#include <sys/cdefs.h>
|
||||
#if defined(__RCSID) && !defined(lint)
|
||||
__RCSID("$NetBSD: tree.c,v 1.330 2021/08/03 21:09:26 rillig Exp $");
|
||||
__RCSID("$NetBSD: tree.c,v 1.331 2021/08/09 20:07:23 rillig Exp $");
|
||||
#endif
|
||||
|
||||
#include <float.h>
|
||||
|
@ -1346,6 +1346,63 @@ check_pointer_comparison(op_t op, const tnode_t *ln, const tnode_t *rn)
|
|||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
is_direct_function_call(const tnode_t *tn, const char *name)
|
||||
{
|
||||
return tn->tn_op == CALL &&
|
||||
tn->tn_left->tn_op == ADDR &&
|
||||
tn->tn_left->tn_left->tn_op == NAME &&
|
||||
strcmp(tn->tn_left->tn_left->tn_sym->s_name, name) == 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
is_const_char_pointer(const tnode_t *tn)
|
||||
{
|
||||
const type_t *tp;
|
||||
|
||||
/*
|
||||
* For traditional reasons, C99 6.4.5p5 defines that string literals
|
||||
* have type 'char[]'. They are often implicitly converted to
|
||||
* 'char *', for example when they are passed as function arguments.
|
||||
*
|
||||
* C99 6.4.5p6 further defines that modifying a string that is
|
||||
* constructed from a string literal invokes undefined behavior.
|
||||
*
|
||||
* Out of these reasons, string literals are treated as 'effectively
|
||||
* const' here.
|
||||
*/
|
||||
if (tn->tn_op == CVT &&
|
||||
tn->tn_left->tn_op == ADDR &&
|
||||
tn->tn_left->tn_left->tn_op == STRING)
|
||||
return true;
|
||||
|
||||
tp = before_conversion(tn)->tn_type;
|
||||
return tp->t_tspec == PTR &&
|
||||
tp->t_subt->t_tspec == CHAR &&
|
||||
tp->t_subt->t_const;
|
||||
}
|
||||
|
||||
static bool
|
||||
is_strchr_arg_const(const tnode_t *tn)
|
||||
{
|
||||
return tn->tn_right->tn_op == PUSH &&
|
||||
tn->tn_right->tn_right->tn_op == PUSH &&
|
||||
tn->tn_right->tn_right->tn_right == NULL &&
|
||||
is_const_char_pointer(tn->tn_right->tn_right->tn_left);
|
||||
}
|
||||
|
||||
static void
|
||||
check_unconst_strchr(const type_t *lstp,
|
||||
const tnode_t *rn, const type_t *rstp)
|
||||
{
|
||||
if (lstp->t_tspec == CHAR && !lstp->t_const &&
|
||||
is_direct_function_call(rn, "strchr") &&
|
||||
is_strchr_arg_const(rn)) {
|
||||
/* call to '%s' effectively discards 'const' from argument */
|
||||
warning(346, "strchr");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks type compatibility for ASSIGN, INIT, FARG and RETURN
|
||||
* and prints warnings/errors if necessary.
|
||||
|
@ -1429,6 +1486,10 @@ check_assign_types_compatible(op_t op, int arg,
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!tflag)
|
||||
check_unconst_strchr(lstp, rn, rstp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue