Skip to content

Commit 6463a94

Browse files
authored
Merge pull request #4297 from github/igfoo/compileTimeConstantInt
C++: Improve `compileTimeConstantInt`
2 parents c67605f + c7b6374 commit 6463a94

File tree

1 file changed

+49
-7
lines changed

1 file changed

+49
-7
lines changed

cpp/ql/src/semmle/code/cpp/controlflow/internal/ConstantExprs.qll

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -279,20 +279,62 @@ private predicate reachableRecursive(ControlFlowNode n) {
279279
reachableRecursive(n.getAPredecessor())
280280
}
281281

282+
/** Holds if `e` is a compile time constant with integer value `val`. */
282283
private predicate compileTimeConstantInt(Expr e, int val) {
283-
val = e.getFullyConverted().getValue().toInt() and
284-
not e instanceof StringLiteral and
285-
not exists(Expr e1 | e1.getConversion() = e) // only values for fully converted expressions
284+
(
285+
// If we have an integer value then we are done.
286+
if exists(e.getValue().toInt())
287+
then val = e.getValue().toInt()
288+
else
289+
// Otherwise, if we are a conversion of another expression with an
290+
// integer value, and that value can be converted into our type,
291+
// then we have that value.
292+
exists(Expr x, int valx |
293+
x.getConversion() = e and
294+
compileTimeConstantInt(x, valx) and
295+
val = convertIntToType(valx, e.getType().getUnspecifiedType())
296+
)
297+
) and
298+
// If our unconverted expression is a string literal `"123"`, then we
299+
// do not have integer value `123`.
300+
not e.getUnconverted() instanceof StringLiteral
286301
}
287302

288-
library class CompileTimeConstantInt extends Expr {
289-
CompileTimeConstantInt() { compileTimeConstantInt(this, _) }
303+
/**
304+
* Get `val` represented as type `t`, if that is possible without
305+
* overflow or underflows.
306+
*/
307+
bindingset[val, t]
308+
private int convertIntToType(int val, IntegralType t) {
309+
if t instanceof BoolType
310+
then if val = 0 then result = 0 else result = 1
311+
else
312+
if t.isUnsigned()
313+
then if val >= 0 and val.bitShiftRight(t.getSize() * 8) = 0 then result = val else none()
314+
else
315+
if val >= 0 and val.bitShiftRight(t.getSize() * 8 - 1) = 0
316+
then result = val
317+
else
318+
if (-(val + 1)).bitShiftRight(t.getSize() * 8 - 1) = 0
319+
then result = val
320+
else none()
321+
}
322+
323+
/**
324+
* INTERNAL: Do not use.
325+
* An expression that has been found to have an integer value at compile
326+
* time.
327+
*/
328+
class CompileTimeConstantInt extends Expr {
329+
int val;
330+
331+
CompileTimeConstantInt() { compileTimeConstantInt(this.getFullyConverted(), val) }
290332

291-
int getIntValue() { compileTimeConstantInt(this, result) }
333+
int getIntValue() { result = val }
292334
}
293335

294336
library class CompileTimeVariableExpr extends Expr {
295-
CompileTimeVariableExpr() { not compileTimeConstantInt(this, _) }
337+
CompileTimeVariableExpr() { not this instanceof CompileTimeConstantInt }
296338
}
297339

298340
/** A helper class for evaluation of expressions. */

0 commit comments

Comments
 (0)