mirror of
https://github.com/github/codeql.git
synced 2025-12-16 08:43:11 +01:00
Merge branch 'master' into master
This commit is contained in:
@@ -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
63
.gitattributes
vendored
@@ -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
4
.gitignore
vendored
@@ -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
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
@@ -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()
|
||||
...
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
...
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
...
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
void f() {
|
||||
static int i = 0; //i is unused
|
||||
...
|
||||
return;
|
||||
}
|
||||
void f() {
|
||||
static int i = 0; //i is unused
|
||||
...
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
...
|
||||
}
|
||||
|
||||
@@ -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
|
||||
...
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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[]'
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
|
||||
@@ -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
|
||||
...
|
||||
}
|
||||
|
||||
@@ -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
|
||||
...
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
int foo = 1;
|
||||
... //foo is unused
|
||||
}
|
||||
{
|
||||
int foo = 1;
|
||||
... //foo is unused
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
//...
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
...
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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'
|
||||
// ...
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 *)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
LPMALLOC pMalloc;
|
||||
HRESULT hr = CoGetMalloc(1, &pMalloc);
|
||||
|
||||
if (!hr)
|
||||
{
|
||||
// code ...
|
||||
}
|
||||
@@ -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>
|
||||
71
cpp/ql/src/Security/CWE/CWE-253/HResultBooleanConversion.ql
Normal file
71
cpp/ql/src/Security/CWE/CWE-253/HResultBooleanConversion.ql
Normal 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
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// common.h
|
||||
|
||||
#include "nameclash.h"
|
||||
|
||||
// common.h
|
||||
|
||||
#include "nameclash.h"
|
||||
|
||||
static int myArray[sizeof(MYTYPE)];
|
||||
@@ -1,3 +1,3 @@
|
||||
// defines_issue.h
|
||||
|
||||
// defines_issue.h
|
||||
|
||||
#include DEFINED_HEADER
|
||||
@@ -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"
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
// nameclash.h
|
||||
|
||||
// nameclash.h
|
||||
|
||||
#include_next "nameclash.h"
|
||||
@@ -1,3 +1,3 @@
|
||||
// subdir1/nameclash.h
|
||||
|
||||
// subdir1/nameclash.h
|
||||
|
||||
typedef long long int MYTYPE;
|
||||
@@ -1,3 +1,3 @@
|
||||
// subdir2/nameclash.h
|
||||
|
||||
// subdir2/nameclash.h
|
||||
|
||||
typedef char MYTYPE;
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
|
||||
extern void swap(int*, int*);
|
||||
|
||||
extern void swap(int*, int*);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
{
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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() {
|
||||
}
|
||||
};
|
||||
@@ -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>;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
class C {
|
||||
C() {}
|
||||
};
|
||||
|
||||
typedef C CC;
|
||||
|
||||
CC** f() {
|
||||
return 0;
|
||||
}
|
||||
class C {
|
||||
C() {}
|
||||
};
|
||||
|
||||
typedef C CC;
|
||||
|
||||
CC** f() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user