aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2022-05-22 20:46:58 +0200
committerLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2022-05-31 13:49:29 +0200
commit3d1d65bfe6dad089b9c2a8d69f36ba5301a9509c (patch)
treef780af23ebc5de203303205323b33248d5b1be63
parent99a5645a0edbafac8eb667e0f341a73bebb5f34d (diff)
downloadsparse-3d1d65bfe6dad089b9c2a8d69f36ba5301a9509c.tar.gz
fix zero/sign extension of integer character constants
An integer character constant has type 'int' but, subtly enough, its value is the one of a 'char' converted to an 'int'. So, do this conversion. Also set the type of wide character constants from 'long' to 'wchar_t'. Link: https://lore.kernel.org/r/20210927130253.GH2083@kadam Reported-by: Dan Carpenter <dan.carpenter@oracle.com> Reported-by: Rasmus Villemoes <linux@rasmusvillemoes.dk> Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
-rw-r--r--expression.c10
-rw-r--r--validation/char-constant-signed.c9
-rw-r--r--validation/char-constant-unsigned.c9
3 files changed, 27 insertions, 1 deletions
diff --git a/expression.c b/expression.c
index 221d7780..efdaa367 100644
--- a/expression.c
+++ b/expression.c
@@ -427,8 +427,16 @@ struct token *primary_expression(struct token *token, struct expression **tree)
case TOKEN_CHAR ... TOKEN_WIDE_CHAR_EMBEDDED_3:
expr = alloc_expression(token->pos, EXPR_VALUE);
expr->flags = CEF_SET_CHAR;
- expr->ctype = token_type(token) < TOKEN_WIDE_CHAR ? &int_ctype : &long_ctype;
get_char_constant(token, &expr->value);
+
+ // TODO: handle 'u8', 'u' & 'U' prefixes.
+ if (token_type(token) < TOKEN_WIDE_CHAR) {
+ expr->ctype = &char_ctype;
+ cast_value(expr, &int_ctype, expr, expr->ctype);
+ expr->ctype = &int_ctype;
+ } else {
+ expr->ctype = wchar_ctype;
+ }
token = token->next;
break;
diff --git a/validation/char-constant-signed.c b/validation/char-constant-signed.c
new file mode 100644
index 00000000..be0fd5ce
--- /dev/null
+++ b/validation/char-constant-signed.c
@@ -0,0 +1,9 @@
+int test(void) { return '\377' == -1; }
+
+/*
+ * check-name: char-constant-signed
+ * check-command: test-linearize -Wno-decl -fsigned-char $file
+ *
+ * check-output-ignore
+ * check-output-returns: 1
+ */
diff --git a/validation/char-constant-unsigned.c b/validation/char-constant-unsigned.c
new file mode 100644
index 00000000..d5642b16
--- /dev/null
+++ b/validation/char-constant-unsigned.c
@@ -0,0 +1,9 @@
+int test(void) { return '\377' == 255; }
+
+/*
+ * check-name: char-constant-unsigned
+ * check-command: test-linearize -Wno-decl -funsigned-char $file
+ *
+ * check-output-ignore
+ * check-output-returns: 1
+ */