QL code and tests for C#/C++/JavaScript.

This commit is contained in:
Pavel Avgustinov
2018-08-02 17:53:23 +01:00
commit b55526aa58
10684 changed files with 581163 additions and 0 deletions

View File

@@ -0,0 +1,2 @@
| duplicate_functions.cpp:0:0:0:0 | duplicate_functions.cpp | 42 |
| file://:0:0:0:0 | | 0 |

View File

@@ -0,0 +1 @@
Metrics/Files/FLinesOfDuplicatedCode.ql

View File

@@ -0,0 +1,47 @@
int x;
void Void1()
{
x = 0;
x = 1;
x = 2;
x = 3;
x = 4;
x = 5;
x = 6;
}
void Void2()
{
x = 0;
x = 1;
x = 2;
x = 3;
x = 4;
x = 5;
x = 6;
}
int Int1()
{
x = 0;
++x;
++x;
--x;
--x;
++x;
--x;
return x;
}
int Int2()
{
x = 0;
++x;
++x;
--x;
--x;
++x;
--x;
return x;
}

View File

@@ -0,0 +1,4 @@
| duplicate_functions.cpp:3:6:3:10 | definition of Void1 | Function Void1 is duplicated at $@. | duplicate_functions.cpp:14:6:14:10 | definition of Void2 | duplicate_functions.cpp:14 |
| duplicate_functions.cpp:14:6:14:10 | definition of Void2 | Function Void2 is duplicated at $@. | duplicate_functions.cpp:3:6:3:10 | definition of Void1 | duplicate_functions.cpp:3 |
| duplicate_functions.cpp:25:5:25:8 | definition of Int1 | Function Int1 is duplicated at $@. | duplicate_functions.cpp:37:5:37:8 | definition of Int2 | duplicate_functions.cpp:37 |
| duplicate_functions.cpp:37:5:37:8 | definition of Int2 | Function Int2 is duplicated at $@. | duplicate_functions.cpp:25:5:25:8 | definition of Int1 | duplicate_functions.cpp:25 |

View File

@@ -0,0 +1 @@
external/DuplicateFunction.ql

View File

@@ -0,0 +1,2 @@
| test.c:0:0:0:0 | test.c | 10 |
| file://:0:0:0:0 | | 0 |

View File

@@ -0,0 +1 @@
Metrics/Files/FLinesOfDuplicatedCode.ql

View File

@@ -0,0 +1 @@
| 2 |

View File

@@ -0,0 +1,6 @@
import cpp
// Provided tokenisation succeeded, we ought to have some
// @duplication rows.
select count(@duplication d)

View File

@@ -0,0 +1,18 @@
#define foo "/*bar"
#define bar aaa \ bbb
int i;
void f(void) {
i = 1;
i = 2;
i = 3;
}
void g(void) {
i = 1;
i = 2;
i = 3;
}

View File

@@ -0,0 +1,3 @@
void v(int i) {
int *j = &i;
}

View File

@@ -0,0 +1,10 @@
struct S {
char* name;
};
void v()
{
char c[] = "hello";
struct S s;
s.name = c;
}

View File

@@ -0,0 +1,3 @@
void v(char *c, void *v) {
c = (char *)v;
}

View File

@@ -0,0 +1,5 @@
void v() {
int j = 0;
while(int k = j < 5) {
}
}

View File

@@ -0,0 +1,21 @@
class C {
public:
C(int i) {
}
};
class D {
public:
D() {
}
};
class E {
public:
};
void v(C *c, D *d, E *e) {
c = new C(5);
d = new D();
e = new E();
}

View File

@@ -0,0 +1,4 @@
void v() {
int i = (int)1;
}

View File

@@ -0,0 +1,3 @@
void v(int x) {
x = (int)5 + (int)7;
}

View File

@@ -0,0 +1,3 @@
void v(int x) {
x = (bool)(int)5 + ((int)7);
}

View File

@@ -0,0 +1,3 @@
void v(int x) {
x = ((int)7);
}

View File

@@ -0,0 +1,14 @@
class C {
public:
~C() {
}
};
class D {
public:
};
void v(C *c, D *d) {
delete c;
delete d;
}

View File

@@ -0,0 +1,14 @@
class Base {
virtual void f() { }
};
class Derived : public Base {
void f() { }
};
void v(Base *bp, Derived *d) {
d = dynamic_cast<Derived *>(bp);
}
void v_ref(Base &bp, Derived &d) {
d = dynamic_cast<Derived &>(bp);
}

View File

@@ -0,0 +1,3 @@
void v(int i) {
i = (i + 1) * 2;
}

View File

@@ -0,0 +1,3 @@
void v(int *i, int j) {
j = *i;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
semmle/code/cpp/PrintAST.ql

View File

@@ -0,0 +1,6 @@
/*
there is an implicit compiler-generated dereference node before the access to the variable 'i'
*/
void v(int &i, int j) {
j = i;
}

View File

@@ -0,0 +1,3 @@
int& v(int *i) {
return *i;
}

View File

@@ -0,0 +1,4 @@
void v(int array[]) {
int i = sizeof(int);
int j = sizeof(array);
}

View File

@@ -0,0 +1,3 @@
void v() {
int j = ({ int i = 5; i; });
}

View File

@@ -0,0 +1,9 @@
struct X {
static int i;
};
void v(int i, X &xref) {
// i = X::i;
i = xref.i;
}

View File

@@ -0,0 +1,3 @@
void v(int i[], int j) {
j = i[5];
}

View File

@@ -0,0 +1,16 @@
class E { };
class F {
public:
F() { }
};
void f(int i) {
try {
if(i)
throw E();
else
throw F();
} catch(E *e) {
throw;
}
}

View File

@@ -0,0 +1,20 @@
namespace std
{
class type_info
{
public:
const char *name() const;
};
}
class Base {
public:
virtual void v() { }
};
class Derived : public Base {
};
void v(Base *bp) {
const char *name = typeid(bp).name();
}

View File

@@ -0,0 +1,11 @@
template<class T>
void v(T x, T *y) {
x.T::~T();
y->T::~T();
}
void f(int i) {
// An int doesn't have a destructor, but we get to call it anyway through a
// template.
v(i, &i);
}

View File

@@ -0,0 +1,12 @@
typedef __builtin_va_list __gnuc_va_list;
#define va_start(v,l) __builtin_va_start(v,l)
#define va_end(v) __builtin_va_end(v)
#define va_arg(v,l) __builtin_va_arg(v,l)
#define va_copy(d,s) __builtin_va_copy(d,s)
typedef __gnuc_va_list va_list;
void output(const char *text, ...) {
va_list args;
va_start(args, text);
va_end (args);
}

View File

@@ -0,0 +1,3 @@
This directory contains the C++ demo queries used on LGTM that are not also
standard queries. Maintaining this copy should ensure that they continue to
work.

View File

@@ -0,0 +1 @@
| test.cpp:10:5:10:17 | ... = ... | Assignment of '0' to parameter '$@' has no effect. | test.cpp:3:42:3:44 | buf | buf |

View File

@@ -0,0 +1,17 @@
/**
* @name Assignment to parameter has no effect
* @description An assignment to a parameter that is not subsequently read may
* indicate a logic error.
* @kind problem
* @problem.severity warning
*/
import cpp
from Parameter p, Assignment assign
where assign = p.getAnAssignment()
and not assign.getASuccessor+() = p.getAnAccess()
and not p.getType() instanceof ReferenceType
select assign, "Assignment of '"+ assign.getRValue() +
"' to parameter '$@' has no effect.",
p, p.getName()

View File

@@ -0,0 +1 @@
| test.cpp:4:9:4:17 | ... == ... | Expression tested for equality with 'true' |

View File

@@ -0,0 +1,15 @@
/**
* @name Equality test on Boolean
* @description Testing equality with `true` is redundant
* and can make the code harder to read.
* @kind problem
* @problem.severity warning
*/
import cpp
from EqualityOperation eq, Expr trueExpr
where
trueExpr = eq.getAnOperand() and
trueExpr.getType() instanceof BoolType and
trueExpr.getValue().toInt() = 1
select eq, "Expression tested for equality with 'true'"

View File

@@ -0,0 +1 @@
| test.cpp:5:9:5:15 | call to sprintf | sprintf called with variable format string. |

View File

@@ -0,0 +1,16 @@
/**
* @name Call to sprintf with non-literal format string
* @description Passing a non-constant 'format' string to a printf-like
* function can lead to a mismatch between the number of arguments
* defined by the 'format' and the number of arguments actually
* passed to the function. If the format string ultimately stems
* from an untrusted source, this can be used for exploits.
* @kind problem
* @problem.severity warning
*/
import cpp
from FunctionCall fc
where fc.getTarget().getQualifiedName() = "sprintf"
and not fc.getArgument(1) instanceof StringLiteral
select fc, "sprintf called with variable format string."

View File

@@ -0,0 +1,11 @@
long sprintf(char *buf, const char *format, ...);
void f(bool b, const char *format, char *buf) {
if (b == true) { // BAD
sprintf(buf, format, 5); // BAD
} else if (!b) { // GOOD
buf = buf + 1; // GOOD
sprintf(buf, "%d", 5); // GOOD
}
buf = nullptr; // BAD
}

View File

@@ -0,0 +1,3 @@
// This file exists to ensure that the output subdirectory exists prior to
// a.c being indexed, as said directory needs to exist for the PCH file to
// be created, and will be created by running the extractor.

View File

@@ -0,0 +1,3 @@
#include "a.h"
#define FOUR 4
// semmle-extractor-options: --clang -emit-pch -o ${testdir}/clang-pch.testproj/a.pch

View File

@@ -0,0 +1 @@
#define ONE 1

View File

@@ -0,0 +1,7 @@
#define TWO 2
#include "b.h"
int main() {
return ONE + TWO + THREE + FOUR;
}
// semmle-extractor-options: --clang -include-pch ${testdir}/clang-pch.testproj/a.pch -Iextra_dummy_path

View File

@@ -0,0 +1 @@
#define THREE 3

View File

@@ -0,0 +1,4 @@
int main() {
return ONE + FOUR;
}
// semmle-extractor-options: --clang -include ${testdir}/clang-pch.testproj/a -Iextra_dummy_path

View File

@@ -0,0 +1,6 @@
| b.c:5:3:5:34 | return ... | 10 |
| c.c:2:3:2:20 | return ... | 5 |
| e.c:2:3:2:19 | return ... | 17 |
| i.c:3:3:3:12 | return ... | 30 |
| i.c:8:3:8:12 | return ... | 31 |
| i.c:13:3:13:12 | return ... | 32 |

View File

@@ -0,0 +1,4 @@
import cpp
from ReturnStmt rs
select rs, rs.getExpr().getValue()

View File

@@ -0,0 +1,2 @@
#import "d.h"
// semmle-extractor-options: --clang -emit-pch -o ${testdir}/clang-pch.testproj/d.pch

View File

@@ -0,0 +1 @@
enum { SEVENTEEN = 17 };

View File

@@ -0,0 +1,4 @@
int main() {
return SEVENTEEN;
}
// semmle-extractor-options: --clang -include-pch ${testdir}/clang-pch.testproj/d.pch

View File

@@ -0,0 +1,6 @@
#if 1
#pragma hdrstop
extern int x;
#define SEEN_F
#endif
// semmle-extractor-options: --clang -emit-pch -o ${testdir}/clang-pch.testproj/f.pch

View File

@@ -0,0 +1,6 @@
#ifdef SEEN_F
static int g() {
return 20;
}
#endif
// semmle-extractor-options: --clang -include-pch ${testdir}/clang-pch.testproj/f.pch --expect_errors

View File

@@ -0,0 +1,5 @@
#include "h1.h"
#pragma hdrstop
#include "h2.h"
#define SEEN_H
// semmle-extractor-options: --clang -emit-pch -o ${testdir}/clang-pch.testproj/h.pch

View File

@@ -0,0 +1,3 @@
#define H1

View File

@@ -0,0 +1,3 @@
#define H2

View File

@@ -0,0 +1,16 @@
#ifdef SEEN_H
static int h() {
return 30; // [FALSE POSITIVE] (#pragma hdrstop bug, SEEN_H should not be defined in the precompiled header)
}
#endif
#ifdef H1
static int h1() {
return 31;
}
#endif
#ifdef H2
static int h2() {
return 32; // [FALSE POSITIVE] (#pragma hdrstop bug, H2 should not be defined in the precompiled header)
}
#endif
// semmle-extractor-options: --clang -include-pch ${testdir}/clang-pch.testproj/h.pch

View File

@@ -0,0 +1,8 @@
const char* bar()
{
#ifndef BAR
return "bar";
#else
return "baz";
#endif
}

View File

@@ -0,0 +1,4 @@
| file://:0:0:0:0 | __va_list_tag | 1 distinct class(es) called __va_list_tag |
| main2.cpp:7:7:7:7 | C | 2 distinct class(es) called C |
| main2.cpp:7:7:7:7 | C | 2 distinct class(es) called C |
| main2.cpp:15:7:15:7 | D | 1 distinct class(es) called D |

View File

@@ -0,0 +1,5 @@
import default
from Class c, string n
where n = count(Class x | x.getName() = c.getName()) + " distinct class(es) called " + c.getName()
select c, n

View File

@@ -0,0 +1,10 @@
const char* foo()
{
return "foo";
}
#ifdef FOO
int foo_defined;
#else
int foo_not_defined;
#endif

View File

@@ -0,0 +1,15 @@
| bar.h:1:13:1:15 | bar | Function | 2 | <none> |
| bar.h:1:13:1:15 | bar | MemberFunction | 1 | C |
| bar.h:1:13:1:15 | bar | MemberFunction | 1 | C |
| bar.h:1:13:1:15 | bar | MemberFunction | 2 | D |
| file://:0:0:0:0 | operator= | MemberFunction | 0 | __va_list_tag |
| file://:0:0:0:0 | operator= | MemberFunction | 0 | __va_list_tag |
| foo.h:1:13:1:15 | foo | Function | 1 | <none> |
| foo.h:1:13:1:15 | foo | MemberFunction | 1 | C |
| foo.h:1:13:1:15 | foo | MemberFunction | 1 | C |
| main2.cpp:7:7:7:7 | operator= | MemberFunction | 0 | C |
| main2.cpp:7:7:7:7 | operator= | MemberFunction | 0 | C |
| main2.cpp:7:7:7:7 | operator= | MemberFunction | 0 | C |
| main2.cpp:7:7:7:7 | operator= | MemberFunction | 0 | C |
| main2.cpp:15:7:15:7 | operator= | MemberFunction | 0 | D |
| main2.cpp:15:7:15:7 | operator= | MemberFunction | 0 | D |

View File

@@ -0,0 +1,9 @@
import cpp
from Function f, string d, string c
where if f instanceof MemberFunction then (
d = "MemberFunction" and c = ((MemberFunction)f).getDeclaringType().getName()
) else (
d = "Function" and c = "<none>"
)
select f, d, count(f.getBlock()), c

View File

@@ -0,0 +1,3 @@
#define FOO
#define BAR
#include "main2.cpp"

View File

@@ -0,0 +1,18 @@
#include "foo.h"
#include "bar.h"
// This will cause multiple, incompatible definitions of C since the member
// variable in foo.h has different names depending on whether or not FOO is
// defined.
class C
{
#include "foo.h"
#include "bar.h"
};
// All definitions of D should be merged, since all members have the same name
// and type.
class D
{
#include "bar.h"
};

View File

@@ -0,0 +1,14 @@
| file://:0:0:0:0 | fp_offset | file://:0:0:0:0 | unsigned int | MemberVariable | __va_list_tag |
| file://:0:0:0:0 | gp_offset | file://:0:0:0:0 | unsigned int | MemberVariable | __va_list_tag |
| file://:0:0:0:0 | overflow_arg_area | file://:0:0:0:0 | void * | MemberVariable | __va_list_tag |
| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | C && | Variable | <none> |
| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | C && | Variable | <none> |
| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | D && | Variable | <none> |
| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | const C & | Variable | <none> |
| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | const C & | Variable | <none> |
| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | const D & | Variable | <none> |
| file://:0:0:0:0 | reg_save_area | file://:0:0:0:0 | void * | MemberVariable | __va_list_tag |
| foo.h:7:5:7:15 | foo_defined | file://:0:0:0:0 | int | MemberVariable | C |
| foo.h:7:5:7:15 | foo_defined | file://:0:0:0:0 | int | Variable | <none> |
| foo.h:9:5:9:19 | foo_not_defined | file://:0:0:0:0 | int | MemberVariable | C |
| foo.h:9:5:9:19 | foo_not_defined | file://:0:0:0:0 | int | Variable | <none> |

View File

@@ -0,0 +1,9 @@
import cpp
from Variable v, string d, string c
where if v instanceof MemberVariable then (
d = "MemberVariable" and c = ((MemberVariable)v).getDeclaringType().getName()
) else (
d = "Variable" and c = "<none>"
)
select v, v.getType(), d, c

View File

@@ -0,0 +1,10 @@
int complex()
{
auto x = 4;
return x * x;
}
static int simple()
{
return SIMPLE;
}

View File

@@ -0,0 +1,2 @@
| a.h:9:3:9:16 | return ... | a.h:7:12:7:17 | simple | 1 |
| a.h:9:3:9:16 | return ... | a.h:7:12:7:17 | simple | 2 |

View File

@@ -0,0 +1,4 @@
import cpp
from ReturnStmt r
select r, r.getEnclosingFunction(), r.getExpr().getValue()

View File

@@ -0,0 +1,4 @@
#define SIMPLE 1
#include "a.h"
int one() { return simple(); }

View File

@@ -0,0 +1,5 @@
| a.h:3:8:3:8 | x | x | true |
| file://:0:0:0:0 | fp_offset | fp_offset | false |
| file://:0:0:0:0 | gp_offset | gp_offset | false |
| file://:0:0:0:0 | overflow_arg_area | overflow_arg_area | false |
| file://:0:0:0:0 | reg_save_area | reg_save_area | false |

View File

@@ -0,0 +1,5 @@
import cpp
from Variable x, boolean auto
where if x.declaredUsingAutoType() then auto = true else auto = false
select x, x.getName(), auto

View File

@@ -0,0 +1,4 @@
#define SIMPLE 2
#include "a.h"
int two() { return simple(); }

View File

@@ -0,0 +1 @@
static int one = __COUNTER__;

View File

@@ -0,0 +1 @@
static int two = __COUNTER__;

View File

@@ -0,0 +1 @@
static int three = __COUNTER__;

View File

@@ -0,0 +1 @@
static int four = __COUNTER__;

View File

@@ -0,0 +1 @@
static int five = __COUNTER__;

View File

@@ -0,0 +1 @@
static int six = __COUNTER__;

View File

@@ -0,0 +1 @@
static int seven = __COUNTER__;

View File

@@ -0,0 +1 @@
static int eight = __COUNTER__;

View File

@@ -0,0 +1,15 @@
static int zero = __COUNTER__;
// these map to 1.h through 4.h via little.hmap
#include "a.h"
#include "b.h"
#include "C.H"
#include "D.H"
// these map to 5.h through 8.h via big.hmap
#include "e.h"
#include "f.h"
#include "G.H"
#include "H.H"
// semmle-extractor-options: -I${testdir}/little_qltest.hmap -I${testdir}/big_qltest.hmap

View File

@@ -0,0 +1,9 @@
| 1.h:1:12:1:14 | one | 1 |
| 2.h:1:12:1:14 | two | 2 |
| 3.h:1:12:1:16 | three | 3 |
| 4.h:1:12:1:15 | four | 4 |
| 5.h:1:12:1:15 | five | 5 |
| 6.h:1:12:1:14 | six | 6 |
| 7.h:1:12:1:16 | seven | 7 |
| 8.h:1:12:1:16 | eight | 8 |
| headermaps.c:1:12:1:15 | zero | 0 |

View File

@@ -0,0 +1,4 @@
import cpp
from Variable v
select v, v.getInitializer().getExpr().getValue()

View File

@@ -0,0 +1,90 @@
-- This file generates the header map files used by this test.
-- (it is provided in case the maps need to be changed)
local function hash(str)
local n = 0
for c in str:lower():gmatch"." do
n = n + c:byte()*13
end
return n
end
local function write_map(filename, endian, mapping)
local num_entries = 0
local max_value_length = 0
for k, v in pairs(mapping) do
num_entries = num_entries + 1
max_value_length = math.max(max_value_length, #v)
end
local num_buckets = 2^math.ceil(math.log(num_entries + 1)/math.log(2))
local f = io.open(filename, "wb")
local function write_uint32(val)
local b0 = (val % 256); val = (val - b0) / 256
local b1 = (val % 256); val = (val - b1) / 256
local b2 = (val % 256); val = (val - b2) / 256
local b3 = (val % 256);
if endian == "little" then
f:write(string.char(b0, b1, b2, b3))
elseif endian == "big" then
f:write(string.char(b3, b2, b1, b0))
else
error(("Expected endian of %q or %q, got %q"):format("little", "big", endian))
end
end
if endian == "little" then
f:write("pamh\1\0")
else
f:write("hmap\0\1")
end
f:write("\0\0")
write_uint32(6*4 + num_buckets*12)
write_uint32(num_entries)
write_uint32(num_buckets)
write_uint32(max_value_length)
local string_pieces = {"\0"}
local string_piece_length = 1
local encode = setmetatable({}, {__index = function(cache, str)
local result = string_piece_length
cache[str] = result
str = str .."\0"
string_pieces[#string_pieces + 1] = str
string_piece_length = string_piece_length + #str
return result
end})
local buckets = {}
for k, v in pairs(mapping) do
local i = hash(k) % num_buckets
while buckets[i] do
i = (i + 1) % num_buckets
end
local v1, v2 = v:match"(.*/)([^/]*)$"
buckets[i] = {encode[k], encode[v1], encode[v2]}
end
for i = 0, num_buckets-1 do
for _, v in ipairs(buckets[i] or {0, 0, 0}) do
write_uint32(v)
end
end
f:write(table.unpack(string_pieces))
f:close()
end
-- for langtests:
--local root = "semmlecode-cpp-tests/header-variant-tests/headermaps/"
-- for qltest:
local root = "./"
write_map("little.hmap", "little", {
["a.h"] = root .."1.h",
["B.h"] = root .."2.h",
["c.H"] = root .."3.h",
["D.H"] = root .."4.h",
})
write_map("big.hmap", "big", {
["e.h"] = root .."5.h",
["F.h"] = root .."6.h",
["g.H"] = root .."7.h",
["H.H"] = root .."8.h",
})

View File

@@ -0,0 +1 @@
static int dir1_a = __COUNTER__;

View File

@@ -0,0 +1 @@
static int dir1_b = __COUNTER__;

View File

@@ -0,0 +1 @@
static int dir2_a = __COUNTER__;

View File

@@ -0,0 +1,6 @@
#include "a.h"
#include <a.h>
#include "b.h"
static int has_angle_b = __has_include(<b.h>);
// semmle-extractor-options: -I${testdir}/dir2 -iquote ${testdir}/dir1 --edg --clang

View File

@@ -0,0 +1,4 @@
| dir1/a.h:1:12:1:17 | dir1_a | 0 |
| dir1/b.h:1:12:1:17 | dir1_b | 2 |
| dir2/a.h:1:12:1:17 | dir2_a | 1 |
| iquote.c:4:12:4:22 | has_angle_b | 0 |

View File

@@ -0,0 +1,4 @@
import cpp
from Variable v
select v, v.getInitializer().getExpr().getValue()

Some files were not shown because too many files have changed in this diff Show More