mirror of
https://github.com/github/codeql.git
synced 2026-04-06 07:34:00 +02:00
445 lines
11 KiB
Plaintext
445 lines
11 KiB
Plaintext
import cpp
|
|
import semmle.code.cpp.AutogeneratedFile
|
|
|
|
/*
|
|
* Counting nontrivial literal occurrences
|
|
*/
|
|
|
|
predicate trivialPositiveIntValue(string s) {
|
|
// Small numbers
|
|
s = [0 .. 20].toString() or
|
|
// Popular powers of two (decimal)
|
|
s = "16" or
|
|
s = "24" or
|
|
s = "32" or
|
|
s = "64" or
|
|
s = "128" or
|
|
s = "256" or
|
|
s = "512" or
|
|
s = "1024" or
|
|
s = "2048" or
|
|
s = "4096" or
|
|
s = "16384" or
|
|
s = "32768" or
|
|
s = "65536" or
|
|
s = "1048576" or
|
|
s = "2147483648" or
|
|
s = "4294967296" or
|
|
// Popular powers of two, minus one (decimal)
|
|
s = "15" or
|
|
s = "31" or
|
|
s = "63" or
|
|
s = "127" or
|
|
s = "255" or
|
|
s = "511" or
|
|
s = "1023" or
|
|
s = "2047" or
|
|
s = "4095" or
|
|
s = "16383" or
|
|
s = "32767" or
|
|
s = "65535" or
|
|
s = "1048577" or
|
|
s = "2147483647" or
|
|
s = "4294967295" or
|
|
// Popular powers of two (32-bit hex)
|
|
s = "0x00000001" or
|
|
s = "0x00000002" or
|
|
s = "0x00000004" or
|
|
s = "0x00000008" or
|
|
s = "0x00000010" or
|
|
s = "0x00000020" or
|
|
s = "0x00000040" or
|
|
s = "0x00000080" or
|
|
s = "0x00000100" or
|
|
s = "0x00000200" or
|
|
s = "0x00000400" or
|
|
s = "0x00000800" or
|
|
s = "0x00001000" or
|
|
s = "0x00002000" or
|
|
s = "0x00004000" or
|
|
s = "0x00008000" or
|
|
s = "0x00010000" or
|
|
s = "0x00020000" or
|
|
s = "0x00040000" or
|
|
s = "0x00080000" or
|
|
s = "0x00100000" or
|
|
s = "0x00200000" or
|
|
s = "0x00400000" or
|
|
s = "0x00800000" or
|
|
s = "0x01000000" or
|
|
s = "0x02000000" or
|
|
s = "0x04000000" or
|
|
s = "0x08000000" or
|
|
s = "0x10000000" or
|
|
s = "0x20000000" or
|
|
s = "0x40000000" or
|
|
s = "0x80000000" or
|
|
// Popular powers of two, minus one (32-bit hex)
|
|
s = "0x00000001" or
|
|
s = "0x00000003" or
|
|
s = "0x00000007" or
|
|
s = "0x0000000f" or
|
|
s = "0x0000001f" or
|
|
s = "0x0000003f" or
|
|
s = "0x0000007f" or
|
|
s = "0x000000ff" or
|
|
s = "0x000001ff" or
|
|
s = "0x000003ff" or
|
|
s = "0x000007ff" or
|
|
s = "0x00000fff" or
|
|
s = "0x00001fff" or
|
|
s = "0x00003fff" or
|
|
s = "0x00007fff" or
|
|
s = "0x0000ffff" or
|
|
s = "0x0001ffff" or
|
|
s = "0x0003ffff" or
|
|
s = "0x0007ffff" or
|
|
s = "0x000fffff" or
|
|
s = "0x001fffff" or
|
|
s = "0x003fffff" or
|
|
s = "0x007fffff" or
|
|
s = "0x00ffffff" or
|
|
s = "0x01ffffff" or
|
|
s = "0x03ffffff" or
|
|
s = "0x07ffffff" or
|
|
s = "0x0fffffff" or
|
|
s = "0x1fffffff" or
|
|
s = "0x3fffffff" or
|
|
s = "0x7fffffff" or
|
|
s = "0xffffffff" or
|
|
// Popular powers of two (16-bit hex)
|
|
s = "0x0001" or
|
|
s = "0x0002" or
|
|
s = "0x0004" or
|
|
s = "0x0008" or
|
|
s = "0x0010" or
|
|
s = "0x0020" or
|
|
s = "0x0040" or
|
|
s = "0x0080" or
|
|
s = "0x0100" or
|
|
s = "0x0200" or
|
|
s = "0x0400" or
|
|
s = "0x0800" or
|
|
s = "0x1000" or
|
|
s = "0x2000" or
|
|
s = "0x4000" or
|
|
s = "0x8000" or
|
|
// Popular powers of two, minus one (16-bit hex)
|
|
s = "0x0001" or
|
|
s = "0x0003" or
|
|
s = "0x0007" or
|
|
s = "0x000f" or
|
|
s = "0x001f" or
|
|
s = "0x003f" or
|
|
s = "0x007f" or
|
|
s = "0x00ff" or
|
|
s = "0x01ff" or
|
|
s = "0x03ff" or
|
|
s = "0x07ff" or
|
|
s = "0x0fff" or
|
|
s = "0x1fff" or
|
|
s = "0x3fff" or
|
|
s = "0x7fff" or
|
|
s = "0xffff" or
|
|
// Popular powers of two (8-bit hex)
|
|
s = "0x01" or
|
|
s = "0x02" or
|
|
s = "0x04" or
|
|
s = "0x08" or
|
|
s = "0x10" or
|
|
s = "0x20" or
|
|
s = "0x40" or
|
|
s = "0x80" or
|
|
// Popular powers of two, minus one (8-bit hex)
|
|
s = "0x01" or
|
|
s = "0x03" or
|
|
s = "0x07" or
|
|
s = "0x0f" or
|
|
s = "0x1f" or
|
|
s = "0x3f" or
|
|
s = "0x7f" or
|
|
s = "0xff" or
|
|
s = "0x00" or
|
|
// Powers of ten
|
|
s = "10" or
|
|
s = "100" or
|
|
s = "1000" or
|
|
s = "10000" or
|
|
s = "100000" or
|
|
s = "1000000" or
|
|
s = "10000000" or
|
|
s = "100000000" or
|
|
s = "1000000000"
|
|
}
|
|
|
|
predicate trivialIntValue(string s) {
|
|
trivialPositiveIntValue(s)
|
|
or
|
|
exists(string pos | trivialPositiveIntValue(pos) and s = "-" + pos)
|
|
}
|
|
|
|
predicate trivialLongValue(string s) { exists(string v | trivialIntValue(v) and s = v + "L") }
|
|
|
|
predicate intTrivial(Literal lit) { exists(string v | trivialIntValue(v) and v = lit.getValue()) }
|
|
|
|
predicate longTrivial(Literal lit) { exists(string v | trivialLongValue(v) and v = lit.getValue()) }
|
|
|
|
predicate powerOfTen(float f) {
|
|
f = 10 or
|
|
f = 100 or
|
|
f = 1000 or
|
|
f = 10000 or
|
|
f = 100000 or
|
|
f = 1000000 or
|
|
f = 10000000 or
|
|
f = 100000000 or
|
|
f = 1000000000
|
|
}
|
|
|
|
predicate floatTrivial(Literal lit) {
|
|
lit.getType() instanceof FloatingPointType and
|
|
exists(string value, float f |
|
|
lit.getValue() = value and
|
|
f = value.toFloat() and
|
|
(f.abs() <= 20.0 or powerOfTen(f))
|
|
)
|
|
}
|
|
|
|
predicate charLiteral(Literal lit) { lit instanceof CharLiteral }
|
|
|
|
Type literalType(Literal literal) { result = literal.getType() }
|
|
|
|
predicate stringType(DerivedType t) {
|
|
t.getBaseType() instanceof CharType
|
|
or
|
|
exists(SpecifiedType constCharType |
|
|
t.getBaseType() = constCharType and
|
|
constCharType.isConst() and
|
|
constCharType.getBaseType() instanceof CharType
|
|
)
|
|
}
|
|
|
|
predicate numberType(Type t) { t instanceof FloatingPointType or t instanceof IntegralType }
|
|
|
|
predicate stringLiteral(Literal literal) { literal instanceof StringLiteral }
|
|
|
|
predicate stringTrivial(Literal lit) {
|
|
stringLiteral(lit) and
|
|
lit.getValue().length() < 8
|
|
}
|
|
|
|
predicate joiningStringTrivial(Literal lit) {
|
|
// We want to be more lenient with string literals that are being
|
|
// joined together, because replacing sentence fragments with named
|
|
// constants could actually result in code that is harder to
|
|
// understand (which is against the spirit of these queries).
|
|
stringLiteral(lit) and
|
|
exists(FunctionCall fc |
|
|
(
|
|
fc.getTarget().getName() = "operator+" or
|
|
fc.getTarget().getName() = "operator<<"
|
|
) and
|
|
fc.getAnArgument().getAChild*() = lit
|
|
) and
|
|
lit.getValue().length() < 16
|
|
}
|
|
|
|
predicate small(Literal lit) { lit.getValue().length() <= 1 }
|
|
|
|
predicate trivial(Literal lit) {
|
|
charLiteral(lit) or
|
|
intTrivial(lit) or
|
|
floatTrivial(lit) or
|
|
stringTrivial(lit) or
|
|
joiningStringTrivial(lit) or
|
|
longTrivial(lit) or
|
|
small(lit)
|
|
}
|
|
|
|
private predicate isReferenceTo(Variable ref, Variable to) {
|
|
exists(VariableAccess a |
|
|
ref.getInitializer().getExpr().getConversion().(ReferenceToExpr).getExpr() = a and
|
|
a.getTarget() = to
|
|
)
|
|
}
|
|
|
|
private predicate variableNotModifiedAfterInitializer(Variable v) {
|
|
not exists(VariableAccess a | a.getTarget() = v and a.isModified()) and
|
|
not exists(AddressOfExpr e | e.getAddressable() = v) and
|
|
forall(Variable v2 | isReferenceTo(v2, v) | variableNotModifiedAfterInitializer(v2))
|
|
}
|
|
|
|
predicate literalIsConstantInitializer(Literal literal, Variable f) {
|
|
f.getInitializer().getExpr() = literal and
|
|
variableNotModifiedAfterInitializer(f) and
|
|
not f instanceof Parameter
|
|
}
|
|
|
|
predicate literalIsEnumInitializer(Literal literal) {
|
|
exists(EnumConstant ec | ec.getInitializer().getExpr() = literal)
|
|
}
|
|
|
|
predicate literalInArrayInitializer(Literal literal) {
|
|
exists(AggregateLiteral arrayInit | arrayInitializerChild(arrayInit, literal))
|
|
}
|
|
|
|
predicate arrayInitializerChild(AggregateLiteral parent, Expr e) {
|
|
e = parent
|
|
or
|
|
exists(Expr mid | arrayInitializerChild(parent, mid) and e.getParent() = mid)
|
|
}
|
|
|
|
// i.e. not a constant folded expression
|
|
predicate literallyLiteral(Literal lit) {
|
|
lit
|
|
.getValueText()
|
|
.regexpMatch(".*\".*|\\s*+[-+]?+\\s*+(0[xob][0-9a-fA-F]|[0-9])[0-9a-fA-F,._]*+([eE][-+]?+[0-9,._]*+)?+\\s*+[a-zA-Z]*+\\s*+")
|
|
}
|
|
|
|
predicate nonTrivialValue(string value, Literal literal) {
|
|
value = literal.getValue() and
|
|
not trivial(literal) and
|
|
not literalIsConstantInitializer(literal, _) and
|
|
not literalIsEnumInitializer(literal) and
|
|
not literalInArrayInitializer(literal) and
|
|
not literal.isAffectedByMacro() and
|
|
literallyLiteral(literal)
|
|
}
|
|
|
|
predicate valueOccurrenceCount(string value, int n) {
|
|
n = strictcount(Location loc |
|
|
exists(Literal lit | lit.getLocation() = loc | nonTrivialValue(value, lit)) and
|
|
// Exclude generated files (they do not have the same maintainability
|
|
// concerns as ordinary source files)
|
|
not loc.getFile() instanceof AutogeneratedFile
|
|
) and
|
|
n > 20
|
|
}
|
|
|
|
predicate occurenceCount(Literal lit, string value, int n) {
|
|
valueOccurrenceCount(value, n) and
|
|
value = lit.getValue() and
|
|
nonTrivialValue(_, lit)
|
|
}
|
|
|
|
/*
|
|
* Literals repeated frequently
|
|
*/
|
|
|
|
predicate check(Literal lit, string value, int n, File f) {
|
|
// Check that the literal is nontrivial
|
|
not trivial(lit) and
|
|
// Check that it is repeated a number of times
|
|
occurenceCount(lit, value, n) and
|
|
n > 20 and
|
|
f = lit.getFile() and
|
|
// Exclude generated files
|
|
not f instanceof AutogeneratedFile
|
|
}
|
|
|
|
predicate checkWithFileCount(string value, int overallCount, int fileCount, File f) {
|
|
fileCount = strictcount(Location loc |
|
|
exists(Literal lit | lit.getLocation() = loc | check(lit, value, overallCount, f))
|
|
)
|
|
}
|
|
|
|
predicate start(Literal lit, int startLine) {
|
|
exists(Location l | l = lit.getLocation() and startLine = l.getStartLine())
|
|
}
|
|
|
|
predicate firstOccurrence(Literal lit, string value, int n) {
|
|
exists(File f, int fileCount |
|
|
checkWithFileCount(value, n, fileCount, f) and
|
|
fileCount < 100 and
|
|
check(lit, value, n, f) and
|
|
not exists(Literal lit2, int start1, int start2 |
|
|
check(lit2, value, n, f) and
|
|
start(lit, start1) and
|
|
start(lit2, start2) and
|
|
start2 < start1
|
|
)
|
|
)
|
|
}
|
|
|
|
predicate magicConstant(Literal e, string msg) {
|
|
exists(string value, int n |
|
|
firstOccurrence(e, value, n) and
|
|
msg = "Magic constant: literal '" + value + "' is repeated " + n.toString() +
|
|
" times and should be encapsulated in a constant."
|
|
)
|
|
}
|
|
|
|
/*
|
|
* Literals where there is a defined constant with the same value
|
|
*/
|
|
|
|
predicate relevantVariable(Variable f, string value) {
|
|
exists(Literal lit |
|
|
not trivial(lit) and value = lit.getValue() and literalIsConstantInitializer(lit, f)
|
|
)
|
|
}
|
|
|
|
predicate relevantCallable(Function f, string value) {
|
|
exists(Literal lit |
|
|
not trivial(lit) and value = lit.getValue() and lit.getEnclosingFunction() = f
|
|
)
|
|
}
|
|
|
|
predicate isVisible(Variable field, Function fromCallable) {
|
|
exists(string value |
|
|
//public fields
|
|
relevantVariable(field, value) and
|
|
field.(MemberVariable).isPublic() and
|
|
relevantCallable(fromCallable, value)
|
|
or
|
|
//in same class
|
|
relevantVariable(field, value) and
|
|
exists(Type t |
|
|
t = field.getDeclaringType() and
|
|
t = fromCallable.getDeclaringType()
|
|
) and
|
|
relevantCallable(fromCallable, value)
|
|
or
|
|
//in subclass and not private
|
|
relevantVariable(field, value) and
|
|
not field.(MemberVariable).isPrivate() and
|
|
exists(Class sup, Class sub |
|
|
sup = field.getDeclaringType() and
|
|
sub.getABaseClass+() = sup and
|
|
sub = fromCallable.getDeclaringType()
|
|
) and
|
|
relevantCallable(fromCallable, value)
|
|
)
|
|
}
|
|
|
|
predicate canUseFieldInsteadOfLiteral(Variable constField, Literal magicLiteral) {
|
|
exists(Literal initLiteral |
|
|
literalIsConstantInitializer(initLiteral, constField) and
|
|
not trivial(initLiteral) and
|
|
not constField.getType().hasName("boolean") and
|
|
exists(string value |
|
|
value = initLiteral.getValue() and
|
|
magicLiteral.getValue() = value
|
|
) and
|
|
constField.getType() = magicLiteral.getType() and
|
|
not literalIsConstantInitializer(magicLiteral, _) and
|
|
exists(Function c |
|
|
c = magicLiteral.getEnclosingFunction() and
|
|
(
|
|
constField.isTopLevel() and
|
|
(not constField.isStatic() or constField.getFile() = c.getFile())
|
|
or
|
|
isVisible(constField, c)
|
|
)
|
|
)
|
|
)
|
|
}
|
|
|
|
predicate literalInsteadOfConstant(
|
|
Literal magicLiteral, string message, Variable constField, string linkText
|
|
) {
|
|
canUseFieldInsteadOfLiteral(constField, magicLiteral) and
|
|
message = "Literal value '" + magicLiteral.getValue() + "' used instead of constant $@." and
|
|
linkText = constField.getName()
|
|
}
|