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:
rillig 2021-08-09 20:07:23 +00:00
parent d7fca1ab3d
commit 9cea3ffa32
6 changed files with 106 additions and 7 deletions

View File

@ -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

View File

@ -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>

View File

@ -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'));
}

View File

@ -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]

View File

@ -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 {

View File

@ -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;
}