mirror of
https://github.com/github/codeql.git
synced 2026-04-30 19:26:02 +02:00
Add pythagorean query
This commit is contained in:
12
python/ql/src/Numerics/Pythagorean.py
Normal file
12
python/ql/src/Numerics/Pythagorean.py
Normal file
@@ -0,0 +1,12 @@
|
||||
# We know that a^2 + b^2 = c^2, and wish to use this to compute c
|
||||
from math import sqrt, hypot
|
||||
|
||||
a = 3e154 # a^2 > 1e308
|
||||
b = 4e154 # b^2 > 1e308
|
||||
# with these, c = 5e154 which is less that 1e308
|
||||
|
||||
def longSideDirect():
|
||||
return sqrt(a**2 + b**2) # this will overflow
|
||||
|
||||
def longSideBuiltin():
|
||||
return hypot(a, b) # better to use built-in function
|
||||
33
python/ql/src/Numerics/Pythagorean.qhelp
Normal file
33
python/ql/src/Numerics/Pythagorean.qhelp
Normal file
@@ -0,0 +1,33 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>
|
||||
Calculating the length of the hypotenuse using the standard formula <code>c = sqrt(a**2 + b**2)</code> may lead to overflow if the two other sides are both very large.
|
||||
Even though <code>c</code> will not be much bigger than <code>max(a, b)</code>, either <code>a**2</code> or <code>b**2</code> (or both) will.
|
||||
Thus, the calculation could overflow, even though the result is well within representable range.
|
||||
</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>
|
||||
Rather than <code>sqrt(a**2 + b**2)</code>, use the built-in function <code>hypot(a,b)</code> from the <code>math</code> library.
|
||||
</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>
|
||||
The following code shows two different ways of computing the hypotenuse.
|
||||
The first is a direct rewrite of the Pythagorean theorem, the second uses the built-in function.
|
||||
</p>
|
||||
|
||||
<sample src="Pythagorean.py" />
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>Python Language Reference: <a href="https://docs.python.org/library/math.html#math.hypot">The hypot function</a></li>
|
||||
<li>Wikipedia: <a href="https://en.wikipedia.org/wiki/Hypot">Hypot</a>.</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
48
python/ql/src/Numerics/Pythagorean.ql
Normal file
48
python/ql/src/Numerics/Pythagorean.ql
Normal file
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* @name Pythagorean calculation with sub-optimal numerics
|
||||
* @description Calculating the length of the hypotenuse using the standard formula may lead to overflow.
|
||||
* @kind problem
|
||||
* @tags accuracy
|
||||
* @problem.severity warning
|
||||
* @sub-severity low
|
||||
* @precision medium
|
||||
* @id py/pythagorean
|
||||
*/
|
||||
|
||||
import python
|
||||
|
||||
predicate squareOp(BinaryExpr e) {
|
||||
e.getOp() instanceof Pow and e.getRight().(IntegerLiteral).getN() = "2"
|
||||
}
|
||||
|
||||
predicate squareMul(BinaryExpr e) {
|
||||
e.getOp() instanceof Mult and e.getRight().(Name).getId() = e.getLeft().(Name).getId()
|
||||
}
|
||||
|
||||
predicate squareRef(Name e) {
|
||||
e.isUse() and
|
||||
exists(SsaVariable v, Expr s |
|
||||
v.getVariable() = e.getVariable() |
|
||||
s = v.getDefinition().getNode().getParentNode().(AssignStmt).getValue() and
|
||||
square(s)
|
||||
)
|
||||
}
|
||||
|
||||
predicate square(Expr e) {
|
||||
squareOp(e)
|
||||
or
|
||||
squareMul(e)
|
||||
or
|
||||
squareRef(e)
|
||||
}
|
||||
|
||||
from
|
||||
Call c,
|
||||
BinaryExpr s
|
||||
where
|
||||
c.getFunc().toString() = "sqrt" and
|
||||
c.getArg(0) = s and
|
||||
s.getOp() instanceof Add and
|
||||
square(s.getLeft()) and square(s.getRight())
|
||||
select
|
||||
c, "Pythagorean calculation with sub-optimal numerics"
|
||||
3
python/ql/test/query-tests/Numerics/Pythagorean.expected
Normal file
3
python/ql/test/query-tests/Numerics/Pythagorean.expected
Normal file
@@ -0,0 +1,3 @@
|
||||
| pythagorean_test.py:6:12:6:28 | sqrt() | Pythagorean calculation with sub-optimal numerics |
|
||||
| pythagorean_test.py:9:12:9:26 | sqrt() | Pythagorean calculation with sub-optimal numerics |
|
||||
| pythagorean_test.py:14:12:14:24 | sqrt() | Pythagorean calculation with sub-optimal numerics |
|
||||
1
python/ql/test/query-tests/Numerics/Pythagorean.qlref
Normal file
1
python/ql/test/query-tests/Numerics/Pythagorean.qlref
Normal file
@@ -0,0 +1 @@
|
||||
Numerics/Pythagorean.ql
|
||||
14
python/ql/test/query-tests/Numerics/pythagorean_test.py
Normal file
14
python/ql/test/query-tests/Numerics/pythagorean_test.py
Normal file
@@ -0,0 +1,14 @@
|
||||
# Computing the Euclidian norm using the Pythagorean Theorem
|
||||
|
||||
from math import sqrt
|
||||
|
||||
def withPow(a, b):
|
||||
return sqrt(a**2 + b**2)
|
||||
|
||||
def withMul(a, b):
|
||||
return sqrt(a*a + b*b)
|
||||
|
||||
def withRef(a, b):
|
||||
a2 = a**2
|
||||
b2 = b*b
|
||||
return sqrt(a2 + b2)
|
||||
Reference in New Issue
Block a user