Merge branch 'master' into master

This commit is contained in:
Raul Garcia
2018-09-25 10:58:51 -07:00
committed by GitHub
328 changed files with 8737 additions and 7968 deletions

View File

@@ -1,2 +1,2 @@
[*.{ql,qll,qlref,dbscheme,qhelp,html,js,mjs,ts,json,yml}]
end_of_line = lf
[*]
end_of_line = lf

63
.gitattributes vendored
View File

@@ -1,23 +1,48 @@
# The following file types will be normalized to LF line endings in the Git
# database, and will keep those LF line endings in the working tree even on
# Windows. Any other files will have whatever line endings they had when they
# were committed. If you add new entries below, you should renormalize the
# affected files by running the following from the root of this repo (requires
# Git 2.16 or greater):
# Text files will be normalized to LF line endings in the Git database, and will keep those LF line
# endings in the working tree even on Windows. If you make changes below, you should renormalize the
# affected files by running the following from the root of this repo (requires Git 2.16 or greater):
#
# git add --renormalize .
# git status [just to show what files were renormalized]
# git commit -m "Normalize line endings"
#
# Also, please update .editorconfig to handle any new entries as well.
*.ql eol=lf
*.qll eol=lf
*.qlref eol=lf
*.dbscheme eol=lf
*.qhelp eol=lf
*.html eol=lf
*.js eol=lf
*.mjs eol=lf
*.ts eol=lf
*.json eol=lf
*.yml eol=lf
# Anything Git auto-detects as text gets normalized and checked out as LF
* text=auto eol=lf
# Explicitly set a bunch of known extensions to text, in case auto detection gets confused.
*.ql text
*.qll text
*.qlref text
*.dbscheme text
*.qhelp text
*.html text
*.htm text
*.xhtml text
*.xhtm text
*.js text
*.mjs text
*.ts text
*.json text
*.yml text
*.yaml text
*.c text
*.cpp text
*.h text
*.hpp text
*.md text
*.stats text
*.xml text
*.sh text
*.pl text
*.java text
*.cs text
*.py text
*.lua text
*.expected text
# Explicitly set a bunch of known extensions to binary, because Git < 2.10 will treat
# `* text=auto eol=lf` as `* text eol=lf`
*.png -text
*.jpg -text
*.jpeg -text
*.gif -text

4
.gitignore vendored
View File

@@ -12,6 +12,4 @@
/.vs/ql/v15/Browse.VC.opendb
/.vs/ql/v15/Browse.VC.db
/.vs/ProjectSettings.json
/.vs/ql5/v15/Browse.VC.opendb
/.vs/ql5/v15/Browse.VC.db
/.vs/ql5/v15/.suo

View File

@@ -1,20 +1,20 @@
# Improvements to C/C++ analysis
## General improvements
## New queries
| **Query** | **Tags** | **Purpose** |
|-----------------------------|-----------|--------------------------------------------------------------------|
| *@name of query (Query ID)* | *Tags* |*Aim of the new query and whether it is enabled by default or not* |
## Changes to existing queries
| **Query** | **Expected impact** | **Change** |
|----------------------------|------------------------|------------------------------------------------------------------|
| *@name of query (Query ID)*| *Impact on results* | *How/why the query has changed* |
## Changes to QL libraries
* Added a hash consing library for structural comparison of expressions.
# Improvements to C/C++ analysis
## General improvements
## New queries
| **Query** | **Tags** | **Purpose** |
|-----------------------------|-----------|--------------------------------------------------------------------|
| *@name of query (Query ID)* | *Tags* |*Aim of the new query and whether it is enabled by default or not* |
## Changes to existing queries
| **Query** | **Expected impact** | **Change** |
|----------------------------|------------------------|------------------------------------------------------------------|
| Resource not released in destructor | Fewer false positive results | Placement new is now excluded from the query. |
## Changes to QL libraries
* Added a hash consing library for structural comparison of expressions.

View File

@@ -22,5 +22,6 @@
| Regular expression injection | Fewer false-positive results | This rule now identifies calls to `String.prototype.search` with more precision. |
| Unbound event handler receiver | Fewer false-positive results | This rule now recognizes additional ways class methods can be bound. |
| Remote property injection | Fewer results | The precision of this rule has been revised to "medium". Results are no longer shown on LGTM by default. |
| Missing CSRF middleware | Fewer false-positive results | This rule now recognizes additional CSRF protection middlewares. |
## Changes to QL libraries

View File

@@ -1,13 +1,13 @@
# CWE-120: Buffer Copy without Checking Size of Input ('Classic Buffer Overflow')
+ semmlecode-cpp-queries/Security/CWE/CWE-120/UnboundedWrite.ql: /CWE/CWE-120
@name Unbounded write (CWE-120)
+ semmlecode-cpp-queries/Security/CWE/CWE-120/BadlyBoundedWrite.ql: /CWE/CWE-120
@name Badly bounded write (CWE-120)
+ semmlecode-cpp-queries/Security/CWE/CWE-120/OverrunWrite.ql: /CWE/CWE-120
@name Potentially overrunning write (CWE-120)
+ semmlecode-cpp-queries/Security/CWE/CWE-120/OverrunWriteFloat.ql: /CWE/CWE-120
@name Potentially overrunning write with float to string conversion (CWE-120)
+ semmlecode-cpp-queries/Best Practices/Likely Errors/OffsetUseBeforeRangeCheck.ql: /CWE/CWE-120
@name Array offset used before range check (CWE-120)
+ semmlecode-cpp-queries/Likely Bugs/Memory Management/UnsafeUseOfStrcat.ql: /CWE/CWE-120
@name Potentially unsafe use of strcat (CWE-120)
# CWE-120: Buffer Copy without Checking Size of Input ('Classic Buffer Overflow')
+ semmlecode-cpp-queries/Security/CWE/CWE-120/UnboundedWrite.ql: /CWE/CWE-120
@name Unbounded write (CWE-120)
+ semmlecode-cpp-queries/Security/CWE/CWE-120/BadlyBoundedWrite.ql: /CWE/CWE-120
@name Badly bounded write (CWE-120)
+ semmlecode-cpp-queries/Security/CWE/CWE-120/OverrunWrite.ql: /CWE/CWE-120
@name Potentially overrunning write (CWE-120)
+ semmlecode-cpp-queries/Security/CWE/CWE-120/OverrunWriteFloat.ql: /CWE/CWE-120
@name Potentially overrunning write with float to string conversion (CWE-120)
+ semmlecode-cpp-queries/Best Practices/Likely Errors/OffsetUseBeforeRangeCheck.ql: /CWE/CWE-120
@name Array offset used before range check (CWE-120)
+ semmlecode-cpp-queries/Likely Bugs/Memory Management/UnsafeUseOfStrcat.ql: /CWE/CWE-120
@name Potentially unsafe use of strcat (CWE-120)

View File

@@ -1,3 +1,3 @@
# CWE-121: Stack-based Buffer Overflow
+ semmlecode-cpp-queries/Security/CWE/CWE-121/UnterminatedVarargsCall.ql: /CWE/CWE-121
@name Unterminated variadic call (CWE-121)
# CWE-121: Stack-based Buffer Overflow
+ semmlecode-cpp-queries/Security/CWE/CWE-121/UnterminatedVarargsCall.ql: /CWE/CWE-121
@name Unterminated variadic call (CWE-121)

View File

@@ -1,7 +1,7 @@
# CWE-131: Incorrect Calculation of Buffer Size
+ semmlecode-cpp-queries/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql: /CWE/CWE-131
@name No space for zero terminator (CWE-131)
+ semmlecode-cpp-queries/Critical/SizeCheck.ql: /CWE/CWE-131
@name Not enough memory allocated for pointer type (CWE-131)
+ semmlecode-cpp-queries/Critical/SizeCheck2.ql: /CWE/CWE-131
@name Not enough memory allocated for array of pointer type (CWE-131)
# CWE-131: Incorrect Calculation of Buffer Size
+ semmlecode-cpp-queries/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql: /CWE/CWE-131
@name No space for zero terminator (CWE-131)
+ semmlecode-cpp-queries/Critical/SizeCheck.ql: /CWE/CWE-131
@name Not enough memory allocated for pointer type (CWE-131)
+ semmlecode-cpp-queries/Critical/SizeCheck2.ql: /CWE/CWE-131
@name Not enough memory allocated for array of pointer type (CWE-131)

View File

@@ -1,13 +1,13 @@
# CWE-134: Uncontrolled Format String
+ semmlecode-cpp-queries/Likely Bugs/Format/NonConstantFormat.ql: /CWE/CWE-134
@name Non-constant format string (CWE-134)
# This one runs out of memory. See ODASA-608.
#+ semmlecode-cpp-queries/PointsTo/TaintedFormatStrings.ql: /CWE/CWE-134
+ semmlecode-cpp-queries/Likely Bugs/Format/WrongNumberOfFormatArguments.ql: /CWE/CWE-134
@name Wrong number of arguments to formatting function (CWE-134)
+ semmlecode-cpp-queries/Likely Bugs/Format/WrongTypeFormatArguments.ql: /CWE/CWE-134
@name Wrong type of arguments to formatting function (CWE-134)
+ semmlecode-cpp-queries/Security/CWE/CWE-134/UncontrolledFormatString.ql: /CWE/CWE-134
@name Uncontrolled format string (CWE-134)
+ semmlecode-cpp-queries/Security/CWE/CWE-134/UncontrolledFormatStringThroughGlobalVar.ql: /CWE/CWE-134
@name Uncontrolled format string (through global variable) (CWE-134)
# CWE-134: Uncontrolled Format String
+ semmlecode-cpp-queries/Likely Bugs/Format/NonConstantFormat.ql: /CWE/CWE-134
@name Non-constant format string (CWE-134)
# This one runs out of memory. See ODASA-608.
#+ semmlecode-cpp-queries/PointsTo/TaintedFormatStrings.ql: /CWE/CWE-134
+ semmlecode-cpp-queries/Likely Bugs/Format/WrongNumberOfFormatArguments.ql: /CWE/CWE-134
@name Wrong number of arguments to formatting function (CWE-134)
+ semmlecode-cpp-queries/Likely Bugs/Format/WrongTypeFormatArguments.ql: /CWE/CWE-134
@name Wrong type of arguments to formatting function (CWE-134)
+ semmlecode-cpp-queries/Security/CWE/CWE-134/UncontrolledFormatString.ql: /CWE/CWE-134
@name Uncontrolled format string (CWE-134)
+ semmlecode-cpp-queries/Security/CWE/CWE-134/UncontrolledFormatStringThroughGlobalVar.ql: /CWE/CWE-134
@name Uncontrolled format string (through global variable) (CWE-134)

View File

@@ -1,17 +1,17 @@
// an include declaration just adds one source dependency, it does not automatically
// add a dependency from this file to all the declarations in stdio.h
#include <stdio.h>
#include <myfile.h> // contains non-static global myfile_err
extern int myfile_err; // this external declaration adds a dependency on myfile.h
class C {
public:
C() {
// one dependency for printf:
printf("Hello world!");
// one dependency for FILE type, and one for NULL macro:
FILE fp = NULL;
}
};
// an include declaration just adds one source dependency, it does not automatically
// add a dependency from this file to all the declarations in stdio.h
#include <stdio.h>
#include <myfile.h> // contains non-static global myfile_err
extern int myfile_err; // this external declaration adds a dependency on myfile.h
class C {
public:
C() {
// one dependency for printf:
printf("Hello world!");
// one dependency for FILE type, and one for NULL macro:
FILE fp = NULL;
}
};

View File

@@ -1,20 +1,20 @@
//This struct contains 30 fields.
struct MyParticle {
bool isActive;
int priority;
float x, y, z;
float dx, dy, dz;
float ddx, ddy, ddz;
bool isCollider;
int age, maxAge;
float size1, size2;
bool hasColor;
unsigned char r1, g1, b1, a1;
unsigned char r2, g2, b2, a2;
class texture *tex;
float u1, v1, u2, v2;
};
//This struct contains 30 fields.
struct MyParticle {
bool isActive;
int priority;
float x, y, z;
float dx, dy, dz;
float ddx, ddy, ddz;
bool isCollider;
int age, maxAge;
float size1, size2;
bool hasColor;
unsigned char r1, g1, b1, a1;
unsigned char r2, g2, b2, a2;
class texture *tex;
float u1, v1, u2, v2;
};

View File

@@ -1,8 +1,8 @@
// this example has 15 parameters.
void fillRect(int x, int y, int w, int h,
int r1, int g1, int b1, int a1,
int r2, int g2, int b2, int a2,
gradient_type grad, unsigned int flags, bool border)
{
// ...
}
// this example has 15 parameters.
void fillRect(int x, int y, int w, int h,
int r1, int g1, int b1, int a1,
int r2, int g2, int b2, int a2,
gradient_type grad, unsigned int flags, bool border)
{
// ...
}

View File

@@ -1,13 +1,13 @@
//This condition is too complex and can be improved by using local variables
bool accept_message =
(message_type == CONNECT && _state != CONNECTED) ||
(message_type == DISCONNECT && _state == CONNECTED) ||
(message_type == DATA && _state == CONNECTED);
//This condition is acceptable, as all the logical operators are of the same type (&&)
bool valid_connect =
message_type == CONNECT &&
_state != CONNECTED &&
time_since_prev_connect > MAX_CONNECT_INTERVAL &&
message_length <= MAX_PACKET_SIZE &&
//This condition is too complex and can be improved by using local variables
bool accept_message =
(message_type == CONNECT && _state != CONNECTED) ||
(message_type == DISCONNECT && _state == CONNECTED) ||
(message_type == DATA && _state == CONNECTED);
//This condition is acceptable, as all the logical operators are of the same type (&&)
bool valid_connect =
message_type == CONNECT &&
_state != CONNECTED &&
time_since_prev_connect > MAX_CONNECT_INTERVAL &&
message_length <= MAX_PACKET_SIZE &&
checksum(message) == get_checksum_field(message);

View File

@@ -1,6 +1,6 @@
void f(int i) {
for (int i = 0; i < 10; ++i) { //the loop variable hides the parameter to f()
...
}
}
void f(int i) {
for (int i = 0; i < 10; ++i) { //the loop variable hides the parameter to f()
...
}
}

View File

@@ -1,12 +1,12 @@
void f() {
int i = 10;
for (int i = 0; i < 10; i++) { //the loop counter hides the variable
...
}
{
int i = 12; //this variable hides the variable in the outer block
...
}
}
void f() {
int i = 10;
for (int i = 0; i < 10; i++) { //the loop counter hides the variable
...
}
{
int i = 12; //this variable hides the variable in the outer block
...
}
}

View File

@@ -1,12 +1,12 @@
int i = 10;
void f() {
for (int i = 0; i < 10; i++) { //the loop counter hides the global variable i
...
}
{
int i = 12; //this variable hides the global variable i
...
}
}
int i = 10;
void f() {
for (int i = 0; i < 10; i++) { //the loop counter hides the global variable i
...
}
{
int i = 12; //this variable hides the global variable i
...
}
}

View File

@@ -1,9 +1,9 @@
void f(int i) {
if (i == 10); //empty then block
... //won't be part of the if statement
if (i == 12) {
...
} else { //empty else block, most likely a mistake
}
}
void f(int i) {
if (i == 10); //empty then block
... //won't be part of the if statement
if (i == 12) {
...
} else { //empty else block, most likely a mistake
}
}

View File

@@ -1,43 +1,43 @@
static int idctr = 0;
//Basic connection with id
class Connection {
public:
int connId;
virtual void print_info() {
cout << "id: " << connId << "\n";
}
Connection() {
connId = idctr++;
}
};
//Adds counters, and an overriding print_info
class MeteredConnection : public Connection {
public:
int txCtr;
int rxCtr;
MeteredConnection() {
txCtr = 0;
rxCtr = 0;
}
virtual void print_info() {
cout << "id: " << connId << "\n" << "tx/rx: " << txCtr << "/" << rxCtr << "\n";
}
};
int main(int argc, char* argv[]) {
Connection conn;
MeteredConnection m_conn;
Connection curr_conn = conn;
curr_conn.print_info();
curr_conn = m_conn; //Wrong: Derived MetricConnection assigned to Connection
//variable, will slice off the counters and the overriding print_info
curr_conn.print_info(); //Will not print the counters.
Connection* curr_pconn = &conn;
curr_pconn->print_info();
curr_pconn = &m_conn; //Correct: Pointer assigned to address of the MetricConnection.
//Counters and virtual functions remain intact.
curr_pconn->print_info(); //Will call the correct method MeteredConnection::print_info
}
static int idctr = 0;
//Basic connection with id
class Connection {
public:
int connId;
virtual void print_info() {
cout << "id: " << connId << "\n";
}
Connection() {
connId = idctr++;
}
};
//Adds counters, and an overriding print_info
class MeteredConnection : public Connection {
public:
int txCtr;
int rxCtr;
MeteredConnection() {
txCtr = 0;
rxCtr = 0;
}
virtual void print_info() {
cout << "id: " << connId << "\n" << "tx/rx: " << txCtr << "/" << rxCtr << "\n";
}
};
int main(int argc, char* argv[]) {
Connection conn;
MeteredConnection m_conn;
Connection curr_conn = conn;
curr_conn.print_info();
curr_conn = m_conn; //Wrong: Derived MetricConnection assigned to Connection
//variable, will slice off the counters and the overriding print_info
curr_conn.print_info(); //Will not print the counters.
Connection* curr_pconn = &conn;
curr_pconn->print_info();
curr_pconn = &m_conn; //Correct: Pointer assigned to address of the MetricConnection.
//Counters and virtual functions remain intact.
curr_pconn->print_info(); //Will call the correct method MeteredConnection::print_info
}

View File

@@ -1,16 +1,16 @@
void sanitize(Fields[] record) {
//The number of fields here can be put in a const
for (fieldCtr = 0; field < 7; field++) {
sanitize(fields[fieldCtr]);
}
}
#define NUM_FIELDS 7
void process(Fields[] record) {
//This avoids using a magic constant by using the macro instead
for (fieldCtr = 0; field < NUM_FIELDS; field++) {
process(fields[fieldCtr]);
}
}
void sanitize(Fields[] record) {
//The number of fields here can be put in a const
for (fieldCtr = 0; field < 7; field++) {
sanitize(fields[fieldCtr]);
}
}
#define NUM_FIELDS 7
void process(Fields[] record) {
//This avoids using a magic constant by using the macro instead
for (fieldCtr = 0; field < NUM_FIELDS; field++) {
process(fields[fieldCtr]);
}
}

View File

@@ -1,26 +1,26 @@
class C {
private:
Other* other = NULL;
public:
C(const C& copyFrom) {
Other* newOther = new Other();
*newOther = copyFrom.other;
this->other = newOther;
}
//No operator=, by default will just copy the pointer other, will not create a new object
};
class D {
Other* other = NULL;
public:
D& operator=(D& rhs) {
Other* newOther = new Other();
*newOther = rhs.other;
this->other = newOther;
return *this;
}
//No copy constructor, will just copy the pointer other and not create a new object
};
class C {
private:
Other* other = NULL;
public:
C(const C& copyFrom) {
Other* newOther = new Other();
*newOther = copyFrom.other;
this->other = newOther;
}
//No operator=, by default will just copy the pointer other, will not create a new object
};
class D {
Other* other = NULL;
public:
D& operator=(D& rhs) {
Other* newOther = new Other();
*newOther = rhs.other;
this->other = newOther;
return *this;
}
//No copy constructor, will just copy the pointer other and not create a new object
};

View File

@@ -1,32 +1,32 @@
//This switch statement has long case statements, and can become difficult to
//read as the processing for each message type becomes more complex
switch (message_type) {
case CONNECT:
_state = CONNECTING;
int message_id = message_get_id(message);
int source = connect_get_source(message);
//More code here...
send(connect_response);
break;
case DISCONNECT:
_state = DISCONNECTING;
int message_id = message_get_id(message);
int source = disconnect_get_source(message);
//More code here...
send(disconnect_response);
break;
default:
log("Invalid message, id : %d", message_get_id(message));
}
//This is better, as each case is split out to a separate function
switch (packet_type) {
case STREAM:
process_stream_packet(packet);
break;
case DATAGRAM:
process_datagram_packet(packet);
break;
default:
log("Invalid packet type: %d", packet_type);
//This switch statement has long case statements, and can become difficult to
//read as the processing for each message type becomes more complex
switch (message_type) {
case CONNECT:
_state = CONNECTING;
int message_id = message_get_id(message);
int source = connect_get_source(message);
//More code here...
send(connect_response);
break;
case DISCONNECT:
_state = DISCONNECTING;
int message_id = message_get_id(message);
int source = disconnect_get_source(message);
//More code here...
send(disconnect_response);
break;
default:
log("Invalid message, id : %d", message_get_id(message));
}
//This is better, as each case is split out to a separate function
switch (packet_type) {
case STREAM:
process_stream_packet(packet);
break;
case DATAGRAM:
process_datagram_packet(packet);
break;
default:
log("Invalid packet type: %d", packet_type);
}

View File

@@ -1,5 +1,5 @@
{
int x = 0; //x is unused
int y = 0;
cout << y;
}
{
int x = 0; //x is unused
int y = 0;
cout << y;
}

View File

@@ -1,14 +1,14 @@
//start of file
static void f() { //static function f() is unused in the file
//...
}
static void g() {
//...
}
void public_func() { //non-static function public_func is not called in file,
//but could be visible in other files
//...
g(); //call to g()
//...
}
//end of file
//start of file
static void f() { //static function f() is unused in the file
//...
}
static void g() {
//...
}
void public_func() { //non-static function public_func is not called in file,
//but could be visible in other files
//...
g(); //call to g()
//...
}
//end of file

View File

@@ -1,5 +1,5 @@
void f() {
static int i = 0; //i is unused
...
return;
}
void f() {
static int i = 0; //i is unused
...
return;
}

View File

@@ -1,19 +1,19 @@
while(result) {
if ( ... )
...
else if (result //wrong: this test is redundant
&& result->flags != 0)
...
result = next(queue);
}
fp = fopen(log, "r");
if (fp) {
/*
* large block of code
*/
if (!fp) { //wrong: always false
... /* dead code */
}
}
while(result) {
if ( ... )
...
else if (result //wrong: this test is redundant
&& result->flags != 0)
...
result = next(queue);
}
fp = fopen(log, "r");
if (fp) {
/*
* large block of code
*/
if (!fp) { //wrong: always false
... /* dead code */
}
}

View File

@@ -1,12 +1,12 @@
class C {
public:
void g() {
...
//f() was previously used but is now commented, orphaning f()
//f();
...
}
private:
void f() { //is now unused, and can be removed
}
};
class C {
public:
void g() {
...
//f() was previously used but is now commented, orphaning f()
//f();
...
}
private:
void f() { //is now unused, and can be removed
}
};

View File

@@ -1,9 +1,9 @@
int f() {
try {
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
do_stuff(sockfd);
return sockfd; //if there are no exceptions, the socket is returned
} catch (int do_stuff_exception) {
return -1; //return error value, but sockfd may still be open
}
}
int f() {
try {
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
do_stuff(sockfd);
return sockfd; //if there are no exceptions, the socket is returned
} catch (int do_stuff_exception) {
return -1; //return error value, but sockfd may still be open
}
}

View File

@@ -1,6 +1,6 @@
int main(int argc, char* argv[]) {
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
int status = 0;
... //code that does not close sockfd
return status; //sockfd is never closed
}
int main(int argc, char* argv[]) {
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
int status = 0;
... //code that does not close sockfd
return status; //sockfd is never closed
}

View File

@@ -1,11 +1,11 @@
int g_callCtr;
void initGlobals() {
g_callCtr = 0;
}
int main(int argc, char* argv[]) {
...
cout << g_callCtr; //callCtr used before it is initialized
initGlobals();
}
int g_callCtr;
void initGlobals() {
g_callCtr = 0;
}
int main(int argc, char* argv[]) {
...
cout << g_callCtr; //callCtr used before it is initialized
initGlobals();
}

View File

@@ -1,12 +1,12 @@
GlobalStorage *g_storage;
void init() { //initializes g_storage, but is never run from main
g_storage = new GlobalStorage();
...
}
int main(int argc, char *argv[]) {
... //init not called
strcpy(g_storage->name, argv[1]); // g_storage is used before init() is called
...
}
GlobalStorage *g_storage;
void init() { //initializes g_storage, but is never run from main
g_storage = new GlobalStorage();
...
}
int main(int argc, char *argv[]) {
... //init not called
strcpy(g_storage->name, argv[1]); // g_storage is used before init() is called
...
}

View File

@@ -1,13 +1,13 @@
typedef struct Names {
char first[100];
char last[100];
} Names;
int doFoo(Names n) { //wrong: n is passed by value (meaning the entire structure
//is copied onto the stack, instead of just a pointer)
...
}
int doBar(Names &n) { //better, only a reference is passed
...
}
typedef struct Names {
char first[100];
char last[100];
} Names;
int doFoo(Names n) { //wrong: n is passed by value (meaning the entire structure
//is copied onto the stack, instead of just a pointer)
...
}
int doBar(Names &n) { //better, only a reference is passed
...
}

View File

@@ -1,11 +1,11 @@
typedef struct {
char name[100];
int status;
} person;
void f() {
person* buf = NULL;
buf = malloc(sizeof(person));
(*buf).status = 0; //access to buf before it was checked for NULL
}
typedef struct {
char name[100];
int status;
} person;
void f() {
person* buf = NULL;
buf = malloc(sizeof(person));
(*buf).status = 0; //access to buf before it was checked for NULL
}

View File

@@ -1,5 +1,5 @@
Record* record = new Record[SIZE];
...
delete record; //record was created using 'new[]', but was freed using 'delete'
Record* record = new Record[SIZE];
...
delete record; //record was created using 'new[]', but was freed using 'delete'

View File

@@ -1,5 +1,5 @@
Record *ptr = new Record(...);
...
delete [] ptr; // ptr was created using 'new', but was freed using 'delete[]'
Record *ptr = new Record(...);
...
delete [] ptr; // ptr was created using 'new', but was freed using 'delete[]'

View File

@@ -1,5 +1,5 @@
Record *ptr = new Record(...);
...
free(ptr); // BAD: ptr was created using 'new', but is being freed using 'free'
Record *ptr = new Record(...);
...
free(ptr); // BAD: ptr was created using 'new', but is being freed using 'free'

View File

@@ -1,6 +1,6 @@
{
int i;
...
int g = COEFF * i; //i is used before it is initialized
}
{
int i;
...
int g = COEFF * i; //i is used before it is initialized
}

View File

@@ -1,13 +1,13 @@
int main(int argc, char* argv[]) {
char param[SIZE];
char arg1[10];
char arg2[20];
//wrong: only uses the size of the source (argv[1]) when using strncpy
strncpy(param, argv[1], strlen(arg1));
//correct: uses the size of the destination array as well
strncpy(param, argv[1], min(strlen(arg1, sizeof(param) -1)));
}
int main(int argc, char* argv[]) {
char param[SIZE];
char arg1[10];
char arg2[20];
//wrong: only uses the size of the source (argv[1]) when using strncpy
strncpy(param, argv[1], strlen(arg1));
//correct: uses the size of the destination array as well
strncpy(param, argv[1], min(strlen(arg1, sizeof(param) -1)));
}

View File

@@ -1,23 +1,23 @@
int doFoo() {
...
return status;
}
void f() {
if (doFoo() == OK) {
...
}
}
void g() {
int status = doFoo();
if (status == OK) {
...
}
}
void err() {
doFoo(); //doFoo is called but its return value is not checked, and
//the value is checked in other locations
...
}
int doFoo() {
...
return status;
}
void f() {
if (doFoo() == OK) {
...
}
}
void g() {
int status = doFoo();
if (status == OK) {
...
}
}
void err() {
doFoo(); //doFoo is called but its return value is not checked, and
//the value is checked in other locations
...
}

View File

@@ -1,10 +1,10 @@
#define RECORD_SIZE 30 //incorrect or outdated size for record
typedef struct {
char name[30];
int status;
} Record;
void f() {
Record* p = malloc(RECORD_SIZE); //not of sufficient size to hold a Record
...
}
#define RECORD_SIZE 30 //incorrect or outdated size for record
typedef struct {
char name[30];
int status;
} Record;
void f() {
Record* p = malloc(RECORD_SIZE); //not of sufficient size to hold a Record
...
}

View File

@@ -1,4 +1,4 @@
{
int foo = 1;
... //foo is unused
}
{
int foo = 1;
... //foo is unused
}

View File

@@ -1,9 +1,9 @@
int f() {
char* buf = new char[SIZE];
....
if (error) {
free(buf); //error handling has freed the buffer
}
...
log_contents(buf); //but it is still used here for logging
}
int f() {
char* buf = new char[SIZE];
....
if (error) {
free(buf); //error handling has freed the buffer
}
...
log_contents(buf); //but it is still used here for logging
}

View File

@@ -1,4 +1,4 @@
int isOdd(int n) {
//TODO: Works only for positive n. Need to check if negative n is valid input
return (n % 2) == 1;
int isOdd(int n) {
//TODO: Works only for positive n. Need to check if negative n is valid input
return (n % 2) == 1;
}

View File

@@ -1,8 +1,8 @@
// header_file.h
#ifndef HEADER_FILE_H
#define HEADER_FILE_H
// ...
// header_file.h
#ifndef HEADER_FILE_H
#define HEADER_FILE_H
// ...
#endif // HEADER_FILE_H

View File

@@ -1,8 +1,8 @@
// another_header_file.h
#ifndef HEADER_FILE_H // should be ANOTHER_HEADER_FILE_H
#define HEADER_FILE_H // should be ANOTHER_HEADER_FILE_H
// ...
// another_header_file.h
#ifndef HEADER_FILE_H // should be ANOTHER_HEADER_FILE_H
#define HEADER_FILE_H // should be ANOTHER_HEADER_FILE_H
// ...
#endif // HEADER_FILE_H

View File

@@ -1,6 +1,6 @@
void h() {
int a, b, c;
a < b != c; //parenthesize to explicitly define order of operators
(a < b) < c; //correct: parenthesized to specify order
}
void h() {
int a, b, c;
a < b != c; //parenthesize to explicitly define order of operators
(a < b) < c; //correct: parenthesized to specify order
}

View File

@@ -21,17 +21,19 @@ import semmle.code.cpp.controlflow.SSA
/**
* Holds if `e` is either:
* - a constant
* - a char-typed expression, meaning it's a small number
* - an array access to an array of constants
* - flows from one of the above
* In these cases the value of `e` is likely to be small and
* controlled, so we consider it less likely to cause an overflow.
*/
predicate effectivelyConstant(Expr e) {
predicate likelySmall(Expr e) {
e.isConstant() or
e.getType().getSize() <= 1 or
e.(ArrayExpr).getArrayBase().getType().(ArrayType).getBaseType().isConst() or
exists(SsaDefinition def, Variable v |
def.getAUse(v) = e and
effectivelyConstant(def.getDefiningValue(v))
likelySmall(def.getDefiningValue(v))
)
}
@@ -56,7 +58,7 @@ int getEffectiveMulOperands(MulExpr me) {
result = count(Expr op |
op = getMulOperand*(me) and
not op instanceof MulExpr and
not effectivelyConstant(op)
not likelySmall(op)
)
}

View File

@@ -1,13 +1,13 @@
//Function foo's array parameter has a specified size
void foo(int a[10]) {
int i = 0;
for (i = 0; i <10; i++) {
a[i] = i * 2;
}
}
...
int my_arr[5];
//Function foo's array parameter has a specified size
void foo(int a[10]) {
int i = 0;
for (i = 0; i <10; i++) {
a[i] = i * 2;
}
}
...
int my_arr[5];
foo(my_arr); //my_arr is smaller than foo's array parameter, and will cause access to memory outside its bounds

View File

@@ -1,4 +1,4 @@
//sz is a signed integer, but malloc expects one that is unsigned.
//Negative values will be interpreted as a large number, which may
//lead to unexpected behavior
char *buf = malloc(sz);
//sz is a signed integer, but malloc expects one that is unsigned.
//Negative values will be interpreted as a large number, which may
//lead to unexpected behavior
char *buf = malloc(sz);

View File

@@ -1,5 +1,5 @@
void f(char *p) {
int my_ptr = p; //Wrong: pointer assigned to int, would be incorrect if sizeof(char*)
//is larger than sizeof(int)
//...
}
void f(char *p) {
int my_ptr = p; //Wrong: pointer assigned to int, would be incorrect if sizeof(char*)
//is larger than sizeof(int)
//...
}

View File

@@ -1,30 +1,30 @@
struct property {
char *name;
int value;
};
struct property * get_property(char *key);
struct property * get_property_default(char *key, int default_value);
void check_properties() {
// this call will get flagged since most
// calls to get_property handle NULL
struct property *p1 = get_property("time");
if(p1->value > 600) {
...
}
// this call will not get flagged since
// the result of the call is checked for NULL
struct property *p2 = get_property("time");
if(p2 != NULL && p2->value > 600) {
...
}
// this call will not get flagged since calls
// to get_property_default rarely handle NULL
struct property *p3 = get_property_default("time", 50);
if(p3->value > 60) {
...
}
}
struct property {
char *name;
int value;
};
struct property * get_property(char *key);
struct property * get_property_default(char *key, int default_value);
void check_properties() {
// this call will get flagged since most
// calls to get_property handle NULL
struct property *p1 = get_property("time");
if(p1->value > 600) {
...
}
// this call will not get flagged since
// the result of the call is checked for NULL
struct property *p2 = get_property("time");
if(p2 != NULL && p2->value > 600) {
...
}
// this call will not get flagged since calls
// to get_property_default rarely handle NULL
struct property *p3 = get_property_default("time", 50);
if(p3->value > 60) {
...
}
}

View File

@@ -1,13 +1,13 @@
if (!flags & SOME_BIT) { //wrong: '!' has higher precedence than '&', so this
// is bracketed as '(!flags) & SOME_BIT', and does not
// check whether a particular bit is set.
// ...
}
if ((p != NULL) & p->f()) { //wrong: The use of '&' rather than '&&' will still
// de-reference the pointer even if it is NULL.
// ...
}
int bits = (s > 8) & 0xff; //wrong: Invalid attempt to get the 8 most significant
// bits of a short.
if (!flags & SOME_BIT) { //wrong: '!' has higher precedence than '&', so this
// is bracketed as '(!flags) & SOME_BIT', and does not
// check whether a particular bit is set.
// ...
}
if ((p != NULL) & p->f()) { //wrong: The use of '&' rather than '&&' will still
// de-reference the pointer even if it is NULL.
// ...
}
int bits = (s > 8) & 0xff; //wrong: Invalid attempt to get the 8 most significant
// bits of a short.

View File

@@ -1,11 +1,11 @@
if (0 || condition) { //wrong: can be converted to just 'condition'
//...
}
if (0 && condition) { //wrong: always evaluates to false, if statement can be removed
// ...
}
if ('A' == 65 && condition) { // wrong: can be converted to just 'condition'
// ...
}
if (0 || condition) { //wrong: can be converted to just 'condition'
//...
}
if (0 && condition) { //wrong: always evaluates to false, if statement can be removed
// ...
}
if ('A' == 65 && condition) { // wrong: can be converted to just 'condition'
// ...
}

View File

@@ -1,30 +1,30 @@
typedef enum {
RED,
ORANGE,
YELLOW,
GREEN,
BLUE,
INDIGO,
VIOLET
} colors;
int f(colors c) {
switch (c) {
case RED:
//...
case GREEN:
//...
case BLUE:
//...
//wrong: does not use all enum values, and has no default
}
switch(c) {
case RED:
//...
case GREEN:
//...
default:
//correct: does not use all enum values, but has a default
}
}
typedef enum {
RED,
ORANGE,
YELLOW,
GREEN,
BLUE,
INDIGO,
VIOLET
} colors;
int f(colors c) {
switch (c) {
case RED:
//...
case GREEN:
//...
case BLUE:
//...
//wrong: does not use all enum values, and has no default
}
switch(c) {
case RED:
//...
case GREEN:
//...
default:
//correct: does not use all enum values, but has a default
}
}

View File

@@ -1,12 +1,12 @@
void f(char* s, float f) {
char buf[30];
//wrong: gets has no limit to the length of data it puts in the buffer
gets(buf);
//wrong: sprintf does not limit the length of the string put into buf
sprintf(buf, "This is a string: %s", s);
//wrong: %f can expand to a very long string in extreme cases, easily overrunning this buffer
sprintf(buf, "This is a float: %f", f);
}
void f(char* s, float f) {
char buf[30];
//wrong: gets has no limit to the length of data it puts in the buffer
gets(buf);
//wrong: sprintf does not limit the length of the string put into buf
sprintf(buf, "This is a string: %s", s);
//wrong: %f can expand to a very long string in extreme cases, easily overrunning this buffer
sprintf(buf, "This is a float: %f", f);
}

View File

@@ -1,4 +1,4 @@
strncat(dest, src, strlen(dest)); //wrong: should use remaining size of dest
strncat(dest, src, sizeof(dest)); //wrong: should use remaining size of dest.
//Also fails if dest is a pointer and not an array.
strncat(dest, src, strlen(dest)); //wrong: should use remaining size of dest
strncat(dest, src, sizeof(dest)); //wrong: should use remaining size of dest.
//Also fails if dest is a pointer and not an array.

View File

@@ -1,4 +1,4 @@
void f(char s[]) {
int size = sizeof(s); //wrong: s is now a char*, not an array.
//sizeof(s) will evaluate to sizeof(char *)
}
void f(char s[]) {
int size = sizeof(s); //wrong: s is now a char*, not an array.
//sizeof(s) will evaluate to sizeof(char *)
}

View File

@@ -1,16 +1,16 @@
int x1 = 0;
for (x1 = 0; x1 < 100; x1++) {
int x2 = 0;
for (x1 = 0; x1 < 300; x1++) {
// this is most likely a typo
// the outer loop will exit immediately
}
}
for (x1 = 0; x1 < 100; x1++) {
if(x1 == 10 && condition) {
for (; x1 < 75; x1++) {
// this should be written as a while loop
}
}
}
int x1 = 0;
for (x1 = 0; x1 < 100; x1++) {
int x2 = 0;
for (x1 = 0; x1 < 300; x1++) {
// this is most likely a typo
// the outer loop will exit immediately
}
}
for (x1 = 0; x1 < 100; x1++) {
if(x1 == 10 && condition) {
for (; x1 < 75; x1++) {
// this should be written as a while loop
}
}
}

View File

@@ -1,31 +1,31 @@
class Base {
public:
Resource *p;
Base() {
p = createResource();
}
//...
~Base() {
//wrong: this destructor is non-virtual, but Base has a derived class
// with a non-virtual destructor
freeResource(p);
}
};
class Derived: public Base {
public:
Resource *dp;
Derived() {
dp = createResource2();
}
~Derived() {
freeResource2(dp);
}
};
int f() {
Base *b = new Derived(); //creates resources for both Base::p and Derived::dp
//...
delete b; //will only call Base::~Base(), leaking the resource dp.
// Change both destructors to virtual to ensure they are both called.
}
class Base {
public:
Resource *p;
Base() {
p = createResource();
}
//...
~Base() {
//wrong: this destructor is non-virtual, but Base has a derived class
// with a non-virtual destructor
freeResource(p);
}
};
class Derived: public Base {
public:
Resource *dp;
Derived() {
dp = createResource2();
}
~Derived() {
freeResource2(dp);
}
};
int f() {
Base *b = new Derived(); //creates resources for both Base::p and Derived::dp
//...
delete b; //will only call Base::~Base(), leaking the resource dp.
// Change both destructors to virtual to ensure they are both called.
}

View File

@@ -1,19 +1,19 @@
class C {
public:
//...
~C(){
if (error) {
throw "Exception in destructor"; //wrong: exception thrown in destructor
}
}
};
void f() {
C* c = new C();
try {
doOperation(c);
delete c;
} catch ( char * do_operation_exception) {
delete c; //would immediately terminate program if C::~C throws an exception
}
}
class C {
public:
//...
~C(){
if (error) {
throw "Exception in destructor"; //wrong: exception thrown in destructor
}
}
};
void f() {
C* c = new C();
try {
doOperation(c);
delete c;
} catch ( char * do_operation_exception) {
delete c; //would immediately terminate program if C::~C throws an exception
}
}

View File

@@ -1,14 +1,14 @@
int i = 0;
for (i = 0; i < NUM_RECORDS; i++) {
int j = 0;
//This loop should have a more descriptive iteration variable
for (j = 0; j < NUM_FIELDS; j++) {
process(record[i]->field[j]);
}
int field_idx = 0;
//Better: the inner loop has a descriptive name
for (field_idx = 0; field_idx < NUM_FIELDS; field_idx++) {
save(record[i]->field[field_idx]);
}
int i = 0;
for (i = 0; i < NUM_RECORDS; i++) {
int j = 0;
//This loop should have a more descriptive iteration variable
for (j = 0; j < NUM_FIELDS; j++) {
process(record[i]->field[j]);
}
int field_idx = 0;
//Better: the inner loop has a descriptive name
for (field_idx = 0; field_idx < NUM_FIELDS; field_idx++) {
save(record[i]->field[field_idx]);
}
}

View File

@@ -1,28 +1,28 @@
void main(int argc, char **argv) {
uint32_t big_num = INT32_MAX;
char buf[big_num];
int16_t bytes_received = 0;
int max_get = INT16_MAX + 1;
// BAD: 'bytes_received' is compared with a value of a wider type.
// 'bytes_received' overflows before reaching 'max_get',
// causing an infinite loop
while (bytes_received < max_get)
bytes_received += get_from_input(buf, bytes_received);
}
uint32_t bytes_received = 0;
// GOOD: 'bytes_received2' has a type at least as wide as 'max_get'
while (bytes_received < max_get) {
bytes_received += get_from_input(buf, bytes_received);
}
}
int getFromInput(char *buf, short pos) {
// write to buf
// ...
return 1;
}
void main(int argc, char **argv) {
uint32_t big_num = INT32_MAX;
char buf[big_num];
int16_t bytes_received = 0;
int max_get = INT16_MAX + 1;
// BAD: 'bytes_received' is compared with a value of a wider type.
// 'bytes_received' overflows before reaching 'max_get',
// causing an infinite loop
while (bytes_received < max_get)
bytes_received += get_from_input(buf, bytes_received);
}
uint32_t bytes_received = 0;
// GOOD: 'bytes_received2' has a type at least as wide as 'max_get'
while (bytes_received < max_get) {
bytes_received += get_from_input(buf, bytes_received);
}
}
int getFromInput(char *buf, short pos) {
// write to buf
// ...
return 1;
}

View File

@@ -0,0 +1,7 @@
LPMALLOC pMalloc;
HRESULT hr = CoGetMalloc(1, &pMalloc);
if (!hr)
{
// code ...
}

View File

@@ -0,0 +1,26 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>This query indicates that an <code>HRESULT</code> is being cast to a boolean type or vice versa.</p>
<p>The typical success value (<code>S_OK</code>) of an <code>HRESULT</code> equals 0. However, 0 indicates failure for a boolean type.</p>
<p>Casting an <code>HRESULT</code> to a boolean type and then using it in a test expression will yield an incorrect result.</p>
</overview>
<recommendation>
<p>To check if a call that returns an HRESULT succeeded use the <code>FAILED</code> macro.</p>
</recommendation>
<example>
<p>In the following example, <code>HRESULT</code> is used in a test expression incorrectly as it may yield an incorrect result.</p>
<sample src="HResultBooleanConversion.cpp" />
<p>To fix this issue, use the <code>FAILED</code> macro in the test expression.</p>
</example>
<references>
</references>
</qhelp>

View File

@@ -0,0 +1,71 @@
/**
* @name Cast between semantically different integer types: HRESULT to/from a Boolean type
* @description Cast between semantically different integer types: HRESULT to/from a Boolean type.
* Boolean types indicate success by a non-zero value, whereas success (S_OK) in HRESULT is indicated by a value of 0.
* Casting an HRESULT to/from a Boolean type and then using it in a test expression will yield an incorrect result.
* @kind problem
* @id cpp/hresult-boolean-conversion
* @problem.severity error
* @precision high
* @tags security
* external/cwe/cwe-253
* external/microsoft/C6214
* external/microsoft/C6215
* external/microsoft/C6216
* external/microsoft/C6217
* external/microsoft/C6230
*/
import cpp
predicate isHresultBooleanConverted( Expr e1, Cast e2 )
{
exists ( Type t1, Type t2 |
t1 = e1.getType() and
t2 = e2.getType() and
((t1.hasName("bool") or t1.hasName("BOOL") or t1.hasName("_Bool")) and t2.hasName("HRESULT") or
(t2.hasName("bool") or t2.hasName("BOOL") or t2.hasName("_Bool")) and t1.hasName("HRESULT")
))
}
predicate isHresultBooleanConverted( Expr e1 )
{
exists( Cast e2 |
e2 = e1.getConversion() and
isHresultBooleanConverted(e1, e2)
)
}
from Expr e1, string msg
where exists
(
Cast e2 |
e2 = e1.getConversion() |
isHresultBooleanConverted( e1, e2 )
and if e2.isImplicit() then ( msg = "Implicit conversion from " + e1.getType().toString() + " to " + e2.getType().toString())
else ( msg = "Explicit conversion from " + e1.getType().toString() + " to " + e2.getType().toString())
)
or exists
(
ControlStructure ctls |
ctls.getControllingExpr() = e1
and e1.getType().(TypedefType).hasName("HRESULT")
and not isHresultBooleanConverted(e1)
and msg = "Direct usage of a type " + e1.getType().toString() + " as a conditional expression"
)
or
(
exists( BinaryLogicalOperation blop |
blop.getAnOperand() = e1 |
e1.getType().(TypedefType).hasName("HRESULT")
and msg = "Usage of a type " + e1.getType().toString() + " as an argument of a binary logical operation"
)
or exists
(
UnaryLogicalOperation ulop |
ulop.getAnOperand() = e1 |
e1.getType().(TypedefType).hasName("HRESULT")
and msg = "Usage of a type " + e1.getType().toString() + " as an argument of a unary logical operation"
)
and not isHresultBooleanConverted(e1)
)
select e1, msg

View File

@@ -10,33 +10,69 @@
* external/cwe/cwe-404
*/
import cpp
import Critical.NewDelete
// List pairs of functions that do resource acquisition/release
// Extend this to add custom function pairs. As written the query
// will only apply if the resource is the *return value* of the
// first call and a *parameter* to the second. Other cases should
// be handled differently.
predicate resourceManagementPair(string acquire, string release) {
(acquire = "fopen" and release = "fclose")
or
(acquire = "open" and release = "close")
or
(acquire = "socket" and release = "close")
/**
* An expression that acquires a resource, and the kind of resource that is acquired. The
* kind of a resource indicates which acquisition/release expressions can be paired.
*/
predicate acquireExpr(Expr acquire, string kind) {
exists(FunctionCall fc, Function f, string name |
fc = acquire and
f = fc.getTarget() and
name = f.getName() and
(
(
name = "fopen" and
kind = "file"
) or (
name = "open" and
kind = "file descriptor"
) or (
name = "socket" and
kind = "file descriptor"
)
)
) or (
allocExpr(acquire, kind)
)
}
// List functions that return malloc-allocated memory. Customize
// to list your own functions there
predicate mallocFunction(Function malloc) {
malloc.hasName("malloc") or malloc.hasName("calloc") or // Not realloc: doesn't acquire it, really
malloc.hasName("strdup")
}
private predicate isRelease(string release) {
resourceManagementPair(_, release) or
release = "free" or
release = "delete"
/**
* An expression that releases a resource, and the kind of resource that is released. The
* kind of a resource indicates which acquisition/release expressions can be paired.
*/
predicate releaseExpr(Expr release, Expr resource, string kind) {
exists(FunctionCall fc, Function f, string name |
fc = release and
f = fc.getTarget() and
name = f.getName() and
(
(
name = "fclose" and
resource = fc.getArgument(0) and
kind = "file"
) or (
name = "close" and
resource = fc.getArgument(0) and
kind = "file descriptor"
)
)
) or exists(string releaseKind |
freeExpr(release, resource, releaseKind) and
(
(
kind = "malloc" and
releaseKind = "free"
) or (
kind = "new" and
releaseKind = "delete"
) or (
kind = "new[]" and
releaseKind = "delete[]"
)
)
)
}
/**
@@ -52,35 +88,23 @@ Expr exprOrDereference(Expr e) {
* Holds if the expression `e` releases expression `released`, whether directly
* or via one or more function call(s).
*/
private predicate exprReleases(Expr e, Expr released, string releaseType) {
private predicate exprReleases(Expr e, Expr released, string kind) {
(
// `e` is a call to a release function and `released` is any argument
e.(FunctionCall).getTarget().getName() = releaseType and
isRelease(releaseType) and
e.(FunctionCall).getAnArgument() = released
) or (
// `e` is a call to `delete` and `released` is the target
e.(DeleteExpr).getExpr() = released and
releaseType = "delete"
) or (
// `e` is a call to `delete[]` and `released` is the target
e.(DeleteArrayExpr).getExpr() = released and
releaseType = "delete"
// `e` is a call to a release function and `released` is the released argument
releaseExpr(e, released, kind)
) or exists(Function f, int arg |
// `e` is a call to a function that releases one of it's parameters,
// and `released` is the corresponding argument
e.(FunctionCall).getTarget() = f and
e.(FunctionCall).getArgument(arg) = released and
exprReleases(_, exprOrDereference(f.getParameter(arg).getAnAccess()), releaseType)
) or exists(Function f, Expr innerThis |
exprReleases(_, exprOrDereference(f.getParameter(arg).getAnAccess()), kind)
) or exists(Function f, ThisExpr innerThis |
// `e` is a call to a method that releases `this`, and `released`
// is the object that is called
e.(FunctionCall).getTarget() = f and
e.(FunctionCall).getQualifier() = exprOrDereference(released) and
innerThis.getEnclosingFunction() = f and
exprReleases(_, innerThis, releaseType) and
innerThis instanceof ThisExpr and
releaseType = "delete"
exprReleases(_, innerThis, kind)
)
}
@@ -109,28 +133,17 @@ class Resource extends MemberVariable {
)
}
predicate acquisitionWithRequiredRelease(Expr acquire, string releaseName) {
acquire.(Assignment).getLValue() = this.getAnAccess() and
predicate acquisitionWithRequiredRelease(Assignment acquireAssign, string kind) {
// acquireAssign is an assignment to this resource
acquireAssign.(Assignment).getLValue() = this.getAnAccess() and
// Should be in this class, but *any* member method will do
this.inSameClass(acquire) and
this.inSameClass(acquireAssign) and
// Check that it is an acquisition function and return the corresponding free
(
exists(Function f | f = acquire.(Assignment).getRValue().(FunctionCall).getTarget() and
(resourceManagementPair(f.getName(), releaseName) or (mallocFunction(f) and (releaseName = "free" or releaseName = "delete")))
)
or
(acquire = this.getANew() and releaseName = "delete")
)
acquireExpr(acquireAssign.getRValue(), kind)
}
private Assignment getANew() {
result.getLValue() = this.getAnAccess() and
(result.getRValue() instanceof NewExpr or result.getRValue() instanceof NewArrayExpr) and
this.inSameClass(result)
}
Expr getAReleaseExpr(string releaseName) {
exprReleases(result, this.getAnAccess(), releaseName)
Expr getAReleaseExpr(string kind) {
exprReleases(result, this.getAnAccess(), kind)
}
}

View File

@@ -1,20 +1,20 @@
enum Shape_color { red, green, blue };
class Shape
{
public:
virtual void draw (Shape_color color = green) const;
...
}
class Circle : public Shape
{
public:
virtual void draw (Shape_color color = red) const;
...
}
void fun()
{
Shape* sp;
sp = new Circle;
sp->draw (); // Invokes Circle::draw(green) even though the default
} // parameter for Circle is red.
enum Shape_color { red, green, blue };
class Shape
{
public:
virtual void draw (Shape_color color = green) const;
...
}
class Circle : public Shape
{
public:
virtual void draw (Shape_color color = red) const;
...
}
void fun()
{
Shape* sp;
sp = new Circle;
sp->draw (); // Invokes Circle::draw(green) even though the default
} // parameter for Circle is red.

View File

@@ -1,16 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.2"?>
<plugin>
<extension point="com.semmle.plugin.qdt.ui.resources">
<name value="semmlecode-cpp-queries"/>
</extension>
<extension point="com.semmle.plugin.qdt.ui.resources">
<name value="com.semmle.code.cpp.library"/>
</extension>
<extension point="com.semmle.plugin.qdt.ui.resources">
<name value="com.semmle.code.cpp.dbscheme"/>
<path value="/semmlecode.cpp.dbscheme"/>
</extension>
</plugin>
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.2"?>
<plugin>
<extension point="com.semmle.plugin.qdt.ui.resources">
<name value="semmlecode-cpp-queries"/>
</extension>
<extension point="com.semmle.plugin.qdt.ui.resources">
<name value="com.semmle.code.cpp.library"/>
</extension>
<extension point="com.semmle.plugin.qdt.ui.resources">
<name value="com.semmle.code.cpp.dbscheme"/>
<path value="/semmlecode.cpp.dbscheme"/>
</extension>
</plugin>

View File

@@ -68,10 +68,9 @@ class Parameter extends LocalScopeVariable, @parameter {
*/
private VariableDeclarationEntry getAnEffectiveDeclarationEntry() {
if getFunction().isConstructedFrom(_)
then exists (Parameter prototype
| prototype = result.getVariable() and
prototype.getIndex() = getIndex() and
getFunction().isConstructedFrom(prototype.getFunction()))
then exists (Function prototypeInstantiation
| prototypeInstantiation.getParameter(getIndex()) = result.getVariable() and
getFunction().isConstructedFrom(prototypeInstantiation))
else result = getADeclarationEntry()
}

View File

@@ -1,23 +1,31 @@
import semmle.code.cpp.Type
/** Holds if `d` is a complete class named `name`. */
pragma[noinline]
private string getTopLevelClassName(@usertype c) {
isClass(c) and
usertypes(c, result, _) and
not namespacembrs(_, c) and // not in a namespace
not member(_, _, c) and // not in some structure
not class_instantiation(c, _) // not a template instantiation
}
/** Holds if `d` is a unique complete class named `name`. */
pragma[noinline]
private predicate existsCompleteWithName(string name, @usertype d) {
isClass(d) and
is_complete(d) and
usertypes(d, name, _)
name = getTopLevelClassName(d) and
strictcount(@usertype other | is_complete(other) and getTopLevelClassName(other) = name) = 1
}
/** Holds if `c` is an incomplete class named `name`. */
pragma[noinline]
private predicate existsIncompleteWithName(string name, @usertype c) {
isClass(c) and
not is_complete(c) and
usertypes(c, name, _)
name = getTopLevelClassName(c)
}
/**
* Holds if `c` is an incomplete class, and there exists a complete class `d`
* Holds if `c` is an incomplete class, and there exists a unique complete class `d`
* with the same name.
*/
private predicate hasCompleteTwin(@usertype c, @usertype d) {
@@ -30,10 +38,8 @@ private predicate hasCompleteTwin(@usertype c, @usertype d) {
import Cached
cached private module Cached {
/**
* If `c` is incomplete, and there exists a complete class with the same name,
* then the result is that complete class. Otherwise, the result is `c`. If
* multiple complete classes have the same name, this predicate may have
* multiple results.
* If `c` is incomplete, and there exists a unique complete class with the same name,
* then the result is that complete class. Otherwise, the result is `c`.
*/
cached @usertype resolveClass(@usertype c) {
hasCompleteTwin(c, result)

View File

@@ -270,7 +270,7 @@ newtype TTranslatedElement =
not ignoreExpr(initList) and
isFirstValueInitializedElementInRange(initList, elementIndex) and
elementCount =
getNextExplicitlyInitializedElementAfter(initList, elementIndex) -
getEndOfValueInitializedRange(initList, elementIndex) -
elementIndex
} or
// The initialization of a base class from within a constructor.
@@ -322,23 +322,30 @@ newtype TTranslatedElement =
/**
* Gets the index of the first explicitly initialized element in `initList`
* whose index is greater than `afterElementIndex`. If there are no remaining
* explicitly initialized elements in `initList`, the result is the total number
* of elements in the array being initialized.
* whose index is greater than `afterElementIndex`, where `afterElementIndex`
* is a first value-initialized element in a value-initialized range in
* `initList`. If there are no remaining explicitly initialized elements in
* `initList`, the result is the total number of elements in the array being
* initialized.
*/
private int getNextExplicitlyInitializedElementAfter(
ArrayAggregateLiteral initList, int afterElementIndex) {
if exists(int x |
x > afterElementIndex and
exists(initList.getElementExpr(x)))
then (
if exists(initList.getElementExpr(afterElementIndex + 1))
then result = afterElementIndex + 1
else result = getNextExplicitlyInitializedElementAfter(initList, afterElementIndex+1))
else
result = initList.getType().getUnspecifiedType().(ArrayType).getArraySize() and
// required for binding
initList.isInitialized(afterElementIndex)
private int getEndOfValueInitializedRange(ArrayAggregateLiteral initList, int afterElementIndex) {
result = getNextExplicitlyInitializedElementAfter(initList, afterElementIndex)
or
isFirstValueInitializedElementInRange(initList, afterElementIndex) and
not exists(getNextExplicitlyInitializedElementAfter(initList, afterElementIndex)) and
result = initList.getType().getUnspecifiedType().(ArrayType).getArraySize()
}
/**
* Gets the index of the first explicitly initialized element in `initList`
* whose index is greater than `afterElementIndex`, where `afterElementIndex`
* is a first value-initialized element in a value-initialized range in
* `initList`.
*/
private int getNextExplicitlyInitializedElementAfter(
ArrayAggregateLiteral initList, int afterElementIndex) {
isFirstValueInitializedElementInRange(initList, afterElementIndex) and
result = min(int i | exists(initList.getElementExpr(i)) and i > afterElementIndex)
}
/**

View File

@@ -1,137 +1,137 @@
import sys
import os.path
import glob
import re
import json
BEGIN_TEMPLATE = re.compile(r"^/\*template\s*$")
END_TEMPLATE = re.compile(r"^\*/\s*$")
def expand_template_params(args, param_arg_map):
'''Given a list of template arguments that may reference template parameters
of the current template, return a new list of template arguments with each
parameter use replaced with the appropriate fully-qualified argument for
that parameter.'''
result = []
for arg in args:
if arg in param_arg_map:
result.append(param_arg_map[arg])
else:
result.append(arg)
return result
def find_instantiation(module, args, templates):
'''Given a template module and a set of template arguments, find the module
name of the instantiation of that module with those arguments.'''
template = templates[module]
for instantiation in template["template_def"]["instantiations"]:
if instantiation["args"] == args:
return instantiation["name"]
return None
def instantiate_template(template, instantiation, root, templates):
'''Create a single instantiation of a template.'''
template_def = template["template_def"]
output_components = instantiation["name"].split(".")
output_path = root
for component in output_components:
output_path = os.path.join(output_path, component)
output_path = output_path + ".qll"
with open(output_path, "w") as output:
output.write(
"""
/*
* THIS FILE IS AUTOMATICALLY GENERATED FROM '%s'.
* DO NOT EDIT MANUALLY.
*/
""" % (template["name"].replace(".", "/") + ".qllt")
)
param_arg_map = {}
for param_index in range(len(template_def["params"])):
param = template_def["params"][param_index]
arg = instantiation["args"][param_index]
output.write("private import %s as %s // Template parameter\n" % (arg, param))
param_arg_map[param] = arg
for import_record in template_def["imports"]:
if "access" in import_record:
output.write(import_record["access"] + " ")
imported_module = find_instantiation(import_record["module"],
expand_template_params(import_record["args"], param_arg_map), templates)
output.write("import %s // %s<%s>\n" %
(
imported_module,
import_record["module"],
", ".join(import_record["args"])
)
)
output.writelines(template_def["body_lines"])
def generate_instantiations(template, root, templates):
'''Create a .qll source file for each instantiation of the specified template.'''
template_def = template["template_def"]
if "instantiations" in template_def:
for instantiation in template_def["instantiations"]:
instantiate_template(template, instantiation, root, templates)
def read_template(template_path, module_name):
'''Read a .qllt template file from template_path, using module_name as the
fully qualified name of the module.'''
with open(template_path) as input:
in_template = False
template_text = ""
template_def = None
body_lines = []
for line in iter(input):
if in_template:
if END_TEMPLATE.match(line):
template_def = json.loads(template_text)
in_template = False
else:
template_text += line
else:
if BEGIN_TEMPLATE.match(line) and not template_def:
in_template = True
else:
body_lines.append(line)
if template_def:
template_def["body_lines"] = body_lines
result = { "name": module_name }
if template_def:
result["template_def"] = template_def
return result
def module_name_from_path_impl(path):
(head, tail) = os.path.split(path)
if head == "":
return tail
else:
return module_name_from_path(head) + "." + tail
def module_name_from_path(path):
'''Compute the fully qualified name of a module from the path of its .qll[t]
file. The path should be relative to the library root.'''
(module_root, ext) = os.path.splitext(path)
return module_name_from_path_impl(module_root)
def main():
templates = {}
root = sys.argv[1]
for template_path in glob.glob(os.path.join(root, "**\\*.qllt"), recursive = True):
print(template_path)
module_name = module_name_from_path(os.path.relpath(template_path, root))
print(module_name)
template = read_template(template_path, module_name)
templates[template["name"]] = template
for name, template in templates.items():
if "template_def" in template:
generate_instantiations(template, root, templates)
if __name__ == "__main__":
main()
import sys
import os.path
import glob
import re
import json
BEGIN_TEMPLATE = re.compile(r"^/\*template\s*$")
END_TEMPLATE = re.compile(r"^\*/\s*$")
def expand_template_params(args, param_arg_map):
'''Given a list of template arguments that may reference template parameters
of the current template, return a new list of template arguments with each
parameter use replaced with the appropriate fully-qualified argument for
that parameter.'''
result = []
for arg in args:
if arg in param_arg_map:
result.append(param_arg_map[arg])
else:
result.append(arg)
return result
def find_instantiation(module, args, templates):
'''Given a template module and a set of template arguments, find the module
name of the instantiation of that module with those arguments.'''
template = templates[module]
for instantiation in template["template_def"]["instantiations"]:
if instantiation["args"] == args:
return instantiation["name"]
return None
def instantiate_template(template, instantiation, root, templates):
'''Create a single instantiation of a template.'''
template_def = template["template_def"]
output_components = instantiation["name"].split(".")
output_path = root
for component in output_components:
output_path = os.path.join(output_path, component)
output_path = output_path + ".qll"
with open(output_path, "w") as output:
output.write(
"""
/*
* THIS FILE IS AUTOMATICALLY GENERATED FROM '%s'.
* DO NOT EDIT MANUALLY.
*/
""" % (template["name"].replace(".", "/") + ".qllt")
)
param_arg_map = {}
for param_index in range(len(template_def["params"])):
param = template_def["params"][param_index]
arg = instantiation["args"][param_index]
output.write("private import %s as %s // Template parameter\n" % (arg, param))
param_arg_map[param] = arg
for import_record in template_def["imports"]:
if "access" in import_record:
output.write(import_record["access"] + " ")
imported_module = find_instantiation(import_record["module"],
expand_template_params(import_record["args"], param_arg_map), templates)
output.write("import %s // %s<%s>\n" %
(
imported_module,
import_record["module"],
", ".join(import_record["args"])
)
)
output.writelines(template_def["body_lines"])
def generate_instantiations(template, root, templates):
'''Create a .qll source file for each instantiation of the specified template.'''
template_def = template["template_def"]
if "instantiations" in template_def:
for instantiation in template_def["instantiations"]:
instantiate_template(template, instantiation, root, templates)
def read_template(template_path, module_name):
'''Read a .qllt template file from template_path, using module_name as the
fully qualified name of the module.'''
with open(template_path) as input:
in_template = False
template_text = ""
template_def = None
body_lines = []
for line in iter(input):
if in_template:
if END_TEMPLATE.match(line):
template_def = json.loads(template_text)
in_template = False
else:
template_text += line
else:
if BEGIN_TEMPLATE.match(line) and not template_def:
in_template = True
else:
body_lines.append(line)
if template_def:
template_def["body_lines"] = body_lines
result = { "name": module_name }
if template_def:
result["template_def"] = template_def
return result
def module_name_from_path_impl(path):
(head, tail) = os.path.split(path)
if head == "":
return tail
else:
return module_name_from_path(head) + "." + tail
def module_name_from_path(path):
'''Compute the fully qualified name of a module from the path of its .qll[t]
file. The path should be relative to the library root.'''
(module_root, ext) = os.path.splitext(path)
return module_name_from_path_impl(module_root)
def main():
templates = {}
root = sys.argv[1]
for template_path in glob.glob(os.path.join(root, "**\\*.qllt"), recursive = True):
print(template_path)
module_name = module_name_from_path(os.path.relpath(template_path, root))
print(module_name)
template = read_template(template_path, module_name)
templates[template["name"]] = template
for name, template in templates.items():
if "template_def" in template:
generate_instantiations(template, root, templates)
if __name__ == "__main__":
main()

View File

@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>semmlecode-cpp-tests</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
</buildSpec>
<natures>
<nature>com.semmle.plugin.qdt.core.qlnature</nature>
</natures>
</projectDescription>
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>semmlecode-cpp-tests</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
</buildSpec>
<natures>
<nature>com.semmle.plugin.qdt.core.qlnature</nature>
</natures>
</projectDescription>

View File

@@ -1,5 +1,5 @@
// common.h
#include "nameclash.h"
// common.h
#include "nameclash.h"
static int myArray[sizeof(MYTYPE)];

View File

@@ -1,3 +1,3 @@
// defines_issue.h
// defines_issue.h
#include DEFINED_HEADER

View File

@@ -1,7 +1,7 @@
// semmle-extractor-options: -I${testdir}/subdir2
// main2.cpp
#include "common.h"
#define DEFINED_HEADER "define2.h"
#include "defines_issue.h"
// semmle-extractor-options: -I${testdir}/subdir2
// main2.cpp
#include "common.h"
#define DEFINED_HEADER "define2.h"
#include "defines_issue.h"

View File

@@ -1,3 +1,3 @@
// nameclash.h
// nameclash.h
#include_next "nameclash.h"

View File

@@ -1,3 +1,3 @@
// subdir1/nameclash.h
// subdir1/nameclash.h
typedef long long int MYTYPE;

View File

@@ -1,3 +1,3 @@
// subdir2/nameclash.h
// subdir2/nameclash.h
typedef char MYTYPE;

View File

@@ -1,111 +1,111 @@
// semmle-extractor-options: -std=c++17
typedef unsigned long size_t;
namespace std {
enum class align_val_t : size_t {};
}
void* operator new(size_t, float);
void* operator new[](size_t, float);
void* operator new(size_t, std::align_val_t, float);
void* operator new[](size_t, std::align_val_t, float);
void operator delete(void*, float);
void operator delete[](void*, float);
void operator delete(void*, std::align_val_t, float);
void operator delete[](void*, std::align_val_t, float);
struct String {
String();
String(const String&);
String(String&&);
String(const char*);
~String();
String& operator=(const String&);
String& operator=(String&&);
const char* c_str() const;
private:
const char* p;
};
struct SizedDealloc {
char a[32];
void* operator new(size_t);
void* operator new[](size_t);
void operator delete(void*, size_t);
void operator delete[](void*, size_t);
};
struct alignas(128) Overaligned {
char a[256];
};
struct PolymorphicBase {
virtual ~PolymorphicBase();
};
void OperatorNew() {
new int; // No constructor
new(1.0f) int; // Placement new, no constructor
new int(); // Zero-init
new String(); // Constructor
new(1.0f) String("hello"); // Placement new, constructor with args
new Overaligned; // Aligned new
new(1.0f) Overaligned(); // Placement aligned new
}
void OperatorDelete() {
delete static_cast<int*>(nullptr); // No destructor
delete static_cast<String*>(nullptr); // Non-virtual destructor, with size.
delete static_cast<SizedDealloc*>(nullptr); // No destructor, with size.
delete static_cast<Overaligned*>(nullptr); // No destructor, with size and alignment.
delete static_cast<PolymorphicBase*>(nullptr); // Virtual destructor
delete static_cast<const String*>(nullptr); // Pointer to const
}
void OperatorNewArray(int n) {
new int[n]; // No constructor
new(1.0f) int[n]; // Placement new, no constructor
new String[n]; // Constructor
new Overaligned[n]; // Aligned new
new String[10]; // Constant size
}
int* const GetPointer();
void OperatorDeleteArray() {
delete[] static_cast<int*>(nullptr); // No destructor
delete[] static_cast<String*>(nullptr); // Non-virtual destructor, with size.
delete[] static_cast<SizedDealloc*>(nullptr); // No destructor, with size.
delete[] static_cast<Overaligned*>(nullptr); // No destructor, with size and alignment.
delete[] static_cast<PolymorphicBase*>(nullptr); // Virtual destructor
delete[] GetPointer();
}
struct FailedInit {
FailedInit();
~FailedInit();
void* operator new(size_t); // Non-placement
void* operator new[](size_t); // Non-placement
void operator delete(void*, size_t); // Sized deallocation
void operator delete[](void*, size_t); // Sized deallocation
};
struct alignas(128) FailedInitOveraligned {
FailedInitOveraligned();
~FailedInitOveraligned();
void* operator new(size_t, std::align_val_t, float); // Aligned placement
void* operator new[](size_t, std::align_val_t, float); // Aligned placement
void operator delete(void*, std::align_val_t, float); // Aligned placement
void operator delete[](void*, std::align_val_t, float); // Aligned placement
};
void TestFailedInit(int n) {
new FailedInit();
new FailedInit[n];
new(1.0f) FailedInitOveraligned();
new(1.0f) FailedInitOveraligned[10];
}
// semmle-extractor-options: -std=c++17
typedef unsigned long size_t;
namespace std {
enum class align_val_t : size_t {};
}
void* operator new(size_t, float);
void* operator new[](size_t, float);
void* operator new(size_t, std::align_val_t, float);
void* operator new[](size_t, std::align_val_t, float);
void operator delete(void*, float);
void operator delete[](void*, float);
void operator delete(void*, std::align_val_t, float);
void operator delete[](void*, std::align_val_t, float);
struct String {
String();
String(const String&);
String(String&&);
String(const char*);
~String();
String& operator=(const String&);
String& operator=(String&&);
const char* c_str() const;
private:
const char* p;
};
struct SizedDealloc {
char a[32];
void* operator new(size_t);
void* operator new[](size_t);
void operator delete(void*, size_t);
void operator delete[](void*, size_t);
};
struct alignas(128) Overaligned {
char a[256];
};
struct PolymorphicBase {
virtual ~PolymorphicBase();
};
void OperatorNew() {
new int; // No constructor
new(1.0f) int; // Placement new, no constructor
new int(); // Zero-init
new String(); // Constructor
new(1.0f) String("hello"); // Placement new, constructor with args
new Overaligned; // Aligned new
new(1.0f) Overaligned(); // Placement aligned new
}
void OperatorDelete() {
delete static_cast<int*>(nullptr); // No destructor
delete static_cast<String*>(nullptr); // Non-virtual destructor, with size.
delete static_cast<SizedDealloc*>(nullptr); // No destructor, with size.
delete static_cast<Overaligned*>(nullptr); // No destructor, with size and alignment.
delete static_cast<PolymorphicBase*>(nullptr); // Virtual destructor
delete static_cast<const String*>(nullptr); // Pointer to const
}
void OperatorNewArray(int n) {
new int[n]; // No constructor
new(1.0f) int[n]; // Placement new, no constructor
new String[n]; // Constructor
new Overaligned[n]; // Aligned new
new String[10]; // Constant size
}
int* const GetPointer();
void OperatorDeleteArray() {
delete[] static_cast<int*>(nullptr); // No destructor
delete[] static_cast<String*>(nullptr); // Non-virtual destructor, with size.
delete[] static_cast<SizedDealloc*>(nullptr); // No destructor, with size.
delete[] static_cast<Overaligned*>(nullptr); // No destructor, with size and alignment.
delete[] static_cast<PolymorphicBase*>(nullptr); // Virtual destructor
delete[] GetPointer();
}
struct FailedInit {
FailedInit();
~FailedInit();
void* operator new(size_t); // Non-placement
void* operator new[](size_t); // Non-placement
void operator delete(void*, size_t); // Sized deallocation
void operator delete[](void*, size_t); // Sized deallocation
};
struct alignas(128) FailedInitOveraligned {
FailedInitOveraligned();
~FailedInitOveraligned();
void* operator new(size_t, std::align_val_t, float); // Aligned placement
void* operator new[](size_t, std::align_val_t, float); // Aligned placement
void operator delete(void*, std::align_val_t, float); // Aligned placement
void operator delete[](void*, std::align_val_t, float); // Aligned placement
};
void TestFailedInit(int n) {
new FailedInit();
new FailedInit[n];
new(1.0f) FailedInitOveraligned();
new(1.0f) FailedInitOveraligned[10];
}

View File

@@ -1,8 +1,8 @@
#include "calls1.h"
void swap(int* p, int* q)
{
int t = *p;
*p = *q;
*q = t;
}
#include "calls1.h"
void swap(int* p, int* q)
{
int t = *p;
*p = *q;
*q = t;
}

View File

@@ -1,2 +1,2 @@
extern void swap(int*, int*);
extern void swap(int*, int*);

View File

@@ -1,20 +1,20 @@
#include "calls1.h"
void g() {
int x = 2;
int y = 4;
swap(&x,&y);
}
void negate(int& c) { c = -c; }
template<class Iter, class Fct> void compute(Iter b, Fct f)
{
f(b);
}
void f(int aa)
{
compute(aa, negate);
}
#include "calls1.h"
void g() {
int x = 2;
int y = 4;
swap(&x,&y);
}
void negate(int& c) { c = -c; }
template<class Iter, class Fct> void compute(Iter b, Fct f)
{
f(b);
}
void f(int aa)
{
compute(aa, negate);
}

View File

@@ -1,41 +1,41 @@
class A {
};
class B {
};
class C: A, B {
};
class D: C {
class E;
};
class D::E {
class F;
class G {
public:
/* Non-trivial constructor and destructor */
G() { 0; }
~G() { 0; }
};
};
class D::E::F: D::E::G {
/* Should have generated constructor and destructor, because of D::E::G */
static int m() {
D::E::F def; /* Should trigger creation of D::E::F's generated constructor and destructor. */
}
};
// semmle-extractor-options: --microsoft
class A {
};
class B {
};
class C: A, B {
};
class D: C {
class E;
};
class D::E {
class F;
class G {
public:
/* Non-trivial constructor and destructor */
G() { 0; }
~G() { 0; }
};
};
class D::E::F: D::E::G {
/* Should have generated constructor and destructor, because of D::E::G */
static int m() {
D::E::F def; /* Should trigger creation of D::E::F's generated constructor and destructor. */
}
};
// semmle-extractor-options: --microsoft

View File

@@ -1,84 +1,84 @@
struct Base {
int b1;
float b1f;
};
struct SingleInheritance : Base {
int si1;
float si1f;
};
struct Base2 {
int b2;
float b2f;
};
struct MultipleInheritance : Base, Base2 {
int mi1;
float mi1f;
};
struct DeepInheritance : MultipleInheritance, SingleInheritance {
int di1;
float di1f;
};
struct VirtualInheritance1 : virtual Base {
int vi1;
float vi1f;
};
struct VirtualInheritance2 : VirtualInheritance1, virtual Base, virtual Base2 {
int vi2;
float vi2f;
};
struct EffectivelyVirtual : virtual SingleInheritance, MultipleInheritance {
int ev1;
float ev1f;
};
struct PolymorphicBase {
virtual ~PolymorphicBase();
int pb1;
float pb1f;
};
struct InheritsVTable : PolymorphicBase {
int iv1;
float iv1f;
};
struct IntroducesVTable : Base {
virtual ~IntroducesVTable();
int iv2;
float iv2f;
};
struct Left : virtual Base {
int l1;
float l1f;
};
struct Right : virtual Base {
int r1;
float r1f;
};
struct Bottom : Left, Right {
int b1;
float b1f;
};
struct DeepSingleInheritance : SingleInheritance {
int dsi1;
float dsi1f;
};
struct Incomplete;
Incomplete* p;
template<typename T>
struct TemplateClass : Base
{
};
struct Base {
int b1;
float b1f;
};
struct SingleInheritance : Base {
int si1;
float si1f;
};
struct Base2 {
int b2;
float b2f;
};
struct MultipleInheritance : Base, Base2 {
int mi1;
float mi1f;
};
struct DeepInheritance : MultipleInheritance, SingleInheritance {
int di1;
float di1f;
};
struct VirtualInheritance1 : virtual Base {
int vi1;
float vi1f;
};
struct VirtualInheritance2 : VirtualInheritance1, virtual Base, virtual Base2 {
int vi2;
float vi2f;
};
struct EffectivelyVirtual : virtual SingleInheritance, MultipleInheritance {
int ev1;
float ev1f;
};
struct PolymorphicBase {
virtual ~PolymorphicBase();
int pb1;
float pb1f;
};
struct InheritsVTable : PolymorphicBase {
int iv1;
float iv1f;
};
struct IntroducesVTable : Base {
virtual ~IntroducesVTable();
int iv2;
float iv2f;
};
struct Left : virtual Base {
int l1;
float l1f;
};
struct Right : virtual Base {
int r1;
float r1f;
};
struct Bottom : Left, Right {
int b1;
float b1f;
};
struct DeepSingleInheritance : SingleInheritance {
int dsi1;
float dsi1f;
};
struct Incomplete;
Incomplete* p;
template<typename T>
struct TemplateClass : Base
{
};

View File

@@ -1,102 +1,102 @@
// GOOD = at least one iteration
// BAD = possibly no iterations
void test1() {
for (int i = 0; i < 10; i++) { // GOOD
}
}
void test2() {
for (int i = 0, j = 1; i + j < 10; i++) { // GOOD
}
}
void test3() {
int j = 2;
for (int i = j = 1; i + j < 10; i++) { // GOOD
}
}
void test4() {
int i = 2, j = 3;
for (i = j = 1; i + j < 10; i++) { // GOOD
}
}
void test5() {
int i, k;
for (i = k = 0; i < 10; i++) { // GOOD
}
}
void test6() {
int i = 0;
for (; i < 10; i++) { // GOOD
i = 1;
}
}
void test7() {
int i = 0;
for (i = 1; i < 10; i++) { // GOOD
i = 1;
}
}
void test8() {
int i = 0;
i = 1;
for (; i < 10; i++) { // GOOD (NOT REPORTED)
}
}
void test9() {
bool done = false;
for (; !done; ) { // GOOD
done = true;
}
}
void test10(int i) {
bool done = false;
for (; i++; i < 10) { // BAD
for (; !done; ) { // BAD
done = true;
}
}
}
void test11(int i) {
for (; i++; i < 10) { // BAD
bool done = false;
for (; !done; ) { // GOOD
done = true;
}
}
}
void test12(int max) {
int i, k;
int max_index = 0;
for (i = k = 0; i < max; i++) { // BAD
max_index = i;
}
for (i = 0; i <= max_index; i++) { // BAD
}
}
void test13() {
int i;
for (i = 1; i > 0; ) { // GOOD
&i;
}
}
void test14(bool b) {
int i = 1;
while (b) {
for (; i > 0; ) { // BAD
&i;
}
}
// GOOD = at least one iteration
// BAD = possibly no iterations
void test1() {
for (int i = 0; i < 10; i++) { // GOOD
}
}
void test2() {
for (int i = 0, j = 1; i + j < 10; i++) { // GOOD
}
}
void test3() {
int j = 2;
for (int i = j = 1; i + j < 10; i++) { // GOOD
}
}
void test4() {
int i = 2, j = 3;
for (i = j = 1; i + j < 10; i++) { // GOOD
}
}
void test5() {
int i, k;
for (i = k = 0; i < 10; i++) { // GOOD
}
}
void test6() {
int i = 0;
for (; i < 10; i++) { // GOOD
i = 1;
}
}
void test7() {
int i = 0;
for (i = 1; i < 10; i++) { // GOOD
i = 1;
}
}
void test8() {
int i = 0;
i = 1;
for (; i < 10; i++) { // GOOD (NOT REPORTED)
}
}
void test9() {
bool done = false;
for (; !done; ) { // GOOD
done = true;
}
}
void test10(int i) {
bool done = false;
for (; i++; i < 10) { // BAD
for (; !done; ) { // BAD
done = true;
}
}
}
void test11(int i) {
for (; i++; i < 10) { // BAD
bool done = false;
for (; !done; ) { // GOOD
done = true;
}
}
}
void test12(int max) {
int i, k;
int max_index = 0;
for (i = k = 0; i < max; i++) { // BAD
max_index = i;
}
for (i = 0; i <= max_index; i++) { // BAD
}
}
void test13() {
int i;
for (i = 1; i > 0; ) { // GOOD
&i;
}
}
void test14(bool b) {
int i = 1;
while (b) {
for (; i > 0; ) { // BAD
&i;
}
}
}

View File

@@ -1,64 +1,64 @@
// GOOD = at least one iteration
// BAD = possibly no iterations
void test1() {
bool done = false;
while (!done) { // GOOD
done = true;
}
}
void test2() {
bool done = true;
done = false;
while (!done) { // GOOD (NOT REPORTED)
done = true;
}
}
void test3(int i) {
bool done = false;
for (; i++; i < 10) {
while (!done) { // BAD
done = true;
}
}
}
void test4(int i) {
for (; i++; i < 10) {
bool done = false;
while (!done) { // GOOD
done = true;
}
}
}
void test5(int max) {
int i = 0, k = 0;
int max_index = 0;
while (i < max) { // BAD
max_index = i;
i++;
}
i = 0;
while (i <= max_index) { // BAD
i++;
}
}
void test6() {
int i = 1;
while (i > 0) { // GOOD
&i;
}
}
void test7(bool b) {
int i = 1;
while (b) { // BAD
while (i > 0) { // BAD
&i;
}
}
// GOOD = at least one iteration
// BAD = possibly no iterations
void test1() {
bool done = false;
while (!done) { // GOOD
done = true;
}
}
void test2() {
bool done = true;
done = false;
while (!done) { // GOOD (NOT REPORTED)
done = true;
}
}
void test3(int i) {
bool done = false;
for (; i++; i < 10) {
while (!done) { // BAD
done = true;
}
}
}
void test4(int i) {
for (; i++; i < 10) {
bool done = false;
while (!done) { // GOOD
done = true;
}
}
}
void test5(int max) {
int i = 0, k = 0;
int max_index = 0;
while (i < max) { // BAD
max_index = i;
i++;
}
i = 0;
while (i <= max_index) { // BAD
i++;
}
}
void test6() {
int i = 1;
while (i > 0) { // GOOD
&i;
}
}
void test7(bool b) {
int i = 1;
while (b) { // BAD
while (i > 0) { // BAD
&i;
}
}
}

View File

@@ -1,250 +1,250 @@
typedef unsigned short ushort;
enum E {
E0,
E1
};
enum class EC : int {
EC0,
EC1
};
void ArithmeticConversions() {
char c = 0;
unsigned char uc = 0;
short s = 0;
unsigned short us = 0;
int i = 0;
unsigned int ui = 0;
long l = 0;
unsigned long ul = 0;
long long ll = 0;
unsigned long long ull = 0;
float f = 0;
double d = 0;
wchar_t wc = 0;
E e{};
EC ec{};
c = uc;
c = (char)uc;
c = char(uc);
c = static_cast<char>(uc);
i = s;
i = (int)s;
i = int(s);
i = static_cast<int>(s);
us = i;
us = (unsigned short)i;
us = ushort(i);
us = static_cast<unsigned short>(i);
i = d;
i = (int)d;
i = int(d);
i = static_cast<int>(d);
f = c;
f = (float)c;
f = float(c);
f = static_cast<float>(c);
f = d;
f = (float)d;
f = float(d);
f = static_cast<float>(d);
d = f;
d = (double)f;
d = double(f);
d = static_cast<double>(f);
i = E0;
i = e;
i = static_cast<int>(EC::EC0);
i = static_cast<int>(ec);
e = static_cast<E>(i);
ec = static_cast<EC>(i);
}
struct S {
int x;
double y;
};
void ConversionsToBool() {
bool b = 0;
int i = 0;
double d = 0;
void* p = nullptr;
int S::* pmd = nullptr;
if (b) {
}
else if ((bool)b) {
}
else if (i) {
}
else if (d) {
}
else if (p) {
}
else if (pmd) {
}
}
struct Base {
int b1;
void BaseMethod();
};
struct Middle : Base {
int m1;
void MiddleMethod();
};
struct Derived : Middle {
int d1;
void DerivedMethod();
};
void HierarchyCasts() {
Base b;
Middle m;
Derived d;
Base* pb = &b;
Middle* pm = &m;
Derived* pd = &d;
b = m;
b = (Base)m;
b = static_cast<Base>(m);
pb = pm;
pb = (Base*)pm;
pb = static_cast<Base*>(pm);
pb = reinterpret_cast<Base*>(pm);
m = (Middle&)b;
m = static_cast<Middle&>(b);
pm = (Middle*)pb;
pm = static_cast<Middle*>(pb);
pm = reinterpret_cast<Middle*>(pb);
b = d;
b = (Base)d;
b = static_cast<Base>(d);
pb = pd;
pb = (Base*)pd;
pb = static_cast<Base*>(pd);
pb = reinterpret_cast<Base*>(pd);
d = (Derived&)b;
d = static_cast<Derived&>(b);
pd = (Derived*)pb;
pd = static_cast<Derived*>(pb);
pd = reinterpret_cast<Derived*>(pb);
}
void PTMCasts() {
int Base::* pb = &Base::b1;
void (Base::* pmfb)() = &Base::BaseMethod;
int Middle::* pm = &Middle::m1;
void (Middle::* pmfm)() = &Middle::MiddleMethod;
int Derived::* pd = &Derived::d1;
void (Derived::* pmfd)() = &Derived::DerivedMethod;
pb = (int Base::*)pm;
pmfb = (void (Base::*)())pmfm;
pb = static_cast<int Base::*>(pm);
pmfb = static_cast<void (Base::*)()>(pmfm);
pm = pb;
pmfm = pmfb;
pm = (int Middle::*)pb;
pmfm = (void (Middle::*)())pmfb;
pm = static_cast<int Middle::*>(pb);
pmfm = static_cast<void (Middle::*)()>(pmfb);
pb = (int Base::*)pd;
pmfb = (void (Base::*)())pmfd;
pb = static_cast<int Base::*>(pd);
pmfb = static_cast<void (Base::*)()>(pmfd);
pd = pb;
pmfd = pmfb;
pd = (int Derived::*)pb;
pmfd = (void (Derived::*)())pmfb;
pd = static_cast<int Derived::*>(pb);
pmfd = static_cast<void (Derived::*)()>(pmfb);
}
struct String {
String();
String(const String&);
~String();
};
void Adjust() {
const String& s1 = String(); // prvalue adjustment
Base b;
Derived d;
const Base& rb = true ? b : d; // glvalue adjustment
const Base& r = (Base&)s1;
}
void QualificationConversions() {
const int* pc = nullptr;
const volatile int* pcv = nullptr;
pcv = pc;
pc = const_cast<const int*>(pcv);
}
void PointerIntegralConversions() {
void* p = nullptr;
long n = (long)p;
n = reinterpret_cast<long>(p);
p = (void*)n;
p = reinterpret_cast<void*>(n);
}
struct PolymorphicBase {
virtual ~PolymorphicBase();
};
struct PolymorphicDerived : PolymorphicBase {
};
void DynamicCast() {
PolymorphicBase b;
PolymorphicDerived d;
PolymorphicBase* pb = &b;
PolymorphicDerived* pd = &d;
// These two casts were previously represented as BaseClassCasts because they were resolved at compile time, but the front-end no longer performs this optimization.
pb = dynamic_cast<PolymorphicBase*>(pd);
PolymorphicBase& rb = dynamic_cast<PolymorphicBase&>(d);
pd = dynamic_cast<PolymorphicDerived*>(pb);
PolymorphicDerived& rd = dynamic_cast<PolymorphicDerived&>(b);
}
void FuncPtrConversions(int(*pfn)(int), void* p) {
p = (void*)pfn;
pfn = (int(*)(int))p;
}
int Func();
void ConversionsToVoid() {
int x;
(void)x;
static_cast<void>(x);
(void)Func();
static_cast<void>(Func());
(void)1;
static_cast<void>(1);
}
typedef unsigned short ushort;
enum E {
E0,
E1
};
enum class EC : int {
EC0,
EC1
};
void ArithmeticConversions() {
char c = 0;
unsigned char uc = 0;
short s = 0;
unsigned short us = 0;
int i = 0;
unsigned int ui = 0;
long l = 0;
unsigned long ul = 0;
long long ll = 0;
unsigned long long ull = 0;
float f = 0;
double d = 0;
wchar_t wc = 0;
E e{};
EC ec{};
c = uc;
c = (char)uc;
c = char(uc);
c = static_cast<char>(uc);
i = s;
i = (int)s;
i = int(s);
i = static_cast<int>(s);
us = i;
us = (unsigned short)i;
us = ushort(i);
us = static_cast<unsigned short>(i);
i = d;
i = (int)d;
i = int(d);
i = static_cast<int>(d);
f = c;
f = (float)c;
f = float(c);
f = static_cast<float>(c);
f = d;
f = (float)d;
f = float(d);
f = static_cast<float>(d);
d = f;
d = (double)f;
d = double(f);
d = static_cast<double>(f);
i = E0;
i = e;
i = static_cast<int>(EC::EC0);
i = static_cast<int>(ec);
e = static_cast<E>(i);
ec = static_cast<EC>(i);
}
struct S {
int x;
double y;
};
void ConversionsToBool() {
bool b = 0;
int i = 0;
double d = 0;
void* p = nullptr;
int S::* pmd = nullptr;
if (b) {
}
else if ((bool)b) {
}
else if (i) {
}
else if (d) {
}
else if (p) {
}
else if (pmd) {
}
}
struct Base {
int b1;
void BaseMethod();
};
struct Middle : Base {
int m1;
void MiddleMethod();
};
struct Derived : Middle {
int d1;
void DerivedMethod();
};
void HierarchyCasts() {
Base b;
Middle m;
Derived d;
Base* pb = &b;
Middle* pm = &m;
Derived* pd = &d;
b = m;
b = (Base)m;
b = static_cast<Base>(m);
pb = pm;
pb = (Base*)pm;
pb = static_cast<Base*>(pm);
pb = reinterpret_cast<Base*>(pm);
m = (Middle&)b;
m = static_cast<Middle&>(b);
pm = (Middle*)pb;
pm = static_cast<Middle*>(pb);
pm = reinterpret_cast<Middle*>(pb);
b = d;
b = (Base)d;
b = static_cast<Base>(d);
pb = pd;
pb = (Base*)pd;
pb = static_cast<Base*>(pd);
pb = reinterpret_cast<Base*>(pd);
d = (Derived&)b;
d = static_cast<Derived&>(b);
pd = (Derived*)pb;
pd = static_cast<Derived*>(pb);
pd = reinterpret_cast<Derived*>(pb);
}
void PTMCasts() {
int Base::* pb = &Base::b1;
void (Base::* pmfb)() = &Base::BaseMethod;
int Middle::* pm = &Middle::m1;
void (Middle::* pmfm)() = &Middle::MiddleMethod;
int Derived::* pd = &Derived::d1;
void (Derived::* pmfd)() = &Derived::DerivedMethod;
pb = (int Base::*)pm;
pmfb = (void (Base::*)())pmfm;
pb = static_cast<int Base::*>(pm);
pmfb = static_cast<void (Base::*)()>(pmfm);
pm = pb;
pmfm = pmfb;
pm = (int Middle::*)pb;
pmfm = (void (Middle::*)())pmfb;
pm = static_cast<int Middle::*>(pb);
pmfm = static_cast<void (Middle::*)()>(pmfb);
pb = (int Base::*)pd;
pmfb = (void (Base::*)())pmfd;
pb = static_cast<int Base::*>(pd);
pmfb = static_cast<void (Base::*)()>(pmfd);
pd = pb;
pmfd = pmfb;
pd = (int Derived::*)pb;
pmfd = (void (Derived::*)())pmfb;
pd = static_cast<int Derived::*>(pb);
pmfd = static_cast<void (Derived::*)()>(pmfb);
}
struct String {
String();
String(const String&);
~String();
};
void Adjust() {
const String& s1 = String(); // prvalue adjustment
Base b;
Derived d;
const Base& rb = true ? b : d; // glvalue adjustment
const Base& r = (Base&)s1;
}
void QualificationConversions() {
const int* pc = nullptr;
const volatile int* pcv = nullptr;
pcv = pc;
pc = const_cast<const int*>(pcv);
}
void PointerIntegralConversions() {
void* p = nullptr;
long n = (long)p;
n = reinterpret_cast<long>(p);
p = (void*)n;
p = reinterpret_cast<void*>(n);
}
struct PolymorphicBase {
virtual ~PolymorphicBase();
};
struct PolymorphicDerived : PolymorphicBase {
};
void DynamicCast() {
PolymorphicBase b;
PolymorphicDerived d;
PolymorphicBase* pb = &b;
PolymorphicDerived* pd = &d;
// These two casts were previously represented as BaseClassCasts because they were resolved at compile time, but the front-end no longer performs this optimization.
pb = dynamic_cast<PolymorphicBase*>(pd);
PolymorphicBase& rb = dynamic_cast<PolymorphicBase&>(d);
pd = dynamic_cast<PolymorphicDerived*>(pb);
PolymorphicDerived& rd = dynamic_cast<PolymorphicDerived&>(b);
}
void FuncPtrConversions(int(*pfn)(int), void* p) {
p = (void*)pfn;
pfn = (int(*)(int))p;
}
int Func();
void ConversionsToVoid() {
int x;
(void)x;
static_cast<void>(x);
(void)Func();
static_cast<void>(Func());
(void)1;
static_cast<void>(1);
}

View File

@@ -45,53 +45,53 @@ private:
int xs[4];
};
struct A {
A(int);
};
struct B {
B(int);
};
struct C {
C(int);
};
struct MultipleBases : A, B, C {
int x;
int y;
int z;
MultipleBases() :
z(5),
B(1),
x(3),
A(0),
C(2),
y(4) {
}
};
struct VB {
struct A {
A(int);
};
struct B {
B(int);
};
struct C {
C(int);
};
struct MultipleBases : A, B, C {
int x;
int y;
int z;
MultipleBases() :
z(5),
B(1),
x(3),
A(0),
C(2),
y(4) {
}
};
struct VB {
VB();
VB(int);
~VB();
};
struct VD : virtual VB {
};
struct VirtualAndNonVirtual : VD, VB {
VirtualAndNonVirtual() {
}
~VirtualAndNonVirtual() {
}
};
struct AllYourVirtualBaseAreBelongToUs : VD, VirtualAndNonVirtual, virtual VB {
AllYourVirtualBaseAreBelongToUs() :
VB(5) {
}
~AllYourVirtualBaseAreBelongToUs() {
}
struct VD : virtual VB {
};
struct VirtualAndNonVirtual : VD, VB {
VirtualAndNonVirtual() {
}
~VirtualAndNonVirtual() {
}
};
struct AllYourVirtualBaseAreBelongToUs : VD, VirtualAndNonVirtual, virtual VB {
AllYourVirtualBaseAreBelongToUs() :
VB(5) {
}
~AllYourVirtualBaseAreBelongToUs() {
}
};

View File

@@ -1,10 +1,10 @@
// src5.cpp
#include "src5.fwd.hpp"
template<class elem>
class my_istream {
};
template <>
class my_istream<char>;
// src5.cpp
#include "src5.fwd.hpp"
template<class elem>
class my_istream {
};
template <>
class my_istream<char>;

View File

@@ -1,8 +1,8 @@
// src5.fwd.hpp
#ifndef SRC5_FWD_HPP
#define SRC5_FWD_HPP
template<class elem> class my_istream;
#endif // SRC5_FWD_HPP
// src5.fwd.hpp
#ifndef SRC5_FWD_HPP
#define SRC5_FWD_HPP
template<class elem> class my_istream;
#endif // SRC5_FWD_HPP

View File

@@ -1,5 +1,5 @@
// src6.cpp
#include "src5.fwd.hpp"
my_istream<char> *mis_c;
// src6.cpp
#include "src5.fwd.hpp"
my_istream<char> *mis_c;

View File

@@ -1,28 +1,28 @@
class A {
public:
A() {}
};
A a;
void f() {}
class Test {
A aa;
void fa() {}
void test() {
void (*fptr)();
void (Test::*mfptr)();
void *ptr;
ptr = &a;
ptr = &aa;
fptr = f; // same as below
fptr = &f; // same as above
mfptr = &Test::fa;
}
};
class A {
public:
A() {}
};
A a;
void f() {}
class Test {
A aa;
void fa() {}
void test() {
void (*fptr)();
void (Test::*mfptr)();
void *ptr;
ptr = &a;
ptr = &aa;
fptr = f; // same as below
fptr = &f; // same as above
mfptr = &Test::fa;
}
};

View File

@@ -1,28 +1,28 @@
class Friend1 {
public:
void f();
protected:
void g();
private:
void h();
};
class Friend2 {
public:
void f();
protected:
void g();
private:
void h();
};
void Friend2::f() {
}
void friendFunc() {}
class C {
friend class Friend1;
friend void Friend2::f();
friend void friendFunc();
};
class Friend1 {
public:
void f();
protected:
void g();
private:
void h();
};
class Friend2 {
public:
void f();
protected:
void g();
private:
void h();
};
void Friend2::f() {
}
void friendFunc() {}
class C {
friend class Friend1;
friend void Friend2::f();
friend void friendFunc();
};

View File

@@ -1,31 +1,31 @@
//references(UserType)
class A {
public:
A() {}
};
int f() {
void *a_ptr = new A(); //match (1 call)
A a = A(); // match (1 call)
return 1;
}
//calls(Function)
int g() {return 0;}
extern int h();
int x = g(); //match
int y = x + g(); //match (1 call, 1 access)
int z = x + g() + h(); //match(2 calls, 1 access)
//accesses(Variable)
int i = 1;
int j = i; //match (1 access)
A a; //match(1 call)
A ax = A(); //match (1 call)
A aax = ax; //match (1 access)
//array initialization
int myIntArray[5] = {i, 0, 0, 0, 0}; //match(1 access)
A myObjectArray[3]; //match(1 call)
//references(UserType)
class A {
public:
A() {}
};
int f() {
void *a_ptr = new A(); //match (1 call)
A a = A(); // match (1 call)
return 1;
}
//calls(Function)
int g() {return 0;}
extern int h();
int x = g(); //match
int y = x + g(); //match (1 call, 1 access)
int z = x + g() + h(); //match(2 calls, 1 access)
//accesses(Variable)
int i = 1;
int j = i; //match (1 access)
A a; //match(1 call)
A ax = A(); //match (1 call)
A aax = ax; //match (1 access)
//array initialization
int myIntArray[5] = {i, 0, 0, 0, 0}; //match(1 access)
A myObjectArray[3]; //match(1 call)

View File

@@ -1,89 +1,89 @@
const int c = 1;
int v = 1;
int one() {return 1;}
void myNormalFunction()
{
static int static_1 = 1;
static int static_c = c;
static int static_v = v;
static int static_one = one();
int local_1 = 1;
int local_c = c;
int local_v = v;
int local_one = one();
}
template<class T> void myTemplateFunction()
{
static int static_int_1 = 1;
static int static_int_c = c; // [initializer is not populated]
static int static_int_v = v; // [initializer is not populated]
static int static_int_one = one(); // [initializer is not populated]
static T static_t_1 = 1; // [initializer is not populated]
static T static_t_c = c; // [initializer is not populated]
static T static_t_v = v; // [initializer is not populated]
static T static_t_one = one(); // [initializer is not populated]
int local_int_1 = 1;
int local_int_c = c;
int local_int_v = v;
int local_int_one = one();
T local_t_1 = 1;
T local_t_c = c;
T local_t_v = v;
T local_t_one = one();
}
template<class T> class myTemplateClass
{
public:
void myMethod()
{
static int static_int_1 = 1;
static int static_int_c = c; // [initializer is not populated]
static int static_int_v = v; // [initializer is not populated]
static int static_int_one = one(); // [initializer is not populated]
static T static_t_1 = 1; // [initializer is not populated]
static T static_t_c = c; // [initializer is not populated]
static T static_t_v = v; // [initializer is not populated]
static T static_t_one = one(); // [initializer is not populated]
int local_int_1 = 1;
int local_int_c = c;
int local_int_v = v;
int local_int_one = one();
T local_t_1 = 1;
T local_t_c = c;
T local_t_v = v;
T local_t_one = one();
}
};
enum myEnum
{
MYENUM_CONST
};
template<class T> void myTemplateFunction2(int a = 1, T b = 2)
{
static int static_int_zero = 0;
static int static_int_ec = MYENUM_CONST;
static int static_int_expr = v + 1;
static int *static_int_addr = &v;
static int static_int_sizeof_v = sizeof(v);
static int static_int_sizeof_t = sizeof(T);
static T static_t_zero = 0;
static T static_t_ec = MYENUM_CONST;
static T static_t_expr = v + 1;
static T *static_t_addr = &v;
static T static_t_sizeof_v = sizeof(v);
static T static_t_sizeof_t = sizeof(T);
static int static_int_c1 = c;
static int static_int_c2=c;
{
static int static_int_v2 = v;
}
}
const int c = 1;
int v = 1;
int one() {return 1;}
void myNormalFunction()
{
static int static_1 = 1;
static int static_c = c;
static int static_v = v;
static int static_one = one();
int local_1 = 1;
int local_c = c;
int local_v = v;
int local_one = one();
}
template<class T> void myTemplateFunction()
{
static int static_int_1 = 1;
static int static_int_c = c; // [initializer is not populated]
static int static_int_v = v; // [initializer is not populated]
static int static_int_one = one(); // [initializer is not populated]
static T static_t_1 = 1; // [initializer is not populated]
static T static_t_c = c; // [initializer is not populated]
static T static_t_v = v; // [initializer is not populated]
static T static_t_one = one(); // [initializer is not populated]
int local_int_1 = 1;
int local_int_c = c;
int local_int_v = v;
int local_int_one = one();
T local_t_1 = 1;
T local_t_c = c;
T local_t_v = v;
T local_t_one = one();
}
template<class T> class myTemplateClass
{
public:
void myMethod()
{
static int static_int_1 = 1;
static int static_int_c = c; // [initializer is not populated]
static int static_int_v = v; // [initializer is not populated]
static int static_int_one = one(); // [initializer is not populated]
static T static_t_1 = 1; // [initializer is not populated]
static T static_t_c = c; // [initializer is not populated]
static T static_t_v = v; // [initializer is not populated]
static T static_t_one = one(); // [initializer is not populated]
int local_int_1 = 1;
int local_int_c = c;
int local_int_v = v;
int local_int_one = one();
T local_t_1 = 1;
T local_t_c = c;
T local_t_v = v;
T local_t_one = one();
}
};
enum myEnum
{
MYENUM_CONST
};
template<class T> void myTemplateFunction2(int a = 1, T b = 2)
{
static int static_int_zero = 0;
static int static_int_ec = MYENUM_CONST;
static int static_int_expr = v + 1;
static int *static_int_addr = &v;
static int static_int_sizeof_v = sizeof(v);
static int static_int_sizeof_t = sizeof(T);
static T static_t_zero = 0;
static T static_t_ec = MYENUM_CONST;
static T static_t_expr = v + 1;
static T *static_t_addr = &v;
static T static_t_sizeof_v = sizeof(v);
static T static_t_sizeof_t = sizeof(T);
static int static_int_c1 = c;
static int static_int_c2=c;
{
static int static_int_v2 = v;
}
}

View File

@@ -1,74 +1,74 @@
namespace ns2 {
const int c = 1;
int v = 1;
int one() {return 1;}
void myNormalFunction()
{
static int static_1 = 1;
static int static_c = c;
static int static_v = v;
static int static_one = one();
int local_1 = 1;
int local_c = c;
int local_v = v;
int local_one = one();
}
template<class T> void myTemplateFunction()
{
static int static_int_1 = 1;
static int static_int_c = c; // [initializer is not populated]
static int static_int_v = v; // [initializer is not populated]
static int static_int_one = one(); // [initializer is not populated]
static T static_t_1 = 1; // [initializer is not populated]
static T static_t_c = c; // [initializer is not populated]
static T static_t_v = v; // [initializer is not populated]
static T static_t_one = one(); // [initializer is not populated]
int local_int_1 = 1;
int local_int_c = c;
int local_int_v = v;
int local_int_one = one();
T local_t_1 = 1;
T local_t_c = c;
T local_t_v = v;
T local_t_one = one();
}
template<class T> class myTemplateClass
{
public:
void myMethod()
{
static int static_int_1 = 1;
static int static_int_c = c; // [initializer is not populated]
static int static_int_v = v; // [initializer is not populated]
static int static_int_one = one(); // [initializer is not populated]
static T static_t_1 = 1; // [initializer is not populated]
static T static_t_c = c; // [initializer is not populated]
static T static_t_v = v; // [initializer is not populated]
static T static_t_one = one(); // [initializer is not populated]
int local_int_1 = 1;
int local_int_c = c;
int local_int_v = v;
int local_int_one = one();
T local_t_1 = 1;
T local_t_c = c;
T local_t_v = v;
T local_t_one = one();
}
};
void testFunc()
{
// instantiate the templates
myTemplateFunction<int>();
{
myTemplateClass<int> mtc;
mtc.myMethod();
}
}
}
namespace ns2 {
const int c = 1;
int v = 1;
int one() {return 1;}
void myNormalFunction()
{
static int static_1 = 1;
static int static_c = c;
static int static_v = v;
static int static_one = one();
int local_1 = 1;
int local_c = c;
int local_v = v;
int local_one = one();
}
template<class T> void myTemplateFunction()
{
static int static_int_1 = 1;
static int static_int_c = c; // [initializer is not populated]
static int static_int_v = v; // [initializer is not populated]
static int static_int_one = one(); // [initializer is not populated]
static T static_t_1 = 1; // [initializer is not populated]
static T static_t_c = c; // [initializer is not populated]
static T static_t_v = v; // [initializer is not populated]
static T static_t_one = one(); // [initializer is not populated]
int local_int_1 = 1;
int local_int_c = c;
int local_int_v = v;
int local_int_one = one();
T local_t_1 = 1;
T local_t_c = c;
T local_t_v = v;
T local_t_one = one();
}
template<class T> class myTemplateClass
{
public:
void myMethod()
{
static int static_int_1 = 1;
static int static_int_c = c; // [initializer is not populated]
static int static_int_v = v; // [initializer is not populated]
static int static_int_one = one(); // [initializer is not populated]
static T static_t_1 = 1; // [initializer is not populated]
static T static_t_c = c; // [initializer is not populated]
static T static_t_v = v; // [initializer is not populated]
static T static_t_one = one(); // [initializer is not populated]
int local_int_1 = 1;
int local_int_c = c;
int local_int_v = v;
int local_int_one = one();
T local_t_1 = 1;
T local_t_c = c;
T local_t_v = v;
T local_t_one = one();
}
};
void testFunc()
{
// instantiate the templates
myTemplateFunction<int>();
{
myTemplateClass<int> mtc;
mtc.myMethod();
}
}
}

View File

@@ -1,9 +1,9 @@
class C {
C() {}
};
typedef C CC;
CC** f() {
return 0;
}
class C {
C() {}
};
typedef C CC;
CC** f() {
return 0;
}

View File

@@ -1,15 +1,15 @@
const int j = 0;
enum Day { sun, mon, tue, wed, thu, fri, sat };
enum Day2 { sun2 = j, mon2, tue2 };
enum Flag { b = 'a', c = 'b', d = 'd' };
Day& operator++(Day& d)
{
int i = d;
Flag f = Flag(7);
Flag g = Flag(8);
//const int *p = &sat;
Day2 d2 = (Day2)d;
return d = (sat==d) ? sun: Day(d+1);
}
const int j = 0;
enum Day { sun, mon, tue, wed, thu, fri, sat };
enum Day2 { sun2 = j, mon2, tue2 };
enum Flag { b = 'a', c = 'b', d = 'd' };
Day& operator++(Day& d)
{
int i = d;
Flag f = Flag(7);
Flag g = Flag(8);
//const int *p = &sat;
Day2 d2 = (Day2)d;
return d = (sat==d) ? sun: Day(d+1);
}

View File

@@ -1,14 +1,14 @@
int main()
{
int x;
if (x == 1) {}
if (x != 1) {}
if (x < 1) {}
if (x > 1) {}
if (x <= 1) {}
if (x >= 1) {}
return 0;
}
int main()
{
int x;
if (x == 1) {}
if (x != 1) {}
if (x < 1) {}
if (x > 1) {}
if (x <= 1) {}
if (x >= 1) {}
return 0;
}

View File

@@ -1,15 +1,15 @@
int main()
{
int i;
int *ip;
i = +(-1);
i++;
ip = &i;
*ip--;
++i;
--i;
return 0;
}
int main()
{
int i;
int *ip;
i = +(-1);
i++;
ip = &i;
*ip--;
++i;
--i;
return 0;
}

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