shithub: scc

Download patch

ref: 609bb6b7743e8a37538a2701df3aaa3b652ebfb7
parent: 10faf603cace3ffda21153466dfbd9e672bcf656
author: Roberto E. Vargas Caballero <[email protected]>
date: Mon Sep 7 12:31:39 EDT 2015

Add correct parsing of integer constants

Until this moment there was no check of overflow, and there was no
cast to bigger types when the constant was bigger than the type declared by
the user.

--- a/cc1/fold.c
+++ b/cc1/fold.c
@@ -507,6 +507,7 @@
 Node *
 castcode(Node *np, Type *newtp)
 {
+	TUINT mask;
 	Type *oldtp = np->type;
 	Symbol aux, *sym, *osym = np->sym;
 
@@ -517,6 +518,7 @@
 	case PTR:
 	case INT:
 	case ENUM:
+		mask = ones(newtp->size);
 		switch (oldtp->op) {
 		case PTR:
 		case INT:
@@ -524,15 +526,18 @@
 			if (newtp->sign == oldtp->sign)
 				aux.u = osym->u;
 			if (newtp->sign && !oldtp->sign)
-				aux.u.i = osym->u.u;
+				aux.u.i = osym->u.u & mask;
 			else if (!newtp->sign && oldtp->sign)
-				aux.u.u = osym->u.u;
+				aux.u.u = osym->u.u & mask;
 			break;
 		case FLOAT:
-			if (newtp->sign)
+			if (newtp->sign) {
 				aux.u.i = osym->u.f;
-			else
+				aux.u.i &= mask;
+			} else {
 				aux.u.u = osym->u.f;
+				aux.u.u &= mask;
+			}
 			break;
 		default:
 			goto noconstant;
@@ -539,6 +544,7 @@
 		}
 		break;
 	case FLOAT:
+		/* FIXME: The cast can be from another floar type */
 		aux.u.f = (oldtp->sign) ? osym->u.i : osym->u.u;
 		break;
 	default:
--- a/cc1/lex.c
+++ b/cc1/lex.c
@@ -201,6 +201,55 @@
 	input->begin = input->p;
 }
 
+static Symbol *
+readint(char *s, int base, Symbol *sym)
+{
+	Type *tp = sym->type;
+	struct limits *lim = getlimits(tp);
+	TUINT u, val, max, factor = 1;
+	int c;
+
+	max = (tp->sign) ? lim->max.u : lim->max.i;
+	switch (*s++) {
+	case '-': factor = -1; break;
+	default: --s;
+	case '+': factor = 1; break;
+	}
+
+	for (u = 0; isxdigit(c = *s++); u = u * base + val) {
+		val = (c <= '9') ? c - '0' :  10 + c - 'A';
+		if (u <= max/base + val)
+			continue;
+		if (tp->sign) {
+			if (tp == inttype)
+				tp = longtype;
+			else if (tp == longtype)
+				tp == llongtype;
+			else {
+				errorp("overflow in integer constant");
+				break;
+			}
+		} else {
+			if (tp == uinttype)
+				tp = ulongtype;
+			else if (tp == ulongtype)
+				tp == ullongtype;
+			else {
+				errorp("overflow in integer constant");
+				break;
+			}
+		}
+		sym->type = tp;
+	}
+
+	if (tp->sign)
+		sym->u.i = u * factor;
+	else
+		sym->u.u = u;
+
+	return sym;
+}
+
 static unsigned
 integer(char *s, char base)
 {
@@ -233,10 +282,7 @@
 	sym = newsym(NS_IDEN);
 	sym->type = tp;
 	sym->flags |= ISCONSTANT;
-	v = strtol(s, NULL, base);
-	if (tp == inttype)
-		sym->u.i = v;
-	yylval.sym = sym;
+	yylval.sym = readint(s, base, sym);
 	return CONSTANT;
 }
 
--- a/cc1/types.c
+++ b/cc1/types.c
@@ -17,24 +17,6 @@
  */
 static struct limits limits[][4] = {
 	{
-		{	/* 0 = signed 1 byte */
-			.min.i = -127,
-			.max.i = 127
-		},
-		{	/* 1 = signed 2 byte */
-			.min.i = -32767,
-			.max.i = 327677
-		},
-		{	/* 2 = signed 4 byte */
-			.min.i = -2147483647L,
-			.max.i = 2147483647L
-		},
-		{	/* 3 = signed 8 byte */
-			.min.i = -9223372036854775807LL,
-			.max.i = 9223372036854775807LL,
-		}
-	},
-	{
 		{	/* 0 = unsigned 1 byte */
 			.min.u = 0,
 			.max.u = 255
@@ -50,6 +32,24 @@
 		{	/* 3 = unsigned 4 bytes */
 			.min.u = 0,
 			.max.u = 18446744073709551615u
+		}
+	},
+	{
+		{	/* 0 = signed 1 byte */
+			.min.i = -127,
+			.max.i = 127
+		},
+		{	/* 1 = signed 2 byte */
+			.min.i = -32767,
+			.max.i = 32767
+		},
+		{	/* 2 = signed 4 byte */
+			.min.i = -2147483647L,
+			.max.i = 2147483647L
+		},
+		{	/* 3 = signed 8 byte */
+			.min.i = -9223372036854775807LL,
+			.max.i = 9223372036854775807LL,
 		}
 	},
 	{