QL: Merge pull request #55 from github/mathiasvp/prefix-or-suffix-in-comparison

New query: Find uses of '.prefix' or '.suffix' when comparing against string literals
This commit is contained in:
Anders Schack-Mulligen
2021-10-13 12:45:12 +02:00
committed by GitHub
2 changed files with 60 additions and 0 deletions

View File

@@ -1,3 +1,5 @@
private import codeql_ql.ast.internal.Type
predicate isBuiltinClassless(string sig) {
sig =
[
@@ -58,3 +60,8 @@ predicate isBuiltinMember(string qual, string ret, string name, string args) {
bindingset[args]
string getArgType(string args, int i) { result = args.splitAt(",", i).trim() }
/** The primitive 'string' class. */
class StringClass extends PrimitiveType {
StringClass() { this.getName() = "string" }
}

View File

@@ -0,0 +1,53 @@
/**
* @name Prefix or suffix predicate calls when comparing with literal
* @description Using 'myString.prefix(n) = "..."' instead of 'myString.matches("...%")'
* @kind problem
* @problem.severity error
* @id ql/prefix-or-suffix-equality-check
* @tags performance
* @precision high
*/
import ql
import codeql_ql.ast.internal.Predicate
import codeql_ql.ast.internal.Builtins
class PrefixPredicate extends BuiltinPredicate {
PrefixPredicate() { this = any(StringClass sc).getClassPredicate("prefix", 1) }
}
class SuffixPredicate extends BuiltinPredicate {
SuffixPredicate() { this = any(StringClass sc).getClassPredicate("suffix", 1) }
}
class PrefixPredicateCall extends Call {
PrefixPredicateCall() { this.getTarget() instanceof PrefixPredicate }
}
class SuffixPredicateCall extends Call {
SuffixPredicateCall() { this.getTarget() instanceof SuffixPredicate }
}
class EqFormula extends ComparisonFormula {
EqFormula() { this.getSymbol() = "=" }
}
bindingset[s]
string escape(string s) { result = s.replaceAll("_", "\\\\_").replaceAll("%", "\\\\%") }
pragma[inline]
string getMessage(FixPredicateCall call, String literal) {
call instanceof PrefixPredicateCall and
result = ".matches(\"" + escape(literal.getValue()) + "%\")"
or
call instanceof SuffixPredicateCall and
result = ".matches(\"%" + escape(literal.getValue()) + "\")"
}
class FixPredicateCall extends Call {
FixPredicateCall() { this instanceof PrefixPredicateCall or this instanceof SuffixPredicateCall }
}
from EqFormula eq, FixPredicateCall call, String literal
where eq.getAnOperand() = call and eq.getAnOperand() = literal
select eq, "Use " + getMessage(call, literal) + " instead."