shithub: scc

Download patch

ref: 42fd6480b200aab21dc5118050b8f4753cd25967
parent: bcc4de52e4e216a3b5a9d734fed46a4d06c3252c
author: Roberto E. Vargas Caballero <[email protected]>
date: Wed Sep 2 07:41:05 EDT 2015

Add validation for float operations

--- a/cc1/fold.c
+++ b/cc1/fold.c
@@ -23,6 +23,24 @@
 }
 
 static bool
+addf(TFLOAT l, TFLOAT r, Type *tp)
+{
+	struct limits *lim = getlimits(tp);
+	TFLOAT max = lim->max.f, min = lim->min.f;
+
+	if (l < 0 && r < 0 && l >= min - r ||
+	    l == 0 ||
+	    r == 0 ||
+	    l < 0 && r > 0 ||
+	    l > 0 && r < 0 ||
+	    l > 0 && r > 0 && l <= max - r) {
+		return 1;
+	}
+	warn("overflow in constant expression");
+	return 0;
+}
+
+static bool
 subi(TINT l, TINT r, Type *tp)
 {
 	return addi(l, -r, tp);
@@ -29,6 +47,12 @@
 }
 
 static bool
+subf(TFLOAT l, TFLOAT r, Type *tp)
+{
+	return addf(l, -r, tp);
+}
+
+static bool
 muli(TINT l, TINT r, Type *tp)
 {
 	struct limits *lim = getlimits(tp);
@@ -47,6 +71,24 @@
 }
 
 static bool
+mulf(TFLOAT l, TFLOAT r, Type *tp)
+{
+	struct limits *lim = getlimits(tp);
+	TFLOAT max = lim->max.i, min = lim->min.i;
+
+	if (l > -1 && l <= 1 ||
+	    r > -1 && r <= 1 ||
+	    l < 0 && r < 0 && -l <= max/-r ||
+	    l < 0 && r > 0 &&  l >= min/r  ||
+	    l > 0 && r < 0 &&  r >= min/l  ||
+	    l > 0 && r > 0 &&  l <= max/r) {
+			return 1;
+	}
+	warn("overflow in constant expression");
+	return 0;
+}
+
+static bool
 divi(TINT l, TINT r,  Type *tp)
 {
 	struct limits *lim = getlimits(tp);
@@ -63,6 +105,25 @@
 }
 
 static bool
+divf(TFLOAT l, TFLOAT r,  Type *tp)
+{
+	struct limits *lim = getlimits(tp);
+
+	if (l < 0) l = -l;
+	if (r < 0) r = -r;
+
+	if (r == 0.0) {
+		warn("division by 0");
+		return 0;
+	}
+	if (r < 1.0 && l > lim->max.f * r) {
+		warn("overflow in constant expression");
+		return 0;
+	}
+	return 1;
+}
+
+static bool
 lshi(TINT l, TINT r, Type *tp)
 {
 	if (r < 0 || r >= tp->size * 8) {
@@ -174,6 +235,18 @@
 {
 	TFLOAT f;
 	TINT i;
+	bool (*validate)(TFLOAT, TFLOAT, Type *tp);
+
+	switch (op) {
+	case OADD: validate = addf; break;
+	case OSUB: validate = subf; break;
+	case OMUL: validate = mulf; break;
+	case ODIV: validate = divf; break;
+	default:   validate = NULL; break;
+	}
+
+	if (validate && !(*validate)(l, r, res->type))
+		return 0;
 
 	switch (op) {
 	case OADD: f = l + r;  break;