diff --git a/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.expected b/c/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.expected similarity index 99% rename from c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.expected rename to c/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.expected index 8dd5ac15b8..f3b94b6095 100644 --- a/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.expected +++ b/c/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.expected @@ -1,3 +1,30 @@ +problems +| test.c:12:8:12:9 | l2 | test.c:8:14:8:20 | ... / ... | test.c:12:8:12:9 | l2 | Possibly infinite float value $@ flows to divisor, which would silently underflow and produce zero. | test.c:8:14:8:20 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:13:8:13:9 | l3 | test.c:8:14:8:20 | ... / ... | test.c:13:8:13:9 | l3 | Possibly infinite float value $@ flows to divisor, which would silently underflow and produce zero. | test.c:8:14:8:20 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:18:8:18:9 | l2 | test.c:8:14:8:20 | ... / ... | test.c:18:3:18:9 | l2 | Possibly infinite float value $@ flows to cast to integer. | test.c:8:14:8:20 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:19:8:19:9 | l3 | test.c:8:14:8:20 | ... / ... | test.c:19:3:19:9 | l3 | Possibly infinite float value $@ flows to cast to integer. | test.c:8:14:8:20 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:27:19:27:20 | l2 | test.c:8:14:8:20 | ... / ... | test.c:27:19:27:20 | l2 | Possibly infinite float value $@ flows to divisor, which would silently underflow and produce zero. | test.c:8:14:8:20 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:28:19:28:20 | l3 | test.c:8:14:8:20 | ... / ... | test.c:28:19:28:20 | l3 | Possibly infinite float value $@ flows to divisor, which would silently underflow and produce zero. | test.c:8:14:8:20 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:38:8:38:9 | l7 | test.c:31:14:32:15 | ... / ... | test.c:38:3:38:9 | l7 | Possibly infinite float value $@ flows to cast to integer. | test.c:31:14:32:15 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:61:11:61:17 | ... / ... | test.c:61:5:61:18 | ... / ... | test.c:61:5:61:18 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.c:61:11:61:17 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:66:11:66:19 | ... / ... | test.c:66:5:66:20 | ... / ... | test.c:66:5:66:20 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.c:66:11:66:19 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:72:20:72:28 | ... / ... | test.c:72:14:72:29 | ... / ... | test.c:72:14:72:29 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.c:72:20:72:28 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:75:24:75:32 | ... / ... | test.c:75:18:75:33 | ... / ... | test.c:75:18:75:33 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.c:75:24:75:32 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:79:10:79:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:79:5:79:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:87:10:87:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:87:5:87:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:91:10:91:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:91:5:91:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:93:10:93:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:93:5:93:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:99:10:99:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:99:5:99:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:105:10:105:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:105:5:105:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:111:10:111:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:111:5:111:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:114:21:114:23 | l12 | test.c:77:15:77:21 | ... / ... | test.c:114:16:114:23 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:117:28:117:30 | l12 | test.c:77:15:77:21 | ... / ... | test.c:117:23:117:30 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:120:25:120:27 | l12 | test.c:77:15:77:21 | ... / ... | test.c:120:20:120:27 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:163:9:164:15 | ... / ... | test.c:163:3:164:16 | ... / ... | test.c:163:3:164:16 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.c:163:9:164:15 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:175:32:175:32 | p | test.c:189:51:189:59 | ... / ... | test.c:175:27:175:32 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.c:189:51:189:59 | ... / ... | from division by zero | test.c:189:6:189:24 | addInfThenCastToInt | addInfThenCastToInt | +| test.c:175:32:175:32 | p | test.c:193:13:194:15 | ... / ... | test.c:175:27:175:32 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.c:193:13:194:15 | ... / ... | from division by zero | test.c:192:6:192:7 | f2 | f2 | +| test.c:175:32:175:32 | p | test.c:204:19:204:27 | ... / ... | test.c:175:27:175:32 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.c:204:19:204:27 | ... / ... | from division by zero | test.c:192:6:192:7 | f2 | f2 | +| test.c:185:18:185:18 | p | test.c:200:25:200:33 | ... / ... | test.c:185:13:185:18 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.c:200:25:200:33 | ... / ... | from division by zero | test.c:192:6:192:7 | f2 | f2 | edges | test.c:8:14:8:20 | ... / ... | test.c:8:14:8:20 | ... / ... | provenance | | | test.c:8:14:8:20 | ... / ... | test.c:9:14:9:16 | - ... | provenance | Config | @@ -83,31 +110,4 @@ nodes | test.c:206:21:206:31 | ... + ... | semmle.label | ... + ... | | test.c:208:13:208:21 | middleInf | semmle.label | middleInf | | test.c:210:23:210:31 | middleInf | semmle.label | middleInf | -subpaths -#select -| test.c:12:8:12:9 | l2 | test.c:8:14:8:20 | ... / ... | test.c:12:8:12:9 | l2 | Possibly infinite float value $@ flows to divisor, which would silently underflow and produce zero. | test.c:8:14:8:20 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:13:8:13:9 | l3 | test.c:8:14:8:20 | ... / ... | test.c:13:8:13:9 | l3 | Possibly infinite float value $@ flows to divisor, which would silently underflow and produce zero. | test.c:8:14:8:20 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:18:8:18:9 | l2 | test.c:8:14:8:20 | ... / ... | test.c:18:3:18:9 | l2 | Possibly infinite float value $@ flows to cast to integer. | test.c:8:14:8:20 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:19:8:19:9 | l3 | test.c:8:14:8:20 | ... / ... | test.c:19:3:19:9 | l3 | Possibly infinite float value $@ flows to cast to integer. | test.c:8:14:8:20 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:27:19:27:20 | l2 | test.c:8:14:8:20 | ... / ... | test.c:27:19:27:20 | l2 | Possibly infinite float value $@ flows to divisor, which would silently underflow and produce zero. | test.c:8:14:8:20 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:28:19:28:20 | l3 | test.c:8:14:8:20 | ... / ... | test.c:28:19:28:20 | l3 | Possibly infinite float value $@ flows to divisor, which would silently underflow and produce zero. | test.c:8:14:8:20 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:38:8:38:9 | l7 | test.c:31:14:32:15 | ... / ... | test.c:38:3:38:9 | l7 | Possibly infinite float value $@ flows to cast to integer. | test.c:31:14:32:15 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:61:11:61:17 | ... / ... | test.c:61:5:61:18 | ... / ... | test.c:61:5:61:18 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.c:61:11:61:17 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:66:11:66:19 | ... / ... | test.c:66:5:66:20 | ... / ... | test.c:66:5:66:20 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.c:66:11:66:19 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:72:20:72:28 | ... / ... | test.c:72:14:72:29 | ... / ... | test.c:72:14:72:29 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.c:72:20:72:28 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:75:24:75:32 | ... / ... | test.c:75:18:75:33 | ... / ... | test.c:75:18:75:33 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.c:75:24:75:32 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:79:10:79:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:79:5:79:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:87:10:87:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:87:5:87:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:91:10:91:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:91:5:91:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:93:10:93:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:93:5:93:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:99:10:99:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:99:5:99:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:105:10:105:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:105:5:105:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:111:10:111:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:111:5:111:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:114:21:114:23 | l12 | test.c:77:15:77:21 | ... / ... | test.c:114:16:114:23 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:117:28:117:30 | l12 | test.c:77:15:77:21 | ... / ... | test.c:117:23:117:30 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:120:25:120:27 | l12 | test.c:77:15:77:21 | ... / ... | test.c:120:20:120:27 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:163:9:164:15 | ... / ... | test.c:163:3:164:16 | ... / ... | test.c:163:3:164:16 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.c:163:9:164:15 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:175:32:175:32 | p | test.c:189:51:189:59 | ... / ... | test.c:175:27:175:32 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.c:189:51:189:59 | ... / ... | from division by zero | test.c:189:6:189:24 | addInfThenCastToInt | addInfThenCastToInt | -| test.c:175:32:175:32 | p | test.c:193:13:194:15 | ... / ... | test.c:175:27:175:32 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.c:193:13:194:15 | ... / ... | from division by zero | test.c:192:6:192:7 | f2 | f2 | -| test.c:175:32:175:32 | p | test.c:204:19:204:27 | ... / ... | test.c:175:27:175:32 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.c:204:19:204:27 | ... / ... | from division by zero | test.c:192:6:192:7 | f2 | f2 | -| test.c:185:18:185:18 | p | test.c:200:25:200:33 | ... / ... | test.c:185:13:185:18 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.c:200:25:200:33 | ... / ... | from division by zero | test.c:192:6:192:7 | f2 | f2 | +subpaths \ No newline at end of file diff --git a/c/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.ql b/c/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.ql new file mode 100644 index 0000000000..f0d160a650 --- /dev/null +++ b/c/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.misuseofinfinitefloatingpointvalue.MisuseOfInfiniteFloatingPointValue + +class TestFileQuery extends MisuseOfInfiniteFloatingPointValueSharedQuery, TestQuery { } diff --git a/c/misra/test/rules/DIR-4-15/test.c b/c/common/test/rules/misuseofinfinitefloatingpointvalue/test.c similarity index 82% rename from c/misra/test/rules/DIR-4-15/test.c rename to c/common/test/rules/misuseofinfinitefloatingpointvalue/test.c index a827a7df97..6a4ebd94b9 100644 --- a/c/misra/test/rules/DIR-4-15/test.c +++ b/c/common/test/rules/misuseofinfinitefloatingpointvalue/test.c @@ -33,10 +33,10 @@ void f1(float p1) { float l8 = 0.0 / 0.0; (int)l4; // COMPLIANT - (int)l5; // NON_COMPLIANT: Casting NaN to int - (int)l6; // NON_COMPLIANT: Casting NaN to int - (int)l7; // NON_COMPLIANT: Casting NaN to int - (int)l8; // NON_COMPLIANT: Casting NaN to int + (int)l5; // COMPLIANT: Casting NaN to int + (int)l6; // COMPLIANT: Casting NaN to int + (int)l7; // NON_COMPLIANT: Casting Infinity to int + (int)l8; // COMPLIANT: Casting NaN to int l4 == 0; // COMPLIANT l4 != 0; // COMPLIANT @@ -58,21 +58,21 @@ void f1(float p1) { if (l9 != 0) { (int)(l9 / l9); // COMPLIANT: l9 is not zero } else { - (int)(l9 / l9); // NON_COMPLIANT: Guarded to not be NaN + (int)(l9 / l9); // NON_COMPLIANT[False positive]: Guarded to not be NaN } float l10 = 0; if (l10 == 0) { - (int)(l10 / l10); // NON_COMPLIANT: Casting NaN to integer + (int)(l10 / l10); // NON_COMPLIANT[False positive]: Casting NaN to integer } else { (int)(l10 / l10); // COMPLIANT: Guarded to not be NaN } float l11 = 0; - l11 == 0 ? (int)(l11 / l11) : 0; // NON_COMPLIANT + l11 == 0 ? (int)(l11 / l11) : 0; // NON_COMPLIANT[False positive] l11 == 0 ? 0 : (int)(l11 / l11); // COMPLIANT l11 != 0 ? (int)(l11 / l11) : 0; // COMPLIANT - l11 != 0 ? 0 : (int)(l11 / l11); // NON_COMPLIANT + l11 != 0 ? 0 : (int)(l11 / l11); // NON_COMPLIANT[False positive] float l12 = 1.0 / 0; if (isinf(l12)) { @@ -123,29 +123,29 @@ void f1(float p1) { if (isinf(l13)) { (int)l13; // COMPLIANT: Guarded not to be NaN } else { - (int)l13; // NON_COMPLIANT: Casting NaN to integer + (int)l13; // COMPLIANT: Casting NaN to integer } if (isinf(l13) == 1) { (int)l13; // COMPLIANT: Guarded not to be NaN (must be +Infinity) } else { - (int)l13; // NON_COMPLIANT: Casting NaN to integer + (int)l13; // COMPLIANT: Casting NaN to integer } if (isfinite(l13)) { (int)l13; // COMPLIANT: Guarded not to be NaN } else { - (int)l13; // NON_COMPLIANT: Casting NaN to integer + (int)l13; // COMPLIANT: Casting NaN to integer } if (isnormal(l13)) { (int)l13; // COMPLIANT: Guarded not to be NaN } else { - (int)l13; // NON_COMPLIANT: Casting NaN to integer + (int)l13; // COMPLIANT: Casting NaN to integer } if (isnan(l13)) { - (int)l13; // NON_COMPLIANT: Casting NaN to integer + (int)l13; // COMPLIANT: Casting NaN to integer } else { (int)l13; // COMPLIANT: Guarded not to be NaN } @@ -154,21 +154,21 @@ void f1(float p1) { : 0; // COMPLIANT: Checked infinite, therefore not NaN, before use isinf(l13) ? 0 : (int)l13; // COMPLIANT: Check on wrong branch isfinite(l13) ? (int)l13 : 0; // COMPLIANT: Checked finite before use - isfinite(l13) ? 0 : (int)l13; // NON_COMPLIANT: Checked on wrong branch - isnan(l13) ? (int)l13 : 0; // NON_COMPLIANT: Check on wrong branch + isfinite(l13) ? 0 : (int)l13; // COMPLIANT: Checked on wrong branch + isnan(l13) ? (int)l13 : 0; // COMPLIANT: Check on wrong branch isnan(l13) ? 0 : (int)l13; // COMPLIANT: Checked not NaN before use - (int)pow(2, p1); // NON_COMPLIANT: likely to be Infinity + (int)pow(2, p1); // NON_COMPLIANT[False negative]: likely to be Infinity (int)pow(2, sin(p1)); // COMPLIANT: not likely to be Infinity (int)(1 / sin(p1)); // NON_COMPLIANT: possible infinity from zero in denominator (int)(1 / log(p1)); // COMPLIANT: not possibly zero in denominator - (int)pow(p1, p1); // NON_COMPLIANT: NaN if p1 is zero + (int)pow(p1, p1); // COMPLIANT: NaN if p1 is zero if (p1 != 0) { (int)pow(p1, p1); // COMPLIANT: p1 is not zero } - (int)acos(p1); // NON_COMPLIANT: NaN if p1 is not within -1..1 + (int)acos(p1); // COMPLIANT: NaN if p1 is not within -1..1 (int)acos(cos(p1)); // COMPLIANT: cos(p1) is within -1..1 } @@ -192,13 +192,13 @@ void addNaNThenCastToInt(float p) { castToInt(p + 0.0 / 0.0); } void f2() { castToInt(1.0 / 0.0); // NON_COMPLIANT: Infinity flows to denominator in division - castToInt(0.0 / 0.0); // NON_COMPLIANT: NaN flows to denominator in division + castToInt(0.0 / 0.0); // COMPLIANT checkBeforeCastToInt(1.0 / 0.0); // COMPLIANT checkBeforeCastToInt(0.0 / 0.0); // COMPLIANT addOneThenCastToInt(1.0 / 0.0); // NON_COMPLIANT[False negative] addOneThenCastToInt(0.0 / 0.0); // NON_COMPLIANT castToIntToFloatToInt(1.0 / 0.0); // NON_COMPLIANT - castToIntToFloatToInt(0.0 / 0.0); // NON_COMPLIANT + castToIntToFloatToInt(0.0 / 0.0); // COMPLIANT // Check that during flow analysis, we only report the true root cause: float rootInf = 1.0 / 0.0; @@ -206,7 +206,7 @@ void f2() { float middleInf = rootInf + 1; float middleNaN = rootNaN + 1; castToInt(middleInf); // NON_COMPLIANT - castToInt(middleNaN); // NON_COMPLIANT + castToInt(middleNaN); // COMPLIANT addInfThenCastToInt(middleInf); // NON_COMPLIANT - addNaNThenCastToInt(middleNaN); // NON_COMPLIANT + addNaNThenCastToInt(middleNaN); // COMPLIANT } \ No newline at end of file diff --git a/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.expected b/c/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.expected similarity index 72% rename from c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.expected rename to c/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.expected index aeec3c943f..b567e06bc2 100644 --- a/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.expected +++ b/c/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.expected @@ -1,3 +1,36 @@ +problems +| test.c:36:8:36:9 | l5 | test.c:27:14:27:20 | ... / ... | test.c:36:3:36:9 | l5 | Possible NaN value $@ flows to a cast to integer. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | +| test.c:37:8:37:9 | l6 | test.c:28:14:28:20 | ... / ... | test.c:37:3:37:9 | l6 | Possible NaN value $@ flows to a cast to integer. | test.c:28:14:28:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | +| test.c:38:8:38:9 | l7 | test.c:31:14:32:15 | ... / ... | test.c:38:3:38:9 | l7 | Possible NaN value $@ flows to a cast to integer. | test.c:31:14:32:15 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:39:8:39:9 | l8 | test.c:33:14:33:22 | ... / ... | test.c:39:3:39:9 | l8 | Possible NaN value $@ flows to a cast to integer. | test.c:33:14:33:22 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:46:3:46:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:46:3:46:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | +| test.c:47:3:47:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:47:3:47:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | +| test.c:48:3:48:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:48:3:48:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | +| test.c:49:3:49:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:49:3:49:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | +| test.c:50:3:50:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:50:3:50:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | +| test.c:51:3:51:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:51:3:51:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | +| test.c:52:3:52:4 | l6 | test.c:28:14:28:20 | ... / ... | test.c:52:3:52:4 | l6 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:28:14:28:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | +| test.c:53:3:53:4 | l7 | test.c:31:14:32:15 | ... / ... | test.c:53:3:53:4 | l7 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:31:14:32:15 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:54:3:54:4 | l8 | test.c:33:14:33:22 | ... / ... | test.c:54:3:54:4 | l8 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:33:14:33:22 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:61:11:61:17 | ... / ... | test.c:61:5:61:18 | ... / ... | test.c:61:5:61:18 | ... / ... | Possible NaN value $@ flows to a cast to integer. | test.c:61:11:61:17 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:66:11:66:19 | ... / ... | test.c:66:5:66:20 | ... / ... | test.c:66:5:66:20 | ... / ... | Possible NaN value $@ flows to a cast to integer. | test.c:66:11:66:19 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:72:20:72:28 | ... / ... | test.c:72:14:72:29 | ... / ... | test.c:72:14:72:29 | ... / ... | Possible NaN value $@ flows to a cast to integer. | test.c:72:20:72:28 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:75:24:75:32 | ... / ... | test.c:75:18:75:33 | ... / ... | test.c:75:18:75:33 | ... / ... | Possible NaN value $@ flows to a cast to integer. | test.c:75:24:75:32 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:126:10:126:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:126:5:126:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:132:10:132:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:132:5:132:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:138:10:138:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:138:5:138:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:144:10:144:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:144:5:144:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:148:10:148:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:148:5:148:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:155:25:155:27 | l13 | test.c:122:15:122:21 | ... / ... | test.c:155:20:155:27 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:157:28:157:30 | l13 | test.c:122:15:122:21 | ... / ... | test.c:157:23:157:30 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:158:21:158:23 | l13 | test.c:122:15:122:21 | ... / ... | test.c:158:16:158:23 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:165:8:165:10 | call to pow | test.c:165:3:165:18 | call to pow | test.c:165:3:165:18 | call to pow | Possible NaN value $@ flows to a cast to integer. | test.c:165:8:165:10 | call to pow | both arguments are equal to zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:170:8:170:11 | call to acos | test.c:170:3:170:15 | call to acos | test.c:170:3:170:15 | call to acos | Possible NaN value $@ flows to a cast to integer. | test.c:170:8:170:11 | call to acos | the argument has a range -1000000000000000...1000000000000000 which is outside the domain of this function (-1.0...1.0) | test.c:6:6:6:7 | f1 | f1 | +| test.c:174:32:174:32 | p | test.c:189:51:189:59 | ... / ... | test.c:174:27:174:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.c:189:51:189:59 | ... / ... | from division of zero by zero | test.c:189:6:189:24 | addNaNThenCastToInt | addNaNThenCastToInt | +| test.c:174:32:174:32 | p | test.c:193:13:193:21 | ... / ... | test.c:174:27:174:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.c:193:13:193:21 | ... / ... | from division of zero by zero | test.c:191:6:191:7 | f2 | f2 | +| test.c:174:32:174:32 | p | test.c:197:23:197:31 | ... / ... | test.c:174:27:174:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.c:197:23:197:31 | ... / ... | from division of zero by zero | test.c:191:6:191:7 | f2 | f2 | +| test.c:174:32:174:32 | p | test.c:203:19:203:27 | ... / ... | test.c:174:27:174:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.c:203:19:203:27 | ... / ... | from division of zero by zero | test.c:191:6:191:7 | f2 | f2 | +| test.c:184:18:184:18 | p | test.c:199:25:199:33 | ... / ... | test.c:184:13:184:18 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.c:199:25:199:33 | ... / ... | from division of zero by zero | test.c:191:6:191:7 | f2 | f2 | edges | test.c:27:14:27:20 | ... / ... | test.c:27:14:27:20 | ... / ... | provenance | | | test.c:27:14:27:20 | ... / ... | test.c:36:3:36:9 | l5 | provenance | | @@ -25,24 +58,24 @@ edges | test.c:122:15:122:21 | ... / ... | test.c:155:20:155:27 | l13 | provenance | | | test.c:122:15:122:21 | ... / ... | test.c:157:23:157:30 | l13 | provenance | | | test.c:122:15:122:21 | ... / ... | test.c:158:16:158:23 | l13 | provenance | | -| test.c:175:22:175:22 | p | test.c:175:27:175:32 | p | provenance | | -| test.c:183:34:183:34 | p | test.c:185:13:185:18 | p | provenance | | -| test.c:188:32:188:32 | p | test.c:188:47:188:51 | ... + ... | provenance | Config | -| test.c:188:47:188:51 | ... + ... | test.c:175:22:175:22 | p | provenance | | -| test.c:190:32:190:32 | p | test.c:190:47:190:59 | ... + ... | provenance | Config | -| test.c:190:47:190:59 | ... + ... | test.c:175:22:175:22 | p | provenance | | -| test.c:190:47:190:59 | ... + ... | test.c:175:22:175:22 | p | provenance | | -| test.c:190:51:190:59 | ... / ... | test.c:190:47:190:59 | ... + ... | provenance | Config | -| test.c:195:13:195:21 | ... / ... | test.c:175:22:175:22 | p | provenance | | -| test.c:199:23:199:31 | ... / ... | test.c:188:32:188:32 | p | provenance | | -| test.c:201:25:201:33 | ... / ... | test.c:183:34:183:34 | p | provenance | | -| test.c:205:19:205:27 | ... / ... | test.c:205:19:205:27 | ... / ... | provenance | | -| test.c:205:19:205:27 | ... / ... | test.c:207:21:207:31 | ... + ... | provenance | Config | -| test.c:207:21:207:31 | ... + ... | test.c:207:21:207:31 | ... + ... | provenance | | -| test.c:207:21:207:31 | ... + ... | test.c:209:13:209:21 | middleNaN | provenance | | -| test.c:207:21:207:31 | ... + ... | test.c:211:23:211:31 | middleNaN | provenance | | -| test.c:209:13:209:21 | middleNaN | test.c:175:22:175:22 | p | provenance | | -| test.c:211:23:211:31 | middleNaN | test.c:190:32:190:32 | p | provenance | | +| test.c:174:22:174:22 | p | test.c:174:27:174:32 | p | provenance | | +| test.c:182:34:182:34 | p | test.c:184:13:184:18 | p | provenance | | +| test.c:187:32:187:32 | p | test.c:187:47:187:51 | ... + ... | provenance | Config | +| test.c:187:47:187:51 | ... + ... | test.c:174:22:174:22 | p | provenance | | +| test.c:189:32:189:32 | p | test.c:189:47:189:59 | ... + ... | provenance | Config | +| test.c:189:47:189:59 | ... + ... | test.c:174:22:174:22 | p | provenance | | +| test.c:189:47:189:59 | ... + ... | test.c:174:22:174:22 | p | provenance | | +| test.c:189:51:189:59 | ... / ... | test.c:189:47:189:59 | ... + ... | provenance | Config | +| test.c:193:13:193:21 | ... / ... | test.c:174:22:174:22 | p | provenance | | +| test.c:197:23:197:31 | ... / ... | test.c:187:32:187:32 | p | provenance | | +| test.c:199:25:199:33 | ... / ... | test.c:182:34:182:34 | p | provenance | | +| test.c:203:19:203:27 | ... / ... | test.c:203:19:203:27 | ... / ... | provenance | | +| test.c:203:19:203:27 | ... / ... | test.c:205:21:205:31 | ... + ... | provenance | Config | +| test.c:205:21:205:31 | ... + ... | test.c:205:21:205:31 | ... + ... | provenance | | +| test.c:205:21:205:31 | ... + ... | test.c:207:13:207:21 | middleNaN | provenance | | +| test.c:205:21:205:31 | ... + ... | test.c:209:23:209:31 | middleNaN | provenance | | +| test.c:207:13:207:21 | middleNaN | test.c:174:22:174:22 | p | provenance | | +| test.c:209:23:209:31 | middleNaN | test.c:189:32:189:32 | p | provenance | | nodes | test.c:27:14:27:20 | ... / ... | semmle.label | ... / ... | | test.c:27:14:27:20 | ... / ... | semmle.label | ... / ... | @@ -79,58 +112,25 @@ nodes | test.c:155:20:155:27 | l13 | semmle.label | l13 | | test.c:157:23:157:30 | l13 | semmle.label | l13 | | test.c:158:16:158:23 | l13 | semmle.label | l13 | -| test.c:166:3:166:18 | call to pow | semmle.label | call to pow | -| test.c:171:3:171:15 | call to acos | semmle.label | call to acos | -| test.c:175:22:175:22 | p | semmle.label | p | -| test.c:175:27:175:32 | p | semmle.label | p | -| test.c:183:34:183:34 | p | semmle.label | p | -| test.c:185:13:185:18 | p | semmle.label | p | -| test.c:188:32:188:32 | p | semmle.label | p | -| test.c:188:47:188:51 | ... + ... | semmle.label | ... + ... | -| test.c:190:32:190:32 | p | semmle.label | p | -| test.c:190:47:190:59 | ... + ... | semmle.label | ... + ... | -| test.c:190:47:190:59 | ... + ... | semmle.label | ... + ... | -| test.c:190:51:190:59 | ... / ... | semmle.label | ... / ... | -| test.c:195:13:195:21 | ... / ... | semmle.label | ... / ... | -| test.c:199:23:199:31 | ... / ... | semmle.label | ... / ... | -| test.c:201:25:201:33 | ... / ... | semmle.label | ... / ... | -| test.c:205:19:205:27 | ... / ... | semmle.label | ... / ... | -| test.c:205:19:205:27 | ... / ... | semmle.label | ... / ... | -| test.c:207:21:207:31 | ... + ... | semmle.label | ... + ... | -| test.c:207:21:207:31 | ... + ... | semmle.label | ... + ... | -| test.c:209:13:209:21 | middleNaN | semmle.label | middleNaN | -| test.c:211:23:211:31 | middleNaN | semmle.label | middleNaN | +| test.c:165:3:165:18 | call to pow | semmle.label | call to pow | +| test.c:170:3:170:15 | call to acos | semmle.label | call to acos | +| test.c:174:22:174:22 | p | semmle.label | p | +| test.c:174:27:174:32 | p | semmle.label | p | +| test.c:182:34:182:34 | p | semmle.label | p | +| test.c:184:13:184:18 | p | semmle.label | p | +| test.c:187:32:187:32 | p | semmle.label | p | +| test.c:187:47:187:51 | ... + ... | semmle.label | ... + ... | +| test.c:189:32:189:32 | p | semmle.label | p | +| test.c:189:47:189:59 | ... + ... | semmle.label | ... + ... | +| test.c:189:47:189:59 | ... + ... | semmle.label | ... + ... | +| test.c:189:51:189:59 | ... / ... | semmle.label | ... / ... | +| test.c:193:13:193:21 | ... / ... | semmle.label | ... / ... | +| test.c:197:23:197:31 | ... / ... | semmle.label | ... / ... | +| test.c:199:25:199:33 | ... / ... | semmle.label | ... / ... | +| test.c:203:19:203:27 | ... / ... | semmle.label | ... / ... | +| test.c:203:19:203:27 | ... / ... | semmle.label | ... / ... | +| test.c:205:21:205:31 | ... + ... | semmle.label | ... + ... | +| test.c:205:21:205:31 | ... + ... | semmle.label | ... + ... | +| test.c:207:13:207:21 | middleNaN | semmle.label | middleNaN | +| test.c:209:23:209:31 | middleNaN | semmle.label | middleNaN | subpaths -#select -| test.c:36:8:36:9 | l5 | test.c:27:14:27:20 | ... / ... | test.c:36:3:36:9 | l5 | Possible NaN value $@ flows to a cast to integer. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | -| test.c:37:8:37:9 | l6 | test.c:28:14:28:20 | ... / ... | test.c:37:3:37:9 | l6 | Possible NaN value $@ flows to a cast to integer. | test.c:28:14:28:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | -| test.c:38:8:38:9 | l7 | test.c:31:14:32:15 | ... / ... | test.c:38:3:38:9 | l7 | Possible NaN value $@ flows to a cast to integer. | test.c:31:14:32:15 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:39:8:39:9 | l8 | test.c:33:14:33:22 | ... / ... | test.c:39:3:39:9 | l8 | Possible NaN value $@ flows to a cast to integer. | test.c:33:14:33:22 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:46:3:46:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:46:3:46:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | -| test.c:47:3:47:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:47:3:47:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | -| test.c:48:3:48:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:48:3:48:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | -| test.c:49:3:49:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:49:3:49:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | -| test.c:50:3:50:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:50:3:50:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | -| test.c:51:3:51:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:51:3:51:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | -| test.c:52:3:52:4 | l6 | test.c:28:14:28:20 | ... / ... | test.c:52:3:52:4 | l6 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:28:14:28:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | -| test.c:53:3:53:4 | l7 | test.c:31:14:32:15 | ... / ... | test.c:53:3:53:4 | l7 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:31:14:32:15 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:54:3:54:4 | l8 | test.c:33:14:33:22 | ... / ... | test.c:54:3:54:4 | l8 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:33:14:33:22 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:61:11:61:17 | ... / ... | test.c:61:5:61:18 | ... / ... | test.c:61:5:61:18 | ... / ... | Possible NaN value $@ flows to a cast to integer. | test.c:61:11:61:17 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:66:11:66:19 | ... / ... | test.c:66:5:66:20 | ... / ... | test.c:66:5:66:20 | ... / ... | Possible NaN value $@ flows to a cast to integer. | test.c:66:11:66:19 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:72:20:72:28 | ... / ... | test.c:72:14:72:29 | ... / ... | test.c:72:14:72:29 | ... / ... | Possible NaN value $@ flows to a cast to integer. | test.c:72:20:72:28 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:75:24:75:32 | ... / ... | test.c:75:18:75:33 | ... / ... | test.c:75:18:75:33 | ... / ... | Possible NaN value $@ flows to a cast to integer. | test.c:75:24:75:32 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:126:10:126:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:126:5:126:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:132:10:132:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:132:5:132:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:138:10:138:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:138:5:138:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:144:10:144:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:144:5:144:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:148:10:148:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:148:5:148:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:155:25:155:27 | l13 | test.c:122:15:122:21 | ... / ... | test.c:155:20:155:27 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:157:28:157:30 | l13 | test.c:122:15:122:21 | ... / ... | test.c:157:23:157:30 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:158:21:158:23 | l13 | test.c:122:15:122:21 | ... / ... | test.c:158:16:158:23 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:166:8:166:10 | call to pow | test.c:166:3:166:18 | call to pow | test.c:166:3:166:18 | call to pow | Possible NaN value $@ flows to a cast to integer. | test.c:166:8:166:10 | call to pow | both arguments are equal to zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:171:8:171:11 | call to acos | test.c:171:3:171:15 | call to acos | test.c:171:3:171:15 | call to acos | Possible NaN value $@ flows to a cast to integer. | test.c:171:8:171:11 | call to acos | the argument has a range -1000000000000000...1000000000000000 which is outside the domain of this function (-1.0...1.0) | test.c:6:6:6:7 | f1 | f1 | -| test.c:175:32:175:32 | p | test.c:190:51:190:59 | ... / ... | test.c:175:27:175:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.c:190:51:190:59 | ... / ... | from division of zero by zero | test.c:190:6:190:24 | addNaNThenCastToInt | addNaNThenCastToInt | -| test.c:175:32:175:32 | p | test.c:195:13:195:21 | ... / ... | test.c:175:27:175:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.c:195:13:195:21 | ... / ... | from division of zero by zero | test.c:192:6:192:7 | f2 | f2 | -| test.c:175:32:175:32 | p | test.c:199:23:199:31 | ... / ... | test.c:175:27:175:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.c:199:23:199:31 | ... / ... | from division of zero by zero | test.c:192:6:192:7 | f2 | f2 | -| test.c:175:32:175:32 | p | test.c:205:19:205:27 | ... / ... | test.c:175:27:175:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.c:205:19:205:27 | ... / ... | from division of zero by zero | test.c:192:6:192:7 | f2 | f2 | -| test.c:185:18:185:18 | p | test.c:201:25:201:33 | ... / ... | test.c:185:13:185:18 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.c:201:25:201:33 | ... / ... | from division of zero by zero | test.c:192:6:192:7 | f2 | f2 | diff --git a/c/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.ql b/c/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.ql new file mode 100644 index 0000000000..a1f729ed02 --- /dev/null +++ b/c/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.misuseofnanfloatingpointvalue.MisuseOfNaNFloatingPointValue + +class TestFileQuery extends MisuseOfNaNFloatingPointValueSharedQuery, TestQuery { } diff --git a/c/common/test/rules/misuseofnanfloatingpointvalue/test.c b/c/common/test/rules/misuseofnanfloatingpointvalue/test.c new file mode 100644 index 0000000000..bd997282f0 --- /dev/null +++ b/c/common/test/rules/misuseofnanfloatingpointvalue/test.c @@ -0,0 +1,210 @@ +#include "math.h" + +float getFloat() { return 1.0; } + +// Parameter could be infinity +void f1(float p1) { + float l1 = 1; + float l2 = 1.0 / 0; + float l3 = -l2; + + 10 / l1; // COMPLIANT + 10 / l2; // COMPLIANT: Underflows to zero + 10 / l3; // COMPLIANT: Underflow to negative zero + 10 / p1; // COMPLIANT: Reduce false positives by assuming not infinity + 10 / getFloat(); // COMPLIANT: Reduce false positives by assuming not infinity + + (int)l1; // COMPLIANT + (int)l2; // COMPLIANT + (int)l3; // COMPLIANT + (int)p1; // COMPLIANT: Reduce false positives by assuming not infinity + (int)getFloat(); // COMPLIANT: Reduce false positives by assuming not infinity + + // Not NaN: + float l4 = l1 / l1; // COMPLIANT + + // NaN because of infinity divided by itself: + float l5 = l2 / l2; // COMPLIANT: Division by infinity not allowed. + float l6 = l3 / l3; // COMPLIANT: Division by infinity not allowed. + + // NaN because of zero divided by itself: + float l7 = getFloat() / + p1; // COMPLIANT: Reduce false positives by assuming not infinity + float l8 = 0.0 / 0.0; + + (int)l4; // COMPLIANT + (int)l5; // NON_COMPLIANT: Casting NaN to int + (int)l6; // NON_COMPLIANT: Casting NaN to int + (int)l7; // NON_COMPLIANT: Casting NaN to int + (int)l8; // NON_COMPLIANT: Casting NaN to int + + l4 == 0; // COMPLIANT + l4 != 0; // COMPLIANT + l4 <= 0; // COMPLIANT + l4 < 0; // COMPLIANT + l4 >= 0; // COMPLIANT + l5 == 0; // NON_COMPLIANT: Comparison with NaN always false + l5 != 0; // NON_COMPLIANT: Comparison with NaN always false + l5 < 0; // NON_COMPLIANT: Comparison with NaN always false + l5 <= 0; // NON_COMPLIANT: Comparison with NaN always false + l5 > 0; // NON_COMPLIANT: Comparison with NaN always false + l5 >= 0; // NON_COMPLIANT: Comparison with NaN always false + l6 == 0; // NON_COMPLIANT: Comparison with NaN always false + l7 == 0; // NON_COMPLIANT: Comparison with NaN always false + l8 == 0; // NON_COMPLIANT: Comparison with NaN always false + + // Guards + float l9 = 0; + if (l9 != 0) { + (int)(l9 / l9); // COMPLIANT: l9 is not zero + } else { + (int)(l9 / l9); // NON_COMPLIANT: Casting NaN to integer + } + + float l10 = 0; + if (l10 == 0) { + (int)(l10 / l10); // NON_COMPLIANT: Casting NaN to integer + } else { + (int)(l10 / l10); // COMPLIANT: Guarded to not be NaN + } + + float l11 = 0; + l11 == 0 ? (int)(l11 / l11) : 0; // NON_COMPLIANT + l11 == 0 ? 0 : (int)(l11 / l11); // COMPLIANT + l11 != 0 ? (int)(l11 / l11) : 0; // COMPLIANT + l11 != 0 ? 0 : (int)(l11 / l11); // NON_COMPLIANT + + float l12 = 1.0 / 0; + if (isinf(l12)) { + (int)l12; // COMPLIANT: Casting Infinity to integer + } else { + (int)l12; // COMPLIANT: Guarded not to be Infinity + } + + if (!isinf(l12)) { + (int)l12; // COMPLIANT: Guarded not to be Infinity + } else { + (int)l12; // COMPLIANT: Casting Infinity to integer + } + + if (isinf(l12) == 1) { + (int)l12; // COMPLIANT: Must be +Infinity + } else { + (int)l12; // COMPLIANT: May be -Infinity + } + + if (isfinite(l12)) { + (int)l12; // COMPLIANT: Guarded not to be Infinity + } else { + (int)l12; // COMPLIANT: Casting Infinity to integer + } + + if (isnormal(l12)) { + (int)l12; // COMPLIANT: Guarded not to be Infinity + } else { + (int)l12; // COMPLIANT: Casting Infinity to integer + } + + if (isnan(l12)) { + (int)l12; // COMPLIANT: Guarded not to be Infinity + } else { + (int)l12; // COMPLIANT: Casting Infinity to integer + } + + isinf(l12) ? (int)l12 : 0; // COMPLIANT: Check on wrong branch + isinf(l12) ? 0 : (int)l12; // COMPLIANT: Checked not infinite before use + isfinite(l12) ? (int)l12 : 0; // COMPLIANT: Checked finite before use + isfinite(l12) ? 0 : (int)l12; // COMPLIANT: Checked on wrong branch + isnan(l12) ? (int)l12 + : 0; // COMPLIANT: Checked NaN, therefore not infinite, before use + isnan(l12) ? 0 : (int)l12; // COMPLIANT: Check on wrong branch + + float l13 = 0.0 / 0; + if (isinf(l13)) { + (int)l13; // COMPLIANT: Guarded not to be NaN + } else { + (int)l13; // NON_COMPLIANT: Casting NaN to integer + } + + if (isinf(l13) == 1) { + (int)l13; // COMPLIANT: Guarded not to be NaN (must be +Infinity) + } else { + (int)l13; // NON_COMPLIANT: Casting NaN to integer + } + + if (isfinite(l13)) { + (int)l13; // COMPLIANT: Guarded not to be NaN + } else { + (int)l13; // NON_COMPLIANT: Casting NaN to integer + } + + if (isnormal(l13)) { + (int)l13; // COMPLIANT: Guarded not to be NaN + } else { + (int)l13; // NON_COMPLIANT: Casting NaN to integer + } + + if (isnan(l13)) { + (int)l13; // NON_COMPLIANT: Casting NaN to integer + } else { + (int)l13; // COMPLIANT: Guarded not to be NaN + } + + isinf(l13) ? (int)l13 + : 0; // COMPLIANT: Checked infinite, therefore not NaN, before use + isinf(l13) ? 0 : (int)l13; // NON_COMPLIANT: Check on wrong branch + isfinite(l13) ? (int)l13 : 0; // COMPLIANT: Checked finite before use + isfinite(l13) ? 0 : (int)l13; // NON_COMPLIANT: Checked on wrong branch + isnan(l13) ? (int)l13 : 0; // NON_COMPLIANT: Check on wrong branch + isnan(l13) ? 0 : (int)l13; // COMPLIANT: Checked not NaN before use + + (int)pow(2, p1); // COMPLIANT: likely to be Infinity + (int)pow(2, sin(p1)); // COMPLIANT: not likely to be Infinity + (int)(1 / sin(p1)); // COMPLIANT: possible infinity from zero in denominator + (int)(1 / log(p1)); // COMPLIANT: not possibly zero in denominator + (int)pow(p1, p1); // NON_COMPLIANT: NaN if p1 is zero + if (p1 != 0) { + (int)pow(p1, p1); // COMPLIANT: p1 is not zero + } + + (int)acos(p1); // NON_COMPLIANT: NaN if p1 is not within -1..1 + (int)acos(cos(p1)); // COMPLIANT: cos(p1) is within -1..1 +} + +void castToInt(float p) { (int)p; } + +void checkBeforeCastToInt(float p) { + if (isfinite(p)) { + castToInt(p); + } +} + +void castToIntToFloatToInt(float p) { + // This should be reported as a violation, but not downstream from here. + castToInt((int)p); +} + +void addOneThenCastToInt(float p) { castToInt(p + 1); } +void addInfThenCastToInt(float p) { castToInt(p + 1.0 / 0.0); } +void addNaNThenCastToInt(float p) { castToInt(p + 0.0 / 0.0); } + +void f2() { + castToInt(1.0 / 0.0); // COMPLIANT: Infinity flows to denominator in division + castToInt(0.0 / 0.0); // COMPLIANT: NaN flows to denominator in division + checkBeforeCastToInt(1.0 / 0.0); // COMPLIANT + checkBeforeCastToInt(0.0 / 0.0); // COMPLIANT + addOneThenCastToInt(1.0 / 0.0); // COMPLIANT + addOneThenCastToInt(0.0 / 0.0); // NON_COMPLIANT + castToIntToFloatToInt(1.0 / 0.0); // COMPLIANT + castToIntToFloatToInt(0.0 / 0.0); // NON_COMPLIANT + + // Check that during flow analysis, we only report the true root cause: + float rootInf = 1.0 / 0.0; + float rootNaN = 0.0 / 0.0; + float middleInf = rootInf + 1; + float middleNaN = rootNaN + 1; + castToInt(middleInf); // COMPLIANT + castToInt(middleNaN); // NON_COMPLIANT + addInfThenCastToInt(middleInf); // NON_COMPLIANT + addNaNThenCastToInt(middleNaN); // NON_COMPLIANT +} \ No newline at end of file diff --git a/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql index 812e9fe1e2..0294fc6919 100644 --- a/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql +++ b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql @@ -13,130 +13,11 @@ */ import cpp -import codeql.util.Boolean import codingstandards.c.misra -import codingstandards.cpp.RestrictedRangeAnalysis -import codingstandards.cpp.FloatingPoint -import codingstandards.cpp.AlertReporting -import semmle.code.cpp.controlflow.Guards -import semmle.code.cpp.dataflow.new.DataFlow -import semmle.code.cpp.dataflow.new.TaintTracking -import semmle.code.cpp.controlflow.Dominance +import codingstandards.cpp.rules.misuseofinfinitefloatingpointvalue.MisuseOfInfiniteFloatingPointValue -module InvalidInfinityUsage implements DataFlow::ConfigSig { - /** - * An operation which does not have Infinity as an input, but may produce Infinity, according - * to the `RestrictedRangeAnalysis` module. - */ - predicate isSource(DataFlow::Node node) { - potentialSource(node) and - not exists(DataFlow::Node prior | - isAdditionalFlowStep(prior, node) and - potentialSource(prior) - ) - } - - /** - * An operation which may produce Infinity acconding to the `RestrictedRangeAnalysis` module. - */ - additional predicate potentialSource(DataFlow::Node node) { - node.asExpr() instanceof Operation and - exprMayEqualInfinity(node.asExpr(), _) - } - - predicate isBarrierOut(DataFlow::Node node) { - guardedNotFPClass(node.asExpr(), TInfinite()) - or - exists(Expr e | - e.getType() instanceof IntegralType and - e = node.asConvertedExpr() - ) - } - - /** - * An additional flow step to handle operations which propagate Infinity. - * - * This double checks that an Infinity may propagate by checking the `RestrictedRangeAnalysis` - * value estimate. This is conservative, since `RestrictedRangeAnalysis` is performed locally - * in scope with unanalyzable values in a finite range. However, this conservative approach - * leverages analysis of guards and other local conditions to avoid false positives. - */ - predicate isAdditionalFlowStep(DataFlow::Node source, DataFlow::Node sink) { - exists(Operation o | - o.getAnOperand() = source.asExpr() and - o = sink.asExpr() and - potentialSource(sink) - ) - } - - predicate isSink(DataFlow::Node node) { - node instanceof InvalidInfinityUsage and - ( - // Require that range analysis finds this value potentially infinite, to avoid false positives - // in the presence of guards. This may induce false negatives. - exprMayEqualInfinity(node.asExpr(), _) - or - // Unanalyzable expressions are not checked against range analysis, which assumes a finite - // range. - not RestrictedRangeAnalysis::canBoundExpr(node.asExpr()) - or - node.asExpr().(VariableAccess).getTarget() instanceof Parameter - ) +class PossibleMisuseOfUndetectedInfinityQuery extends MisuseOfInfiniteFloatingPointValueSharedQuery { + PossibleMisuseOfUndetectedInfinityQuery() { + this = FloatingTypes2Package::possibleMisuseOfUndetectedInfinityQuery() } } - -class InvalidInfinityUsage extends DataFlow::Node { - string description; - - InvalidInfinityUsage() { - // Case 2: NaNs and infinities shall not be cast to integers - exists(Conversion c | - asExpr() = c.getUnconverted() and - c.getExpr().getType() instanceof FloatingPointType and - c.getType() instanceof IntegralType and - description = "cast to integer." - ) - or - // Case 3: Infinities shall not underflow or otherwise produce finite values - exists(BinaryOperation op | - asExpr() = op.getRightOperand() and - op.getOperator() = "/" and - description = "divisor, which would silently underflow and produce zero." - ) - } - - string getDescription() { result = description } -} - -module InvalidInfinityFlow = DataFlow::Global; - -import InvalidInfinityFlow::PathGraph - -from - Element elem, InvalidInfinityFlow::PathNode source, InvalidInfinityFlow::PathNode sink, - InvalidInfinityUsage usage, Expr sourceExpr, string sourceString, Function function, - string computedInFunction -where - elem = MacroUnwrapper::unwrapElement(sink.getNode().asExpr()) and - not InvalidInfinityFlow::PathGraph::edges(_, source, _, _) and - not InvalidInfinityFlow::PathGraph::edges(sink, _, _, _) and - not isExcluded(elem, FloatingTypes2Package::possibleMisuseOfUndetectedInfinityQuery()) and - not sourceExpr.isFromTemplateInstantiation(_) and - not usage.asExpr().isFromTemplateInstantiation(_) and - usage = sink.getNode() and - sourceExpr = source.getNode().asExpr() and - function = sourceExpr.getEnclosingFunction() and - InvalidInfinityFlow::flow(source.getNode(), usage) and - ( - if not sourceExpr.getEnclosingFunction() = usage.asExpr().getEnclosingFunction() - then computedInFunction = "computed in function $@ " - else computedInFunction = "" - ) and - ( - if sourceExpr instanceof DivExpr - then sourceString = "from division by zero" - else sourceString = sourceExpr.toString() - ) -select elem, source, sink, - "Possibly infinite float value $@ " + computedInFunction + "flows to " + usage.getDescription(), - sourceExpr, sourceString, function, function.getName() diff --git a/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql index e1b6762ada..9315a4ed4c 100644 --- a/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql +++ b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql @@ -13,190 +13,11 @@ */ import cpp -import codeql.util.Boolean import codingstandards.c.misra -import codingstandards.cpp.RestrictedRangeAnalysis -import codingstandards.cpp.FloatingPoint -import codingstandards.cpp.AlertReporting -import semmle.code.cpp.controlflow.Guards -import semmle.code.cpp.dataflow.new.DataFlow -import semmle.code.cpp.dataflow.new.TaintTracking -import semmle.code.cpp.controlflow.Dominance +import codingstandards.cpp.rules.misuseofnanfloatingpointvalue.MisuseOfNaNFloatingPointValue -abstract class PotentiallyNaNExpr extends Expr { - abstract string getReason(); -} - -class DomainErrorFunctionCall extends FunctionCall, PotentiallyNaNExpr { - string reason; - - DomainErrorFunctionCall() { RestrictedDomainError::hasDomainError(this, reason) } - - override string getReason() { result = reason } -} - -// IEEE 754-1985 Section 7.1 invalid operations -class InvalidOperationExpr extends BinaryOperation, PotentiallyNaNExpr { - string reason; - - InvalidOperationExpr() { - // Usual arithmetic conversions in both languages mean that if either operand is a floating - // type, the other one is converted to a floating type as well. - getAnOperand().getFullyConverted().getType() instanceof FloatingPointType and - ( - // 7.1.1 propagates signaling NaNs, we rely on flow analysis and/or assume quiet NaNs, so we - // intentionally do not cover this case. - // 7.1.2: magnitude subtraction of infinities, such as +Inf + -Inf - getOperator() = "+" and - exists(Boolean sign | - exprMayEqualInfinity(getLeftOperand(), sign) and - exprMayEqualInfinity(getRightOperand(), sign.booleanNot()) - ) and - reason = "from addition of infinity and negative infinity" - or - // 7.1.2 continued - getOperator() = "-" and - exists(Boolean sign | - exprMayEqualInfinity(getLeftOperand(), sign) and - exprMayEqualInfinity(getRightOperand(), sign) - ) and - reason = "from subtraction of an infinity from itself" - or - // 7.1.3: multiplication of zero by infinity - getOperator() = "*" and - exists(Expr zeroOp, Expr infinityOp | - zeroOp = getAnOperand() and - infinityOp = getAnOperand() and - not zeroOp = infinityOp and - exprMayEqualZero(zeroOp) and - exprMayEqualInfinity(infinityOp, _) - ) and - reason = "from multiplication of zero by infinity" - or - // 7.1.4: Division of zero by zero, or infinity by infinity - getOperator() = "/" and - exprMayEqualZero(getLeftOperand()) and - exprMayEqualZero(getRightOperand()) and - reason = "from division of zero by zero" - or - // 7.1.4 continued - getOperator() = "/" and - exprMayEqualInfinity(getLeftOperand(), _) and - exprMayEqualInfinity(getRightOperand(), _) and - reason = "from division of infinity by infinity" - or - // 7.1.5: x % y where y is zero or x is infinite - getOperator() = "%" and - exprMayEqualInfinity(getLeftOperand(), _) and - reason = "from modulus of infinity" - or - // 7.1.5 continued - getOperator() = "%" and - exprMayEqualZero(getRightOperand()) and - reason = "from modulus by zero" - // 7.1.6 handles the sqrt function, not covered here. - // 7.1.7 declares exceptions during invalid conversions, which we catch as sinks in our flow - // analysis. - // 7.1.8 declares exceptions for unordered comparisons, which we catch as sinks in our flow - // analysis. - ) +class PossibleMisuseOfUndetectedNaNQuery extends MisuseOfNaNFloatingPointValueSharedQuery { + PossibleMisuseOfUndetectedNaNQuery() { + this = FloatingTypes2Package::possibleMisuseOfUndetectedNaNQuery() } - - override string getReason() { result = reason } } - -module InvalidNaNUsage implements DataFlow::ConfigSig { - /** - * An expression which has non-NaN inputs and may produce a NaN output. - */ - predicate isSource(DataFlow::Node node) { - potentialSource(node) and - not exists(DataFlow::Node prior | - isAdditionalFlowStep(prior, node) and - potentialSource(prior) - ) - } - - /** - * An expression which may produce a NaN output. - */ - additional predicate potentialSource(DataFlow::Node node) { - node.asExpr() instanceof PotentiallyNaNExpr - } - - predicate isBarrierOut(DataFlow::Node node) { - guardedNotFPClass(node.asExpr(), TNaN()) - or - exists(Expr e | - e.getType() instanceof IntegralType and - e = node.asConvertedExpr() - ) - } - - /** - * Add an additional flow step to handle NaN propagation through floating point operations. - */ - predicate isAdditionalFlowStep(DataFlow::Node source, DataFlow::Node sink) { - exists(Operation o | - o.getAnOperand() = source.asExpr() and - o = sink.asExpr() and - o.getType() instanceof FloatingPointType - ) - } - - predicate isSink(DataFlow::Node node) { - not guardedNotFPClass(node.asExpr(), TNaN()) and - node instanceof InvalidNaNUsage - } -} - -class InvalidNaNUsage extends DataFlow::Node { - string description; - - InvalidNaNUsage() { - // Case 1: NaNs shall not be compared, except to themselves - exists(ComparisonOperation cmp | - this.asExpr() = cmp.getAnOperand() and - not hashCons(cmp.getLeftOperand()) = hashCons(cmp.getRightOperand()) and - description = "comparison, which would always evaluate to false." - ) - or - // Case 2: NaNs and infinities shall not be cast to integers - exists(Conversion c | - this.asExpr() = c.getUnconverted() and - c.getExpr().getType() instanceof FloatingPointType and - c.getType() instanceof IntegralType and - description = "a cast to integer." - ) - } - - string getDescription() { result = description } -} - -module InvalidNaNFlow = DataFlow::Global; - -import InvalidNaNFlow::PathGraph - -from - Element elem, InvalidNaNFlow::PathNode source, InvalidNaNFlow::PathNode sink, - InvalidNaNUsage usage, Expr sourceExpr, string sourceString, Function function, - string computedInFunction -where - not InvalidNaNFlow::PathGraph::edges(_, source, _, _) and - not InvalidNaNFlow::PathGraph::edges(sink, _, _, _) and - not sourceExpr.isFromTemplateInstantiation(_) and - not usage.asExpr().isFromTemplateInstantiation(_) and - elem = MacroUnwrapper::unwrapElement(sink.getNode().asExpr()) and - usage = sink.getNode() and - sourceExpr = source.getNode().asExpr() and - sourceString = source.getNode().asExpr().(PotentiallyNaNExpr).getReason() and - function = sourceExpr.getEnclosingFunction() and - InvalidNaNFlow::flow(source.getNode(), usage) and - ( - if not sourceExpr.getEnclosingFunction() = usage.asExpr().getEnclosingFunction() - then computedInFunction = "computed in function $@ " - else computedInFunction = "" - ) -select elem, source, sink, - "Possible NaN value $@ " + computedInFunction + "flows to " + usage.getDescription(), sourceExpr, - sourceString, function, function.getName() diff --git a/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.qlref b/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.qlref deleted file mode 100644 index dccac37c5f..0000000000 --- a/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql \ No newline at end of file diff --git a/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.testref b/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.testref new file mode 100644 index 0000000000..176855a83d --- /dev/null +++ b/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.testref @@ -0,0 +1 @@ +c/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.ql \ No newline at end of file diff --git a/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.qlref b/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.qlref deleted file mode 100644 index d88c172bd5..0000000000 --- a/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql \ No newline at end of file diff --git a/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.testref b/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.testref new file mode 100644 index 0000000000..7cd2a4d431 --- /dev/null +++ b/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.testref @@ -0,0 +1 @@ +c/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.ql \ No newline at end of file diff --git a/change_notes/2025-04-14-update-infinity-nan-detection.md b/change_notes/2025-04-14-update-infinity-nan-detection.md new file mode 100644 index 0000000000..fe484a37fe --- /dev/null +++ b/change_notes/2025-04-14-update-infinity-nan-detection.md @@ -0,0 +1,4 @@ + - `DIR-4-15` - `PossibleMisuseOfUndetectedInfinity.ql`, `PossibleMisuseOfUndetectedNaN.ql`: + - Add logic to suppress NaNs from the CodeQL extractor in the new restricted range analysis, which can have unexpected downstream effects. + - Alter the behavior of floating point class guards (such as `isinf`, `isfinite`, `isnan`) to more correctly reflect the branches that have been guarded. + - Query files have been moved/refactored to share logic across MISRA-C and MISRA-C++; no observable change in behavior from this is expected. \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/RestrictedRangeAnalysis.qll b/cpp/common/src/codingstandards/cpp/RestrictedRangeAnalysis.qll index 05290b3aaf..d92b46335d 100644 --- a/cpp/common/src/codingstandards/cpp/RestrictedRangeAnalysis.qll +++ b/cpp/common/src/codingstandards/cpp/RestrictedRangeAnalysis.qll @@ -1093,7 +1093,9 @@ module RestrictedRangeAnalysis { ( // If the expression evaluates to a constant, then there is no // need to call getUpperBoundsImpl. - if exists(getValue(expr).toFloat()) + if + exists(getValue(expr).toFloat()) and + not getValue(expr) = "NaN" then result = getValue(expr).toFloat() else ( // Some of the bounds computed by `getUpperBoundsImpl` diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/FloatingPoint.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/FloatingPoint.qll new file mode 100644 index 0000000000..0ff7a07214 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/FloatingPoint.qll @@ -0,0 +1,44 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype FloatingPointQuery = + TPossibleMisuseOfInfiniteFloatingPointValueQuery() or + TPossibleMisuseOfNaNFloatingPointValueQuery() + +predicate isFloatingPointQueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `possibleMisuseOfInfiniteFloatingPointValue` query + FloatingPointPackage::possibleMisuseOfInfiniteFloatingPointValueQuery() and + queryId = + // `@id` for the `possibleMisuseOfInfiniteFloatingPointValue` query + "cpp/misra/possible-misuse-of-infinite-floating-point-value" and + ruleId = "DIR-0-3-1" and + category = "advisory" + or + query = + // `Query` instance for the `possibleMisuseOfNaNFloatingPointValue` query + FloatingPointPackage::possibleMisuseOfNaNFloatingPointValueQuery() and + queryId = + // `@id` for the `possibleMisuseOfNaNFloatingPointValue` query + "cpp/misra/possible-misuse-of-nan-floating-point-value" and + ruleId = "DIR-0-3-1" and + category = "advisory" +} + +module FloatingPointPackage { + Query possibleMisuseOfInfiniteFloatingPointValueQuery() { + //autogenerate `Query` type + result = + // `Query` type for `possibleMisuseOfInfiniteFloatingPointValue` query + TQueryCPP(TFloatingPointPackageQuery(TPossibleMisuseOfInfiniteFloatingPointValueQuery())) + } + + Query possibleMisuseOfNaNFloatingPointValueQuery() { + //autogenerate `Query` type + result = + // `Query` type for `possibleMisuseOfNaNFloatingPointValue` query + TQueryCPP(TFloatingPointPackageQuery(TPossibleMisuseOfNaNFloatingPointValueQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll index 4a6cbe936b..abd6aeff96 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll @@ -18,6 +18,7 @@ import ExceptionSafety import Exceptions1 import Exceptions2 import Expressions +import FloatingPoint import Freed import Functions import IO @@ -72,6 +73,7 @@ newtype TCPPQuery = TExceptions1PackageQuery(Exceptions1Query q) or TExceptions2PackageQuery(Exceptions2Query q) or TExpressionsPackageQuery(ExpressionsQuery q) or + TFloatingPointPackageQuery(FloatingPointQuery q) or TFreedPackageQuery(FreedQuery q) or TFunctionsPackageQuery(FunctionsQuery q) or TIOPackageQuery(IOQuery q) or @@ -126,6 +128,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isExceptions1QueryMetadata(query, queryId, ruleId, category) or isExceptions2QueryMetadata(query, queryId, ruleId, category) or isExpressionsQueryMetadata(query, queryId, ruleId, category) or + isFloatingPointQueryMetadata(query, queryId, ruleId, category) or isFreedQueryMetadata(query, queryId, ruleId, category) or isFunctionsQueryMetadata(query, queryId, ruleId, category) or isIOQueryMetadata(query, queryId, ruleId, category) or diff --git a/cpp/common/src/codingstandards/cpp/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.qll b/cpp/common/src/codingstandards/cpp/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.qll new file mode 100644 index 0000000000..eecd349ad7 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.qll @@ -0,0 +1,141 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * Possible misuse of a generate infinite floating point value. + */ + +import cpp +import codeql.util.Boolean +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import codingstandards.cpp.RestrictedRangeAnalysis +import codingstandards.cpp.FloatingPoint +import codingstandards.cpp.AlertReporting +import semmle.code.cpp.controlflow.Guards +import semmle.code.cpp.dataflow.new.DataFlow +import semmle.code.cpp.dataflow.new.TaintTracking +import semmle.code.cpp.controlflow.Dominance + +module InvalidInfinityUsage implements DataFlow::ConfigSig { + /** + * An operation which does not have Infinity as an input, but may produce Infinity, according + * to the `RestrictedRangeAnalysis` module. + */ + predicate isSource(DataFlow::Node node) { + potentialSource(node) and + not exists(DataFlow::Node prior | + isAdditionalFlowStep(prior, node) and + potentialSource(prior) + ) + } + + /** + * An operation which may produce Infinity acconding to the `RestrictedRangeAnalysis` module. + */ + additional predicate potentialSource(DataFlow::Node node) { + node.asExpr() instanceof Operation and + exprMayEqualInfinity(node.asExpr(), _) + } + + predicate isBarrierOut(DataFlow::Node node) { + guardedNotFPClass(node.asExpr(), TInfinite()) + or + exists(Expr e | + e.getType() instanceof IntegralType and + e = node.asConvertedExpr() + ) + } + + /** + * An additional flow step to handle operations which propagate Infinity. + * + * This double checks that an Infinity may propagate by checking the `RestrictedRangeAnalysis` + * value estimate. This is conservative, since `RestrictedRangeAnalysis` is performed locally + * in scope with unanalyzable values in a finite range. However, this conservative approach + * leverages analysis of guards and other local conditions to avoid false positives. + */ + predicate isAdditionalFlowStep(DataFlow::Node source, DataFlow::Node sink) { + exists(Operation o | + o.getAnOperand() = source.asExpr() and + o = sink.asExpr() and + potentialSource(sink) + ) + } + + predicate isSink(DataFlow::Node node) { + node instanceof InvalidInfinityUsage and + ( + // Require that range analysis finds this value potentially infinite, to avoid false positives + // in the presence of guards. This may induce false negatives. + exprMayEqualInfinity(node.asExpr(), _) + or + // Unanalyzable expressions are not checked against range analysis, which assumes a finite + // range. + not RestrictedRangeAnalysis::canBoundExpr(node.asExpr()) + or + node.asExpr().(VariableAccess).getTarget() instanceof Parameter + ) + } +} + +class InvalidInfinityUsage extends DataFlow::Node { + string description; + + InvalidInfinityUsage() { + // Case 2: NaNs and infinities shall not be cast to integers + exists(Conversion c | + asExpr() = c.getUnconverted() and + c.getExpr().getType() instanceof FloatingPointType and + c.getType() instanceof IntegralType and + description = "cast to integer." + ) + or + // Case 3: Infinities shall not underflow or otherwise produce finite values + exists(BinaryOperation op | + asExpr() = op.getRightOperand() and + op.getOperator() = "/" and + description = "divisor, which would silently underflow and produce zero." + ) + } + + string getDescription() { result = description } +} + +module InvalidInfinityFlow = DataFlow::Global; + +import InvalidInfinityFlow::PathGraph + +abstract class MisuseOfInfiniteFloatingPointValueSharedQuery extends Query { } + +Query getQuery() { result instanceof MisuseOfInfiniteFloatingPointValueSharedQuery } + +query predicate problems( + Element elem, InvalidInfinityFlow::PathNode source, InvalidInfinityFlow::PathNode sink, + string message, Expr sourceExpr, string sourceString, Function function, string functionName +) { + not isExcluded(elem, getQuery()) and + exists(InvalidInfinityUsage usage, string computedInFunction | + elem = MacroUnwrapper::unwrapElement(sink.getNode().asExpr()) and + not InvalidInfinityFlow::PathGraph::edges(_, source, _, _) and + not InvalidInfinityFlow::PathGraph::edges(sink, _, _, _) and + not sourceExpr.isFromTemplateInstantiation(_) and + not usage.asExpr().isFromTemplateInstantiation(_) and + usage = sink.getNode() and + sourceExpr = source.getNode().asExpr() and + function = sourceExpr.getEnclosingFunction() and + InvalidInfinityFlow::flow(source.getNode(), usage) and + ( + if not sourceExpr.getEnclosingFunction() = usage.asExpr().getEnclosingFunction() + then computedInFunction = "computed in function $@ " + else computedInFunction = "" + ) and + ( + if sourceExpr instanceof DivExpr + then sourceString = "from division by zero" + else sourceString = sourceExpr.toString() + ) and + message = + "Possibly infinite float value $@ " + computedInFunction + "flows to " + + usage.getDescription() and + functionName = function.getName() + ) +} diff --git a/cpp/common/src/codingstandards/cpp/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.qll b/cpp/common/src/codingstandards/cpp/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.qll new file mode 100644 index 0000000000..19ec4e1986 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.qll @@ -0,0 +1,201 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * Possible mishandling of an undetected NaN value produced by a floating point + * operation. + */ + +import cpp +import codeql.util.Boolean +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import codingstandards.cpp.RestrictedRangeAnalysis +import codingstandards.cpp.FloatingPoint +import codingstandards.cpp.AlertReporting +import semmle.code.cpp.controlflow.Guards +import semmle.code.cpp.dataflow.new.DataFlow +import semmle.code.cpp.dataflow.new.TaintTracking +import semmle.code.cpp.controlflow.Dominance + +abstract class PotentiallyNaNExpr extends Expr { + abstract string getReason(); +} + +class DomainErrorFunctionCall extends FunctionCall, PotentiallyNaNExpr { + string reason; + + DomainErrorFunctionCall() { RestrictedDomainError::hasDomainError(this, reason) } + + override string getReason() { result = reason } +} + +// IEEE 754-1985 Section 7.1 invalid operations +class InvalidOperationExpr extends BinaryOperation, PotentiallyNaNExpr { + string reason; + + InvalidOperationExpr() { + // Usual arithmetic conversions in both languages mean that if either operand is a floating + // type, the other one is converted to a floating type as well. + getAnOperand().getFullyConverted().getType() instanceof FloatingPointType and + ( + // 7.1.1 propagates signaling NaNs, we rely on flow analysis and/or assume quiet NaNs, so we + // intentionally do not cover this case. + // 7.1.2: magnitude subtraction of infinities, such as +Inf + -Inf + getOperator() = "+" and + exists(Boolean sign | + exprMayEqualInfinity(getLeftOperand(), sign) and + exprMayEqualInfinity(getRightOperand(), sign.booleanNot()) + ) and + reason = "from addition of infinity and negative infinity" + or + // 7.1.2 continued + getOperator() = "-" and + exists(Boolean sign | + exprMayEqualInfinity(getLeftOperand(), sign) and + exprMayEqualInfinity(getRightOperand(), sign) + ) and + reason = "from subtraction of an infinity from itself" + or + // 7.1.3: multiplication of zero by infinity + getOperator() = "*" and + exists(Expr zeroOp, Expr infinityOp | + zeroOp = getAnOperand() and + infinityOp = getAnOperand() and + not zeroOp = infinityOp and + exprMayEqualZero(zeroOp) and + exprMayEqualInfinity(infinityOp, _) + ) and + reason = "from multiplication of zero by infinity" + or + // 7.1.4: Division of zero by zero, or infinity by infinity + getOperator() = "/" and + exprMayEqualZero(getLeftOperand()) and + exprMayEqualZero(getRightOperand()) and + reason = "from division of zero by zero" + or + // 7.1.4 continued + getOperator() = "/" and + exprMayEqualInfinity(getLeftOperand(), _) and + exprMayEqualInfinity(getRightOperand(), _) and + reason = "from division of infinity by infinity" + or + // 7.1.5: x % y where y is zero or x is infinite + getOperator() = "%" and + exprMayEqualInfinity(getLeftOperand(), _) and + reason = "from modulus of infinity" + or + // 7.1.5 continued + getOperator() = "%" and + exprMayEqualZero(getRightOperand()) and + reason = "from modulus by zero" + // 7.1.6 handles the sqrt function, not covered here. + // 7.1.7 declares exceptions during invalid conversions, which we catch as sinks in our flow + // analysis. + // 7.1.8 declares exceptions for unordered comparisons, which we catch as sinks in our flow + // analysis. + ) + } + + override string getReason() { result = reason } +} + +module InvalidNaNUsage implements DataFlow::ConfigSig { + /** + * An expression which has non-NaN inputs and may produce a NaN output. + */ + predicate isSource(DataFlow::Node node) { + potentialSource(node) and + not exists(DataFlow::Node prior | + isAdditionalFlowStep(prior, node) and + potentialSource(prior) + ) + } + + /** + * An expression which may produce a NaN output. + */ + additional predicate potentialSource(DataFlow::Node node) { + node.asExpr() instanceof PotentiallyNaNExpr + } + + predicate isBarrierOut(DataFlow::Node node) { + guardedNotFPClass(node.asExpr(), TNaN()) + or + exists(Expr e | + e.getType() instanceof IntegralType and + e = node.asConvertedExpr() + ) + } + + /** + * Add an additional flow step to handle NaN propagation through floating point operations. + */ + predicate isAdditionalFlowStep(DataFlow::Node source, DataFlow::Node sink) { + exists(Operation o | + o.getAnOperand() = source.asExpr() and + o = sink.asExpr() and + o.getType() instanceof FloatingPointType + ) + } + + predicate isSink(DataFlow::Node node) { + not guardedNotFPClass(node.asExpr(), TNaN()) and + node instanceof InvalidNaNUsage + } +} + +class InvalidNaNUsage extends DataFlow::Node { + string description; + + InvalidNaNUsage() { + // Case 1: NaNs shall not be compared, except to themselves + exists(ComparisonOperation cmp | + this.asExpr() = cmp.getAnOperand() and + not hashCons(cmp.getLeftOperand()) = hashCons(cmp.getRightOperand()) and + description = "comparison, which would always evaluate to false." + ) + or + // Case 2: NaNs and infinities shall not be cast to integers + exists(Conversion c | + this.asExpr() = c.getUnconverted() and + c.getExpr().getType() instanceof FloatingPointType and + c.getType() instanceof IntegralType and + description = "a cast to integer." + ) + } + + string getDescription() { result = description } +} + +module InvalidNaNFlow = DataFlow::Global; + +import InvalidNaNFlow::PathGraph + +abstract class MisuseOfNaNFloatingPointValueSharedQuery extends Query { } + +Query getQuery() { result instanceof MisuseOfNaNFloatingPointValueSharedQuery } + +query predicate problems( + Element elem, InvalidNaNFlow::PathNode source, InvalidNaNFlow::PathNode sink, string message, + Expr sourceExpr, string sourceString, Function function, string functionName +) { + not isExcluded(elem, getQuery()) and + exists(InvalidNaNUsage usage, string computedInFunction | + not InvalidNaNFlow::PathGraph::edges(_, source, _, _) and + not InvalidNaNFlow::PathGraph::edges(sink, _, _, _) and + not sourceExpr.isFromTemplateInstantiation(_) and + not usage.asExpr().isFromTemplateInstantiation(_) and + elem = MacroUnwrapper::unwrapElement(sink.getNode().asExpr()) and + usage = sink.getNode() and + sourceExpr = source.getNode().asExpr() and + sourceString = source.getNode().asExpr().(PotentiallyNaNExpr).getReason() and + function = sourceExpr.getEnclosingFunction() and + InvalidNaNFlow::flow(source.getNode(), usage) and + ( + if not sourceExpr.getEnclosingFunction() = usage.asExpr().getEnclosingFunction() + then computedInFunction = "computed in function $@ " + else computedInFunction = "" + ) and + message = "Possible NaN value $@ " + computedInFunction + "flows to " + usage.getDescription() and + functionName = function.getName() + ) +} diff --git a/cpp/common/test/includes/standard-library/cmath b/cpp/common/test/includes/standard-library/cmath index e69de29bb2..9f3fffda8d 100644 --- a/cpp/common/test/includes/standard-library/cmath +++ b/cpp/common/test/includes/standard-library/cmath @@ -0,0 +1,19 @@ +namespace std { +#include + +int isinf(float x); +int isinf(double x); +int isinf(long double x); +bool isfinite(float x); +bool isfinite(double x); +bool isfinite(long double x); +bool isnan(float x); +bool isnan(double x); +bool isnan(long double x); +bool isnormal(float x); +bool isnormal(double x); +bool isnormal(long double x); +int fpclassify(float x); +int fpclassify(double x); +int fpclassify(long double x); +} \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/math.h b/cpp/common/test/includes/standard-library/math.h index 460c0a9c2f..7ff0ef8357 100644 --- a/cpp/common/test/includes/standard-library/math.h +++ b/cpp/common/test/includes/standard-library/math.h @@ -17,6 +17,9 @@ long double acoshl(long double x); double atanh(double x); float atanhf(float x); long double atanhl(long double x); +float cos(float x); +double cos(double x); +long double cos(long double x); double fmod(double x, double y); float fmodf(float x, float y); long double fmodl(long double x, long double y); @@ -47,6 +50,9 @@ long double logbl(long double x); double pow(double x, double y); float powf(float x, float y); long double powl(long double x, long double y); +float sin(float x); +double sin(double x); +long double sin(long double x); double sqrt(double x); float sqrtf(float x); long double sqrtl(long double x); diff --git a/cpp/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.expected b/cpp/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.expected new file mode 100644 index 0000000000..45bc2466b6 --- /dev/null +++ b/cpp/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.expected @@ -0,0 +1,113 @@ +problems +| test.cpp:12:8:12:9 | l2 | test.cpp:8:14:8:20 | ... / ... | test.cpp:12:8:12:9 | l2 | Possibly infinite float value $@ flows to divisor, which would silently underflow and produce zero. | test.cpp:8:14:8:20 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:13:8:13:9 | l3 | test.cpp:8:14:8:20 | ... / ... | test.cpp:13:8:13:9 | l3 | Possibly infinite float value $@ flows to divisor, which would silently underflow and produce zero. | test.cpp:8:14:8:20 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:18:20:18:21 | l2 | test.cpp:8:14:8:20 | ... / ... | test.cpp:18:3:18:22 | l2 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:8:14:8:20 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:19:20:19:21 | l3 | test.cpp:8:14:8:20 | ... / ... | test.cpp:19:3:19:22 | l3 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:8:14:8:20 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:29:19:29:20 | l2 | test.cpp:8:14:8:20 | ... / ... | test.cpp:29:19:29:20 | l2 | Possibly infinite float value $@ flows to divisor, which would silently underflow and produce zero. | test.cpp:8:14:8:20 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:30:19:30:20 | l3 | test.cpp:8:14:8:20 | ... / ... | test.cpp:30:19:30:20 | l3 | Possibly infinite float value $@ flows to divisor, which would silently underflow and produce zero. | test.cpp:8:14:8:20 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:40:20:40:21 | l7 | test.cpp:33:14:34:15 | ... / ... | test.cpp:40:3:40:22 | l7 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:33:14:34:15 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:64:9:64:15 | ... / ... | test.cpp:63:5:64:16 | ... / ... | test.cpp:63:5:64:16 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.cpp:64:9:64:15 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:70:9:70:17 | ... / ... | test.cpp:69:5:70:18 | ... / ... | test.cpp:69:5:70:18 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.cpp:70:9:70:17 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:76:31:76:39 | ... / ... | test.cpp:76:14:76:40 | ... / ... | test.cpp:76:14:76:40 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.cpp:76:31:76:39 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:79:35:79:43 | ... / ... | test.cpp:79:18:79:44 | ... / ... | test.cpp:79:18:79:44 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.cpp:79:35:79:43 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:83:22:83:24 | l12 | test.cpp:81:15:81:21 | ... / ... | test.cpp:83:5:83:25 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:81:15:81:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:91:22:91:24 | l12 | test.cpp:81:15:81:21 | ... / ... | test.cpp:91:5:91:25 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:81:15:81:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:95:22:95:24 | l12 | test.cpp:81:15:81:21 | ... / ... | test.cpp:95:5:95:25 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:81:15:81:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:97:22:97:24 | l12 | test.cpp:81:15:81:21 | ... / ... | test.cpp:97:5:97:25 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:81:15:81:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:103:22:103:24 | l12 | test.cpp:81:15:81:21 | ... / ... | test.cpp:103:5:103:25 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:81:15:81:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:109:22:109:24 | l12 | test.cpp:81:15:81:21 | ... / ... | test.cpp:109:5:109:25 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:81:15:81:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:115:22:115:24 | l12 | test.cpp:81:15:81:21 | ... / ... | test.cpp:115:5:115:25 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:81:15:81:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:118:38:118:40 | l12 | test.cpp:81:15:81:21 | ... / ... | test.cpp:118:21:118:41 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:81:15:81:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:127:26:127:28 | l12 | test.cpp:81:15:81:21 | ... / ... | test.cpp:127:9:127:29 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:81:15:81:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:133:26:133:28 | l12 | test.cpp:81:15:81:21 | ... / ... | test.cpp:133:9:133:29 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:81:15:81:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:188:7:189:17 | ... / ... | test.cpp:187:3:189:18 | ... / ... | test.cpp:187:3:189:18 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.cpp:188:7:189:17 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:202:44:202:44 | p | test.cpp:216:51:216:59 | ... / ... | test.cpp:202:27:202:45 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.cpp:216:51:216:59 | ... / ... | from division by zero | test.cpp:216:6:216:24 | addInfThenCastToInt | addInfThenCastToInt | +| test.cpp:202:44:202:44 | p | test.cpp:220:13:221:15 | ... / ... | test.cpp:202:27:202:45 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.cpp:220:13:221:15 | ... / ... | from division by zero | test.cpp:219:6:219:7 | f2 | f2 | +| test.cpp:202:44:202:44 | p | test.cpp:231:19:231:27 | ... / ... | test.cpp:202:27:202:45 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.cpp:231:19:231:27 | ... / ... | from division by zero | test.cpp:219:6:219:7 | f2 | f2 | +| test.cpp:212:30:212:30 | p | test.cpp:227:25:227:33 | ... / ... | test.cpp:212:13:212:31 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.cpp:227:25:227:33 | ... / ... | from division by zero | test.cpp:219:6:219:7 | f2 | f2 | +edges +| test.cpp:8:14:8:20 | ... / ... | test.cpp:8:14:8:20 | ... / ... | provenance | | +| test.cpp:8:14:8:20 | ... / ... | test.cpp:9:14:9:16 | - ... | provenance | Config | +| test.cpp:8:14:8:20 | ... / ... | test.cpp:12:8:12:9 | l2 | provenance | | +| test.cpp:8:14:8:20 | ... / ... | test.cpp:18:3:18:22 | l2 | provenance | | +| test.cpp:8:14:8:20 | ... / ... | test.cpp:29:19:29:20 | l2 | provenance | | +| test.cpp:9:14:9:16 | - ... | test.cpp:9:14:9:16 | - ... | provenance | | +| test.cpp:9:14:9:16 | - ... | test.cpp:13:8:13:9 | l3 | provenance | | +| test.cpp:9:14:9:16 | - ... | test.cpp:19:3:19:22 | l3 | provenance | | +| test.cpp:9:14:9:16 | - ... | test.cpp:30:19:30:20 | l3 | provenance | | +| test.cpp:33:14:34:15 | ... / ... | test.cpp:33:14:34:15 | ... / ... | provenance | | +| test.cpp:33:14:34:15 | ... / ... | test.cpp:40:3:40:22 | l7 | provenance | | +| test.cpp:81:15:81:21 | ... / ... | test.cpp:81:15:81:21 | ... / ... | provenance | | +| test.cpp:81:15:81:21 | ... / ... | test.cpp:83:5:83:25 | l12 | provenance | | +| test.cpp:81:15:81:21 | ... / ... | test.cpp:91:5:91:25 | l12 | provenance | | +| test.cpp:81:15:81:21 | ... / ... | test.cpp:95:5:95:25 | l12 | provenance | | +| test.cpp:81:15:81:21 | ... / ... | test.cpp:97:5:97:25 | l12 | provenance | | +| test.cpp:81:15:81:21 | ... / ... | test.cpp:103:5:103:25 | l12 | provenance | | +| test.cpp:81:15:81:21 | ... / ... | test.cpp:109:5:109:25 | l12 | provenance | | +| test.cpp:81:15:81:21 | ... / ... | test.cpp:115:5:115:25 | l12 | provenance | | +| test.cpp:81:15:81:21 | ... / ... | test.cpp:118:21:118:41 | l12 | provenance | | +| test.cpp:81:15:81:21 | ... / ... | test.cpp:127:9:127:29 | l12 | provenance | | +| test.cpp:81:15:81:21 | ... / ... | test.cpp:133:9:133:29 | l12 | provenance | | +| test.cpp:202:22:202:22 | p | test.cpp:202:27:202:45 | p | provenance | | +| test.cpp:210:34:210:34 | p | test.cpp:212:13:212:31 | p | provenance | | +| test.cpp:216:32:216:32 | p | test.cpp:216:47:216:59 | ... + ... | provenance | Config | +| test.cpp:216:47:216:59 | ... + ... | test.cpp:202:22:202:22 | p | provenance | | +| test.cpp:216:47:216:59 | ... + ... | test.cpp:202:22:202:22 | p | provenance | | +| test.cpp:216:51:216:59 | ... / ... | test.cpp:216:47:216:59 | ... + ... | provenance | Config | +| test.cpp:220:13:221:15 | ... / ... | test.cpp:202:22:202:22 | p | provenance | | +| test.cpp:227:25:227:33 | ... / ... | test.cpp:210:34:210:34 | p | provenance | | +| test.cpp:231:19:231:27 | ... / ... | test.cpp:231:19:231:27 | ... / ... | provenance | | +| test.cpp:231:19:231:27 | ... / ... | test.cpp:233:21:233:31 | ... + ... | provenance | Config | +| test.cpp:233:21:233:31 | ... + ... | test.cpp:233:21:233:31 | ... + ... | provenance | | +| test.cpp:233:21:233:31 | ... + ... | test.cpp:235:13:235:21 | middleInf | provenance | | +| test.cpp:233:21:233:31 | ... + ... | test.cpp:237:23:237:31 | middleInf | provenance | | +| test.cpp:235:13:235:21 | middleInf | test.cpp:202:22:202:22 | p | provenance | | +| test.cpp:237:23:237:31 | middleInf | test.cpp:216:32:216:32 | p | provenance | | +nodes +| test.cpp:8:14:8:20 | ... / ... | semmle.label | ... / ... | +| test.cpp:8:14:8:20 | ... / ... | semmle.label | ... / ... | +| test.cpp:9:14:9:16 | - ... | semmle.label | - ... | +| test.cpp:9:14:9:16 | - ... | semmle.label | - ... | +| test.cpp:12:8:12:9 | l2 | semmle.label | l2 | +| test.cpp:13:8:13:9 | l3 | semmle.label | l3 | +| test.cpp:18:3:18:22 | l2 | semmle.label | l2 | +| test.cpp:19:3:19:22 | l3 | semmle.label | l3 | +| test.cpp:29:19:29:20 | l2 | semmle.label | l2 | +| test.cpp:30:19:30:20 | l3 | semmle.label | l3 | +| test.cpp:33:14:34:15 | ... / ... | semmle.label | ... / ... | +| test.cpp:33:14:34:15 | ... / ... | semmle.label | ... / ... | +| test.cpp:40:3:40:22 | l7 | semmle.label | l7 | +| test.cpp:63:5:64:16 | ... / ... | semmle.label | ... / ... | +| test.cpp:69:5:70:18 | ... / ... | semmle.label | ... / ... | +| test.cpp:76:14:76:40 | ... / ... | semmle.label | ... / ... | +| test.cpp:79:18:79:44 | ... / ... | semmle.label | ... / ... | +| test.cpp:81:15:81:21 | ... / ... | semmle.label | ... / ... | +| test.cpp:81:15:81:21 | ... / ... | semmle.label | ... / ... | +| test.cpp:83:5:83:25 | l12 | semmle.label | l12 | +| test.cpp:91:5:91:25 | l12 | semmle.label | l12 | +| test.cpp:95:5:95:25 | l12 | semmle.label | l12 | +| test.cpp:97:5:97:25 | l12 | semmle.label | l12 | +| test.cpp:103:5:103:25 | l12 | semmle.label | l12 | +| test.cpp:109:5:109:25 | l12 | semmle.label | l12 | +| test.cpp:115:5:115:25 | l12 | semmle.label | l12 | +| test.cpp:118:21:118:41 | l12 | semmle.label | l12 | +| test.cpp:127:9:127:29 | l12 | semmle.label | l12 | +| test.cpp:133:9:133:29 | l12 | semmle.label | l12 | +| test.cpp:187:3:189:18 | ... / ... | semmle.label | ... / ... | +| test.cpp:202:22:202:22 | p | semmle.label | p | +| test.cpp:202:27:202:45 | p | semmle.label | p | +| test.cpp:210:34:210:34 | p | semmle.label | p | +| test.cpp:212:13:212:31 | p | semmle.label | p | +| test.cpp:216:32:216:32 | p | semmle.label | p | +| test.cpp:216:47:216:59 | ... + ... | semmle.label | ... + ... | +| test.cpp:216:47:216:59 | ... + ... | semmle.label | ... + ... | +| test.cpp:216:51:216:59 | ... / ... | semmle.label | ... / ... | +| test.cpp:220:13:221:15 | ... / ... | semmle.label | ... / ... | +| test.cpp:227:25:227:33 | ... / ... | semmle.label | ... / ... | +| test.cpp:231:19:231:27 | ... / ... | semmle.label | ... / ... | +| test.cpp:231:19:231:27 | ... / ... | semmle.label | ... / ... | +| test.cpp:233:21:233:31 | ... + ... | semmle.label | ... + ... | +| test.cpp:233:21:233:31 | ... + ... | semmle.label | ... + ... | +| test.cpp:235:13:235:21 | middleInf | semmle.label | middleInf | +| test.cpp:237:23:237:31 | middleInf | semmle.label | middleInf | +subpaths diff --git a/cpp/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.ql b/cpp/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.ql new file mode 100644 index 0000000000..f0d160a650 --- /dev/null +++ b/cpp/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.misuseofinfinitefloatingpointvalue.MisuseOfInfiniteFloatingPointValue + +class TestFileQuery extends MisuseOfInfiniteFloatingPointValueSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/misuseofinfinitefloatingpointvalue/test.cpp b/cpp/common/test/rules/misuseofinfinitefloatingpointvalue/test.cpp new file mode 100644 index 0000000000..a0624ccbf3 --- /dev/null +++ b/cpp/common/test/rules/misuseofinfinitefloatingpointvalue/test.cpp @@ -0,0 +1,239 @@ +#include + +float getFloat() { return 1.0; } + +// Parameter could be infinity +void f1(float p1) { + float l1 = 1; + float l2 = 1.0 / 0; + float l3 = -l2; + + 10 / l1; // COMPLIANT + 10 / l2; // NON_COMPLIANT: Underflows to zero + 10 / l3; // NON_COMPLIANT: Underflow to negative zero + 10 / p1; // COMPLIANT: Reduce false positives by assuming not infinity + 10 / getFloat(); // COMPLIANT: Reduce false positives by assuming not infinity + + static_cast(l1); // COMPLIANT + static_cast(l2); // NON_COMPLIANT + static_cast(l3); // NON_COMPLIANT + static_cast( + p1); // COMPLIANT: Reduce false positives by assuming not infinity + static_cast( + getFloat()); // COMPLIANT: Reduce false positives by assuming not infinity + + // Not NaN: + float l4 = l1 / l1; // COMPLIANT + + // NaN because of infinity divided by itself: + float l5 = l2 / l2; // NON_COMPLIANT: Division by infinity not allowed. + float l6 = l3 / l3; // NON_COMPLIANT: Division by infinity not allowed. + + // NaN because of zero divided by itself: + float l7 = getFloat() / + p1; // COMPLIANT: Reduce false positives by assuming not infinity + float l8 = 0.0 / 0.0; + + static_cast(l4); // COMPLIANT + static_cast(l5); // COMPLIANT: Casting NaN to int + static_cast(l6); // COMPLIANT: Casting NaN to int + static_cast(l7); // NON_COMPLIANT: Casting Infinity to int + static_cast(l8); // COMPLIANT: Casting NaN to int + + l4 == 0; // COMPLIANT + l4 != 0; // COMPLIANT + l4 <= 0; // COMPLIANT + l4 < 0; // COMPLIANT + l4 >= 0; // COMPLIANT + l5 == 0; // NON_COMPLIANT: Comparison with NaN always false + l5 != 0; // NON_COMPLIANT: Comparison with NaN always false + l5 < 0; // NON_COMPLIANT: Comparison with NaN always false + l5 <= 0; // NON_COMPLIANT: Comparison with NaN always false + l5 > 0; // NON_COMPLIANT: Comparison with NaN always false + l5 >= 0; // NON_COMPLIANT: Comparison with NaN always false + l6 == 0; // NON_COMPLIANT: Comparison with NaN always false + l7 == 0; // NON_COMPLIANT: Comparison with NaN always false + l8 == 0; // NON_COMPLIANT: Comparison with NaN always false + + // Guards + float l9 = 0; + if (l9 != 0) { + static_cast(l9 / l9); // COMPLIANT: l9 is not zero + } else { + static_cast( + l9 / l9); // NON_COMPLIANT[False positive]: Guarded to not be NaN + } + + float l10 = 0; + if (l10 == 0) { + static_cast( + l10 / l10); // NON_COMPLIANT[False positive]: Casting NaN to integer + } else { + static_cast(l10 / l10); // COMPLIANT: Guarded to not be NaN + } + + float l11 = 0; + l11 == 0 ? static_cast(l11 / l11) : 0; // NON_COMPLIANT[False positive] + l11 == 0 ? 0 : static_cast(l11 / l11); // COMPLIANT + l11 != 0 ? static_cast(l11 / l11) : 0; // COMPLIANT + l11 != 0 ? 0 : static_cast(l11 / l11); // NON_COMPLIANT[False positive] + + float l12 = 1.0 / 0; + if (std::isinf(l12)) { + static_cast(l12); // NON_COMPLIANT: Casting Infinity to integer + } else { + static_cast(l12); // COMPLIANT: Guarded not to be Infinity + } + + if (!std::isinf(l12)) { + static_cast(l12); // COMPLIANT: Guarded not to be Infinity + } else { + static_cast(l12); // NON_COMPLIANT: Casting Infinity to integer + } + + if (std::isinf(l12) == 1) { + static_cast(l12); // NON_COMPLIANT: Must be +Infinity + } else { + static_cast(l12); // NON_COMPLIANT: May be -Infinity + } + + if (std::isfinite(l12)) { + static_cast(l12); // COMPLIANT: Guarded not to be Infinity + } else { + static_cast(l12); // NON_COMPLIANT: Casting Infinity to integer + } + + if (std::isnormal(l12)) { + static_cast(l12); // COMPLIANT: Guarded not to be Infinity + } else { + static_cast(l12); // NON_COMPLIANT: Casting Infinity to integer + } + + if (std::isnan(l12)) { + static_cast(l12); // COMPLIANT: Guarded not to be Infinity + } else { + static_cast(l12); // NON_COMPLIANT: Casting Infinity to integer + } + + std::isinf(l12) ? static_cast(l12) + : 0; // NON_COMPLIANT: Check on wrong branch + std::isinf(l12) + ? 0 + : static_cast(l12); // COMPLIANT: Checked not infinite before use + std::isfinite(l12) ? static_cast(l12) + : 0; // COMPLIANT: Checked finite before use + std::isfinite(l12) + ? 0 + : static_cast(l12); // NON_COMPLIANT: Checked on wrong branch + std::isnan(l12) + ? static_cast(l12) + : 0; // COMPLIANT: Checked NaN, therefore not infinite, before use + std::isnan(l12) + ? 0 + : static_cast(l12); // NON_COMPLIANT: Check on wrong branch + + float l13 = 0.0 / 0; + if (std::isinf(l13)) { + static_cast(l13); // COMPLIANT: Guarded not to be NaN + } else { + static_cast(l13); // COMPLIANT: Casting NaN to integer + } + + if (std::isinf(l13) == 1) { + static_cast( + l13); // COMPLIANT: Guarded not to be NaN (must be +Infinity) + } else { + static_cast(l13); // COMPLIANT: Casting NaN to integer + } + + if (std::isfinite(l13)) { + static_cast(l13); // COMPLIANT: Guarded not to be NaN + } else { + static_cast(l13); // COMPLIANT: Casting NaN to integer + } + + if (std::isnormal(l13)) { + static_cast(l13); // COMPLIANT: Guarded not to be NaN + } else { + static_cast(l13); // COMPLIANT: Casting NaN to integer + } + + if (std::isnan(l13)) { + static_cast(l13); // COMPLIANT: Casting NaN to integer + } else { + static_cast(l13); // COMPLIANT: Guarded not to be NaN + } + + std::isinf(l13) + ? static_cast(l13) + : 0; // COMPLIANT: Checked infinite, therefore not NaN, before use + std::isinf(l13) ? 0 + : static_cast(l13); // COMPLIANT: Check on wrong branch + std::isfinite(l13) ? static_cast(l13) + : 0; // COMPLIANT: Checked finite before use + std::isfinite(l13) + ? 0 + : static_cast(l13); // COMPLIANT: Checked on wrong branch + std::isnan(l13) ? static_cast(l13) + : 0; // COMPLIANT: Check on wrong branch + std::isnan(l13) + ? 0 + : static_cast(l13); // COMPLIANT: Checked not NaN before use + + static_cast( + std::pow(2, p1)); // NON_COMPLIANT[False negative]: likely to be Infinity + static_cast( + std::pow(2, std::sin(p1))); // COMPLIANT: not likely to be Infinity + static_cast( + 1 / std::sin( + p1)); // NON_COMPLIANT: possible infinity from zero in denominator + static_cast(1 / + std::log(p1)); // COMPLIANT: not possibly zero in denominator + static_cast(std::pow(p1, p1)); // COMPLIANT: NaN if p1 is zero + if (p1 != 0) { + static_cast(std::pow(p1, p1)); // COMPLIANT: p1 is not zero + } + + static_cast(std::acos(p1)); // COMPLIANT: NaN if p1 is not within -1..1 + static_cast( + std::acos(std::cos(p1))); // COMPLIANT: cos(p1) is within -1..1 +} + +void castToInt(float p) { static_cast(p); } + +void checkBeforeCastToInt(float p) { + if (std::isfinite(p)) { + castToInt(p); + } +} + +void castToIntToFloatToInt(float p) { + // This should be reported as a violation, but not downstream from here. + castToInt(static_cast(p)); +} + +void addOneThenCastToInt(float p) { castToInt(p + 1); } +void addInfThenCastToInt(float p) { castToInt(p + 1.0 / 0.0); } +void addNaNThenCastToInt(float p) { castToInt(p + 0.0 / 0.0); } + +void f2() { + castToInt(1.0 / + 0.0); // NON_COMPLIANT: Infinity flows to denominator in division + castToInt(0.0 / 0.0); // COMPLIANT + checkBeforeCastToInt(1.0 / 0.0); // COMPLIANT + checkBeforeCastToInt(0.0 / 0.0); // COMPLIANT + addOneThenCastToInt(1.0 / 0.0); // NON_COMPLIANT[False negative] + addOneThenCastToInt(0.0 / 0.0); // NON_COMPLIANT + castToIntToFloatToInt(1.0 / 0.0); // NON_COMPLIANT + castToIntToFloatToInt(0.0 / 0.0); // COMPLIANT + + // Check that during flow analysis, we only report the true root cause: + float rootInf = 1.0 / 0.0; + float rootNaN = 0.0 / 0.0; + float middleInf = rootInf + 1; + float middleNaN = rootNaN + 1; + castToInt(middleInf); // NON_COMPLIANT + castToInt(middleNaN); // COMPLIANT + addInfThenCastToInt(middleInf); // NON_COMPLIANT + addNaNThenCastToInt(middleNaN); // COMPLIANT +} \ No newline at end of file diff --git a/cpp/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.expected b/cpp/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.expected new file mode 100644 index 0000000000..5e4d3cacd7 --- /dev/null +++ b/cpp/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.expected @@ -0,0 +1,136 @@ +problems +| test.cpp:36:8:36:9 | l5 | test.cpp:27:14:27:20 | ... / ... | test.cpp:36:3:36:9 | l5 | Possible NaN value $@ flows to a cast to integer. | test.cpp:27:14:27:20 | ... / ... | from division of infinity by infinity | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:37:8:37:9 | l6 | test.cpp:28:14:28:20 | ... / ... | test.cpp:37:3:37:9 | l6 | Possible NaN value $@ flows to a cast to integer. | test.cpp:28:14:28:20 | ... / ... | from division of infinity by infinity | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:38:8:38:9 | l7 | test.cpp:31:14:32:15 | ... / ... | test.cpp:38:3:38:9 | l7 | Possible NaN value $@ flows to a cast to integer. | test.cpp:31:14:32:15 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:39:8:39:9 | l8 | test.cpp:33:14:33:22 | ... / ... | test.cpp:39:3:39:9 | l8 | Possible NaN value $@ flows to a cast to integer. | test.cpp:33:14:33:22 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:46:3:46:4 | l5 | test.cpp:27:14:27:20 | ... / ... | test.cpp:46:3:46:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.cpp:27:14:27:20 | ... / ... | from division of infinity by infinity | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:47:3:47:4 | l5 | test.cpp:27:14:27:20 | ... / ... | test.cpp:47:3:47:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.cpp:27:14:27:20 | ... / ... | from division of infinity by infinity | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:48:3:48:4 | l5 | test.cpp:27:14:27:20 | ... / ... | test.cpp:48:3:48:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.cpp:27:14:27:20 | ... / ... | from division of infinity by infinity | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:49:3:49:4 | l5 | test.cpp:27:14:27:20 | ... / ... | test.cpp:49:3:49:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.cpp:27:14:27:20 | ... / ... | from division of infinity by infinity | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:50:3:50:4 | l5 | test.cpp:27:14:27:20 | ... / ... | test.cpp:50:3:50:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.cpp:27:14:27:20 | ... / ... | from division of infinity by infinity | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:51:3:51:4 | l5 | test.cpp:27:14:27:20 | ... / ... | test.cpp:51:3:51:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.cpp:27:14:27:20 | ... / ... | from division of infinity by infinity | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:52:3:52:4 | l6 | test.cpp:28:14:28:20 | ... / ... | test.cpp:52:3:52:4 | l6 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.cpp:28:14:28:20 | ... / ... | from division of infinity by infinity | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:53:3:53:4 | l7 | test.cpp:31:14:32:15 | ... / ... | test.cpp:53:3:53:4 | l7 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.cpp:31:14:32:15 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:54:3:54:4 | l8 | test.cpp:33:14:33:22 | ... / ... | test.cpp:54:3:54:4 | l8 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.cpp:33:14:33:22 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:61:11:61:17 | ... / ... | test.cpp:61:5:61:18 | ... / ... | test.cpp:61:5:61:18 | ... / ... | Possible NaN value $@ flows to a cast to integer. | test.cpp:61:11:61:17 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:66:11:66:19 | ... / ... | test.cpp:66:5:66:20 | ... / ... | test.cpp:66:5:66:20 | ... / ... | Possible NaN value $@ flows to a cast to integer. | test.cpp:66:11:66:19 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:72:20:72:28 | ... / ... | test.cpp:72:14:72:29 | ... / ... | test.cpp:72:14:72:29 | ... / ... | Possible NaN value $@ flows to a cast to integer. | test.cpp:72:20:72:28 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:75:24:75:32 | ... / ... | test.cpp:75:18:75:33 | ... / ... | test.cpp:75:18:75:33 | ... / ... | Possible NaN value $@ flows to a cast to integer. | test.cpp:75:24:75:32 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:127:10:127:12 | l13 | test.cpp:123:15:123:21 | ... / ... | test.cpp:127:5:127:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.cpp:123:15:123:21 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:133:10:133:12 | l13 | test.cpp:123:15:123:21 | ... / ... | test.cpp:133:5:133:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.cpp:123:15:123:21 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:139:10:139:12 | l13 | test.cpp:123:15:123:21 | ... / ... | test.cpp:139:5:139:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.cpp:123:15:123:21 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:145:10:145:12 | l13 | test.cpp:123:15:123:21 | ... / ... | test.cpp:145:5:145:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.cpp:123:15:123:21 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:149:10:149:12 | l13 | test.cpp:123:15:123:21 | ... / ... | test.cpp:149:5:149:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.cpp:123:15:123:21 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:157:30:157:32 | l13 | test.cpp:123:15:123:21 | ... / ... | test.cpp:157:25:157:32 | l13 | Possible NaN value $@ flows to a cast to integer. | test.cpp:123:15:123:21 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:159:33:159:35 | l13 | test.cpp:123:15:123:21 | ... / ... | test.cpp:159:28:159:35 | l13 | Possible NaN value $@ flows to a cast to integer. | test.cpp:123:15:123:21 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:160:26:160:28 | l13 | test.cpp:123:15:123:21 | ... / ... | test.cpp:160:21:160:28 | l13 | Possible NaN value $@ flows to a cast to integer. | test.cpp:123:15:123:21 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:168:8:168:15 | call to pow | test.cpp:168:3:168:23 | call to pow | test.cpp:168:3:168:23 | call to pow | Possible NaN value $@ flows to a cast to integer. | test.cpp:168:8:168:15 | call to pow | both arguments are equal to zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:173:8:173:16 | call to acos | test.cpp:173:3:173:20 | call to acos | test.cpp:173:3:173:20 | call to acos | Possible NaN value $@ flows to a cast to integer. | test.cpp:173:8:173:16 | call to acos | the argument has a range -1000000000000000...1000000000000000 which is outside the domain of this function (-1.0...1.0) | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:177:32:177:32 | p | test.cpp:192:51:192:59 | ... / ... | test.cpp:177:27:177:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.cpp:192:51:192:59 | ... / ... | from division of zero by zero | test.cpp:192:6:192:24 | addNaNThenCastToInt | addNaNThenCastToInt | +| test.cpp:177:32:177:32 | p | test.cpp:196:13:196:21 | ... / ... | test.cpp:177:27:177:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.cpp:196:13:196:21 | ... / ... | from division of zero by zero | test.cpp:194:6:194:7 | f2 | f2 | +| test.cpp:177:32:177:32 | p | test.cpp:200:23:200:31 | ... / ... | test.cpp:177:27:177:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.cpp:200:23:200:31 | ... / ... | from division of zero by zero | test.cpp:194:6:194:7 | f2 | f2 | +| test.cpp:177:32:177:32 | p | test.cpp:206:19:206:27 | ... / ... | test.cpp:177:27:177:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.cpp:206:19:206:27 | ... / ... | from division of zero by zero | test.cpp:194:6:194:7 | f2 | f2 | +| test.cpp:187:18:187:18 | p | test.cpp:202:25:202:33 | ... / ... | test.cpp:187:13:187:18 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.cpp:202:25:202:33 | ... / ... | from division of zero by zero | test.cpp:194:6:194:7 | f2 | f2 | +edges +| test.cpp:27:14:27:20 | ... / ... | test.cpp:27:14:27:20 | ... / ... | provenance | | +| test.cpp:27:14:27:20 | ... / ... | test.cpp:36:3:36:9 | l5 | provenance | | +| test.cpp:27:14:27:20 | ... / ... | test.cpp:46:3:46:4 | l5 | provenance | | +| test.cpp:27:14:27:20 | ... / ... | test.cpp:47:3:47:4 | l5 | provenance | | +| test.cpp:27:14:27:20 | ... / ... | test.cpp:48:3:48:4 | l5 | provenance | | +| test.cpp:27:14:27:20 | ... / ... | test.cpp:49:3:49:4 | l5 | provenance | | +| test.cpp:27:14:27:20 | ... / ... | test.cpp:50:3:50:4 | l5 | provenance | | +| test.cpp:27:14:27:20 | ... / ... | test.cpp:51:3:51:4 | l5 | provenance | | +| test.cpp:28:14:28:20 | ... / ... | test.cpp:28:14:28:20 | ... / ... | provenance | | +| test.cpp:28:14:28:20 | ... / ... | test.cpp:37:3:37:9 | l6 | provenance | | +| test.cpp:28:14:28:20 | ... / ... | test.cpp:52:3:52:4 | l6 | provenance | | +| test.cpp:31:14:32:15 | ... / ... | test.cpp:31:14:32:15 | ... / ... | provenance | | +| test.cpp:31:14:32:15 | ... / ... | test.cpp:38:3:38:9 | l7 | provenance | | +| test.cpp:31:14:32:15 | ... / ... | test.cpp:53:3:53:4 | l7 | provenance | | +| test.cpp:33:14:33:22 | ... / ... | test.cpp:33:14:33:22 | ... / ... | provenance | | +| test.cpp:33:14:33:22 | ... / ... | test.cpp:39:3:39:9 | l8 | provenance | | +| test.cpp:33:14:33:22 | ... / ... | test.cpp:54:3:54:4 | l8 | provenance | | +| test.cpp:123:15:123:21 | ... / ... | test.cpp:123:15:123:21 | ... / ... | provenance | | +| test.cpp:123:15:123:21 | ... / ... | test.cpp:127:5:127:12 | l13 | provenance | | +| test.cpp:123:15:123:21 | ... / ... | test.cpp:133:5:133:12 | l13 | provenance | | +| test.cpp:123:15:123:21 | ... / ... | test.cpp:139:5:139:12 | l13 | provenance | | +| test.cpp:123:15:123:21 | ... / ... | test.cpp:145:5:145:12 | l13 | provenance | | +| test.cpp:123:15:123:21 | ... / ... | test.cpp:149:5:149:12 | l13 | provenance | | +| test.cpp:123:15:123:21 | ... / ... | test.cpp:157:25:157:32 | l13 | provenance | | +| test.cpp:123:15:123:21 | ... / ... | test.cpp:159:28:159:35 | l13 | provenance | | +| test.cpp:123:15:123:21 | ... / ... | test.cpp:160:21:160:28 | l13 | provenance | | +| test.cpp:177:22:177:22 | p | test.cpp:177:27:177:32 | p | provenance | | +| test.cpp:185:34:185:34 | p | test.cpp:187:13:187:18 | p | provenance | | +| test.cpp:190:32:190:32 | p | test.cpp:190:47:190:51 | ... + ... | provenance | Config | +| test.cpp:190:47:190:51 | ... + ... | test.cpp:177:22:177:22 | p | provenance | | +| test.cpp:192:32:192:32 | p | test.cpp:192:47:192:59 | ... + ... | provenance | Config | +| test.cpp:192:47:192:59 | ... + ... | test.cpp:177:22:177:22 | p | provenance | | +| test.cpp:192:47:192:59 | ... + ... | test.cpp:177:22:177:22 | p | provenance | | +| test.cpp:192:51:192:59 | ... / ... | test.cpp:192:47:192:59 | ... + ... | provenance | Config | +| test.cpp:196:13:196:21 | ... / ... | test.cpp:177:22:177:22 | p | provenance | | +| test.cpp:200:23:200:31 | ... / ... | test.cpp:190:32:190:32 | p | provenance | | +| test.cpp:202:25:202:33 | ... / ... | test.cpp:185:34:185:34 | p | provenance | | +| test.cpp:206:19:206:27 | ... / ... | test.cpp:206:19:206:27 | ... / ... | provenance | | +| test.cpp:206:19:206:27 | ... / ... | test.cpp:208:21:208:31 | ... + ... | provenance | Config | +| test.cpp:208:21:208:31 | ... + ... | test.cpp:208:21:208:31 | ... + ... | provenance | | +| test.cpp:208:21:208:31 | ... + ... | test.cpp:210:13:210:21 | middleNaN | provenance | | +| test.cpp:208:21:208:31 | ... + ... | test.cpp:212:23:212:31 | middleNaN | provenance | | +| test.cpp:210:13:210:21 | middleNaN | test.cpp:177:22:177:22 | p | provenance | | +| test.cpp:212:23:212:31 | middleNaN | test.cpp:192:32:192:32 | p | provenance | | +nodes +| test.cpp:27:14:27:20 | ... / ... | semmle.label | ... / ... | +| test.cpp:27:14:27:20 | ... / ... | semmle.label | ... / ... | +| test.cpp:28:14:28:20 | ... / ... | semmle.label | ... / ... | +| test.cpp:28:14:28:20 | ... / ... | semmle.label | ... / ... | +| test.cpp:31:14:32:15 | ... / ... | semmle.label | ... / ... | +| test.cpp:31:14:32:15 | ... / ... | semmle.label | ... / ... | +| test.cpp:33:14:33:22 | ... / ... | semmle.label | ... / ... | +| test.cpp:33:14:33:22 | ... / ... | semmle.label | ... / ... | +| test.cpp:36:3:36:9 | l5 | semmle.label | l5 | +| test.cpp:37:3:37:9 | l6 | semmle.label | l6 | +| test.cpp:38:3:38:9 | l7 | semmle.label | l7 | +| test.cpp:39:3:39:9 | l8 | semmle.label | l8 | +| test.cpp:46:3:46:4 | l5 | semmle.label | l5 | +| test.cpp:47:3:47:4 | l5 | semmle.label | l5 | +| test.cpp:48:3:48:4 | l5 | semmle.label | l5 | +| test.cpp:49:3:49:4 | l5 | semmle.label | l5 | +| test.cpp:50:3:50:4 | l5 | semmle.label | l5 | +| test.cpp:51:3:51:4 | l5 | semmle.label | l5 | +| test.cpp:52:3:52:4 | l6 | semmle.label | l6 | +| test.cpp:53:3:53:4 | l7 | semmle.label | l7 | +| test.cpp:54:3:54:4 | l8 | semmle.label | l8 | +| test.cpp:61:5:61:18 | ... / ... | semmle.label | ... / ... | +| test.cpp:66:5:66:20 | ... / ... | semmle.label | ... / ... | +| test.cpp:72:14:72:29 | ... / ... | semmle.label | ... / ... | +| test.cpp:75:18:75:33 | ... / ... | semmle.label | ... / ... | +| test.cpp:123:15:123:21 | ... / ... | semmle.label | ... / ... | +| test.cpp:123:15:123:21 | ... / ... | semmle.label | ... / ... | +| test.cpp:127:5:127:12 | l13 | semmle.label | l13 | +| test.cpp:133:5:133:12 | l13 | semmle.label | l13 | +| test.cpp:139:5:139:12 | l13 | semmle.label | l13 | +| test.cpp:145:5:145:12 | l13 | semmle.label | l13 | +| test.cpp:149:5:149:12 | l13 | semmle.label | l13 | +| test.cpp:157:25:157:32 | l13 | semmle.label | l13 | +| test.cpp:159:28:159:35 | l13 | semmle.label | l13 | +| test.cpp:160:21:160:28 | l13 | semmle.label | l13 | +| test.cpp:168:3:168:23 | call to pow | semmle.label | call to pow | +| test.cpp:173:3:173:20 | call to acos | semmle.label | call to acos | +| test.cpp:177:22:177:22 | p | semmle.label | p | +| test.cpp:177:27:177:32 | p | semmle.label | p | +| test.cpp:185:34:185:34 | p | semmle.label | p | +| test.cpp:187:13:187:18 | p | semmle.label | p | +| test.cpp:190:32:190:32 | p | semmle.label | p | +| test.cpp:190:47:190:51 | ... + ... | semmle.label | ... + ... | +| test.cpp:192:32:192:32 | p | semmle.label | p | +| test.cpp:192:47:192:59 | ... + ... | semmle.label | ... + ... | +| test.cpp:192:47:192:59 | ... + ... | semmle.label | ... + ... | +| test.cpp:192:51:192:59 | ... / ... | semmle.label | ... / ... | +| test.cpp:196:13:196:21 | ... / ... | semmle.label | ... / ... | +| test.cpp:200:23:200:31 | ... / ... | semmle.label | ... / ... | +| test.cpp:202:25:202:33 | ... / ... | semmle.label | ... / ... | +| test.cpp:206:19:206:27 | ... / ... | semmle.label | ... / ... | +| test.cpp:206:19:206:27 | ... / ... | semmle.label | ... / ... | +| test.cpp:208:21:208:31 | ... + ... | semmle.label | ... + ... | +| test.cpp:208:21:208:31 | ... + ... | semmle.label | ... + ... | +| test.cpp:210:13:210:21 | middleNaN | semmle.label | middleNaN | +| test.cpp:212:23:212:31 | middleNaN | semmle.label | middleNaN | +subpaths diff --git a/cpp/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.ql b/cpp/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.ql new file mode 100644 index 0000000000..a1f729ed02 --- /dev/null +++ b/cpp/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.misuseofnanfloatingpointvalue.MisuseOfNaNFloatingPointValue + +class TestFileQuery extends MisuseOfNaNFloatingPointValueSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/misuseofnanfloatingpointvalue/test.cpp b/cpp/common/test/rules/misuseofnanfloatingpointvalue/test.cpp new file mode 100644 index 0000000000..a68a47daf7 --- /dev/null +++ b/cpp/common/test/rules/misuseofnanfloatingpointvalue/test.cpp @@ -0,0 +1,213 @@ +#include + +float getFloat() { return 1.0; } + +// Parameter could be infinity +void f1(float p1) { + float l1 = 1; + float l2 = 1.0 / 0; + float l3 = -l2; + + 10 / l1; // COMPLIANT + 10 / l2; // COMPLIANT: Underflows to zero + 10 / l3; // COMPLIANT: Underflow to negative zero + 10 / p1; // COMPLIANT: Reduce false positives by assuming not infinity + 10 / getFloat(); // COMPLIANT: Reduce false positives by assuming not infinity + + (int)l1; // COMPLIANT + (int)l2; // COMPLIANT + (int)l3; // COMPLIANT + (int)p1; // COMPLIANT: Reduce false positives by assuming not infinity + (int)getFloat(); // COMPLIANT: Reduce false positives by assuming not infinity + + // Not NaN: + float l4 = l1 / l1; // COMPLIANT + + // NaN because of infinity divided by itself: + float l5 = l2 / l2; // COMPLIANT: Division by infinity not allowed. + float l6 = l3 / l3; // COMPLIANT: Division by infinity not allowed. + + // NaN because of zero divided by itself: + float l7 = getFloat() / + p1; // COMPLIANT: Reduce false positives by assuming not infinity + float l8 = 0.0 / 0.0; + + (int)l4; // COMPLIANT + (int)l5; // NON_COMPLIANT: Casting NaN to int + (int)l6; // NON_COMPLIANT: Casting NaN to int + (int)l7; // NON_COMPLIANT: Casting NaN to int + (int)l8; // NON_COMPLIANT: Casting NaN to int + + l4 == 0; // COMPLIANT + l4 != 0; // COMPLIANT + l4 <= 0; // COMPLIANT + l4 < 0; // COMPLIANT + l4 >= 0; // COMPLIANT + l5 == 0; // NON_COMPLIANT: Comparison with NaN always false + l5 != 0; // NON_COMPLIANT: Comparison with NaN always false + l5 < 0; // NON_COMPLIANT: Comparison with NaN always false + l5 <= 0; // NON_COMPLIANT: Comparison with NaN always false + l5 > 0; // NON_COMPLIANT: Comparison with NaN always false + l5 >= 0; // NON_COMPLIANT: Comparison with NaN always false + l6 == 0; // NON_COMPLIANT: Comparison with NaN always false + l7 == 0; // NON_COMPLIANT: Comparison with NaN always false + l8 == 0; // NON_COMPLIANT: Comparison with NaN always false + + // Guards + float l9 = 0; + if (l9 != 0) { + (int)(l9 / l9); // COMPLIANT: l9 is not zero + } else { + (int)(l9 / l9); // NON_COMPLIANT: Casting NaN to integer + } + + float l10 = 0; + if (l10 == 0) { + (int)(l10 / l10); // NON_COMPLIANT: Casting NaN to integer + } else { + (int)(l10 / l10); // COMPLIANT: Guarded to not be NaN + } + + float l11 = 0; + l11 == 0 ? (int)(l11 / l11) : 0; // NON_COMPLIANT + l11 == 0 ? 0 : (int)(l11 / l11); // COMPLIANT + l11 != 0 ? (int)(l11 / l11) : 0; // COMPLIANT + l11 != 0 ? 0 : (int)(l11 / l11); // NON_COMPLIANT + + float l12 = 1.0 / 0; + if (std::isinf(l12)) { + (int)l12; // COMPLIANT: Casting Infinity to integer + } else { + (int)l12; // COMPLIANT: Guarded not to be Infinity + } + + if (!std::isinf(l12)) { + (int)l12; // COMPLIANT: Guarded not to be Infinity + } else { + (int)l12; // COMPLIANT: Casting Infinity to integer + } + + if (std::isinf(l12) == 1) { + (int)l12; // COMPLIANT: Must be +Infinity + } else { + (int)l12; // COMPLIANT: May be -Infinity + } + + if (std::isfinite(l12)) { + (int)l12; // COMPLIANT: Guarded not to be Infinity + } else { + (int)l12; // COMPLIANT: Casting Infinity to integer + } + + if (std::isnormal(l12)) { + (int)l12; // COMPLIANT: Guarded not to be Infinity + } else { + (int)l12; // COMPLIANT: Casting Infinity to integer + } + + if (std::isnan(l12)) { + (int)l12; // COMPLIANT: Guarded not to be Infinity + } else { + (int)l12; // COMPLIANT: Casting Infinity to integer + } + + std::isinf(l12) ? (int)l12 : 0; // COMPLIANT: Check on wrong branch + std::isinf(l12) ? 0 : (int)l12; // COMPLIANT: Checked not infinite before use + std::isfinite(l12) ? (int)l12 : 0; // COMPLIANT: Checked finite before use + std::isfinite(l12) ? 0 : (int)l12; // COMPLIANT: Checked on wrong branch + std::isnan(l12) + ? (int)l12 + : 0; // COMPLIANT: Checked NaN, therefore not infinite, before use + std::isnan(l12) ? 0 : (int)l12; // COMPLIANT: Check on wrong branch + + float l13 = 0.0 / 0; + if (std::isinf(l13)) { + (int)l13; // COMPLIANT: Guarded not to be NaN + } else { + (int)l13; // NON_COMPLIANT: Casting NaN to integer + } + + if (std::isinf(l13) == 1) { + (int)l13; // COMPLIANT: Guarded not to be NaN (must be +Infinity) + } else { + (int)l13; // NON_COMPLIANT: Casting NaN to integer + } + + if (std::isfinite(l13)) { + (int)l13; // COMPLIANT: Guarded not to be NaN + } else { + (int)l13; // NON_COMPLIANT: Casting NaN to integer + } + + if (std::isnormal(l13)) { + (int)l13; // COMPLIANT: Guarded not to be NaN + } else { + (int)l13; // NON_COMPLIANT: Casting NaN to integer + } + + if (std::isnan(l13)) { + (int)l13; // NON_COMPLIANT: Casting NaN to integer + } else { + (int)l13; // COMPLIANT: Guarded not to be NaN + } + + std::isinf(l13) + ? (int)l13 + : 0; // COMPLIANT: Checked infinite, therefore not NaN, before use + std::isinf(l13) ? 0 : (int)l13; // NON_COMPLIANT: Check on wrong branch + std::isfinite(l13) ? (int)l13 : 0; // COMPLIANT: Checked finite before use + std::isfinite(l13) ? 0 : (int)l13; // NON_COMPLIANT: Checked on wrong branch + std::isnan(l13) ? (int)l13 : 0; // NON_COMPLIANT: Check on wrong branch + std::isnan(l13) ? 0 : (int)l13; // COMPLIANT: Checked not NaN before use + + (int)std::pow(2, p1); // COMPLIANT: likely to be Infinity + (int)std::pow(2, std::sin(p1)); // COMPLIANT: not likely to be Infinity + (int)(1 / + std::sin(p1)); // COMPLIANT: possible infinity from zero in denominator + (int)(1 / std::log(p1)); // COMPLIANT: not possibly zero in denominator + (int)std::pow(p1, p1); // NON_COMPLIANT: NaN if p1 is zero + if (p1 != 0) { + (int)std::pow(p1, p1); // COMPLIANT: p1 is not zero + } + + (int)std::acos(p1); // NON_COMPLIANT: NaN if p1 is not within -1..1 + (int)std::acos(std::cos(p1)); // COMPLIANT: cos(p1) is within -1..1 +} + +void castToInt(float p) { (int)p; } + +void checkBeforeCastToInt(float p) { + if (std::isfinite(p)) { + castToInt(p); + } +} + +void castToIntToFloatToInt(float p) { + // This should be reported as a violation, but not downstream from here. + castToInt((int)p); +} + +void addOneThenCastToInt(float p) { castToInt(p + 1); } +void addInfThenCastToInt(float p) { castToInt(p + 1.0 / 0.0); } +void addNaNThenCastToInt(float p) { castToInt(p + 0.0 / 0.0); } + +void f2() { + castToInt(1.0 / 0.0); // COMPLIANT: Infinity flows to denominator in division + castToInt(0.0 / 0.0); // COMPLIANT: NaN flows to denominator in division + checkBeforeCastToInt(1.0 / 0.0); // COMPLIANT + checkBeforeCastToInt(0.0 / 0.0); // COMPLIANT + addOneThenCastToInt(1.0 / 0.0); // COMPLIANT + addOneThenCastToInt(0.0 / 0.0); // NON_COMPLIANT + castToIntToFloatToInt(1.0 / 0.0); // COMPLIANT + castToIntToFloatToInt(0.0 / 0.0); // NON_COMPLIANT + + // Check that during flow analysis, we only report the true root cause: + float rootInf = 1.0 / 0.0; + float rootNaN = 0.0 / 0.0; + float middleInf = rootInf + 1; + float middleNaN = rootNaN + 1; + castToInt(middleInf); // COMPLIANT + castToInt(middleNaN); // NON_COMPLIANT + addInfThenCastToInt(middleInf); // COMPLIANT + addNaNThenCastToInt(middleNaN); // NON_COMPLIANT +} \ No newline at end of file diff --git a/cpp/misra/src/rules/DIR-0-3-1/PossibleMisuseOfInfiniteFloatingPointValue.ql b/cpp/misra/src/rules/DIR-0-3-1/PossibleMisuseOfInfiniteFloatingPointValue.ql new file mode 100644 index 0000000000..0e3363137e --- /dev/null +++ b/cpp/misra/src/rules/DIR-0-3-1/PossibleMisuseOfInfiniteFloatingPointValue.ql @@ -0,0 +1,22 @@ +/** + * @id cpp/misra/possible-misuse-of-infinite-floating-point-value + * @name DIR-0-3-1: Possible misuse of a generate infinite floating point value + * @description Possible misuse of a generate infinite floating point value. + * @kind path-problem + * @precision medium + * @problem.severity warning + * @tags external/misra/id/dir-0-3-1 + * correctness + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.misuseofinfinitefloatingpointvalue.MisuseOfInfiniteFloatingPointValue + +class PossibleMisuseOfInfiniteFloatingPointValueQuery extends MisuseOfInfiniteFloatingPointValueSharedQuery +{ + PossibleMisuseOfInfiniteFloatingPointValueQuery() { + this = FloatingPointPackage::possibleMisuseOfInfiniteFloatingPointValueQuery() + } +} diff --git a/cpp/misra/src/rules/DIR-0-3-1/PossibleMisuseOfNaNFloatingPointValue.ql b/cpp/misra/src/rules/DIR-0-3-1/PossibleMisuseOfNaNFloatingPointValue.ql new file mode 100644 index 0000000000..035edd85b8 --- /dev/null +++ b/cpp/misra/src/rules/DIR-0-3-1/PossibleMisuseOfNaNFloatingPointValue.ql @@ -0,0 +1,22 @@ +/** + * @id cpp/misra/possible-misuse-of-nan-floating-point-value + * @name DIR-0-3-1: Possible mishandling of an undetected NaN value produced by a floating point operation + * @description Possible mishandling of an undetected NaN value produced by a floating point + * operation. + * @kind path-problem + * @precision low + * @problem.severity warning + * @tags external/misra/id/dir-0-3-1 + * correctness + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.misuseofnanfloatingpointvalue.MisuseOfNaNFloatingPointValue + +class PossibleMisuseOfNaNFloatingPointValueQuery extends MisuseOfNaNFloatingPointValueSharedQuery { + PossibleMisuseOfNaNFloatingPointValueQuery() { + this = FloatingPointPackage::possibleMisuseOfNaNFloatingPointValueQuery() + } +} diff --git a/cpp/misra/test/rules/DIR-0-3-1/PossibleMisuseOfInfiniteFloatingPointValue.testref b/cpp/misra/test/rules/DIR-0-3-1/PossibleMisuseOfInfiniteFloatingPointValue.testref new file mode 100644 index 0000000000..952d461d00 --- /dev/null +++ b/cpp/misra/test/rules/DIR-0-3-1/PossibleMisuseOfInfiniteFloatingPointValue.testref @@ -0,0 +1 @@ +cpp/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/DIR-0-3-1/PossibleMisuseOfNaNFloatingPointValue.testref b/cpp/misra/test/rules/DIR-0-3-1/PossibleMisuseOfNaNFloatingPointValue.testref new file mode 100644 index 0000000000..2cd2de067d --- /dev/null +++ b/cpp/misra/test/rules/DIR-0-3-1/PossibleMisuseOfNaNFloatingPointValue.testref @@ -0,0 +1 @@ +cpp/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.ql \ No newline at end of file diff --git a/rule_packages/c/FloatingTypes2.json b/rule_packages/c/FloatingTypes2.json index 3f4771dcc6..a1c02daaf5 100644 --- a/rule_packages/c/FloatingTypes2.json +++ b/rule_packages/c/FloatingTypes2.json @@ -12,6 +12,7 @@ "precision": "medium", "severity": "warning", "short_name": "PossibleMisuseOfUndetectedInfinity", + "shared_implementation_short_name": "MisuseOfInfiniteFloatingPointValue", "tags": [ "correctness", "external/misra/c/2012/amendment3" @@ -24,6 +25,7 @@ "precision": "low", "severity": "warning", "short_name": "PossibleMisuseOfUndetectedNaN", + "shared_implementation_short_name": "MisuseOfNaNFloatingPointValue", "tags": [ "correctness", "external/misra/c/2012/amendment3" diff --git a/rule_packages/cpp/FloatingPoint.json b/rule_packages/cpp/FloatingPoint.json new file mode 100644 index 0000000000..672e57acff --- /dev/null +++ b/rule_packages/cpp/FloatingPoint.json @@ -0,0 +1,36 @@ +{ + "MISRA-C++-2023": { + "DIR-0-3-1": { + "properties": { + "obligation": "advisory" + }, + "queries": [ + { + "description": "Possible misuse of a generate infinite floating point value.", + "kind": "path-problem", + "name": "Possible misuse of a generate infinite floating point value", + "precision": "medium", + "severity": "warning", + "short_name": "PossibleMisuseOfInfiniteFloatingPointValue", + "shared_implementation_short_name": "MisuseOfInfiniteFloatingPointValue", + "tags": [ + "correctness" + ] + }, + { + "description": "Possible mishandling of an undetected NaN value produced by a floating point operation.", + "kind": "path-problem", + "name": "Possible mishandling of an undetected NaN value produced by a floating point operation", + "precision": "low", + "severity": "warning", + "short_name": "PossibleMisuseOfNaNFloatingPointValue", + "shared_implementation_short_name": "MisuseOfNaNFloatingPointValue", + "tags": [ + "correctness" + ] + } + ], + "title": "Floating-point arithmetic should be used appropriately" + } + } +} \ No newline at end of file