mirror of
https://github.com/github/codeql.git
synced 2025-12-18 09:43:15 +01:00
Before this change, `Expr.isConstant` only was only true for those constant expressions that could be represented as QL values: numbers, Booleans, and string literals. It was not true for string literals converted from arrays to pointers, and it was not true for addresses of variables with static lifetime. The concept of a "constant expression" varies between C and C++ and between versions of the standard, but they all include addresses of data with static lifetime. These are modelled by the new library `AddressConstantExpression.qll`, which is based on the code in `EscapesTree.qll` and modified for its new purpose. I've tested the change for performance on Wireshark and for correctness with the included tests. I've also checked on Wireshark that all static initializers in C files are considered constant, which was not the case before.
87 lines
3.1 KiB
C++
87 lines
3.1 KiB
C++
// semmle-extractor-options: --c++14
|
|
|
|
const int int_const = 1;
|
|
extern const int extern_int_const = 1;
|
|
extern const int extern_int_const_noinit;
|
|
|
|
int int_var;
|
|
int int_arr[4];
|
|
int int_arr_arr[4][4];
|
|
|
|
int *const const_ptr = &int_var;
|
|
|
|
void sideEffect();
|
|
using fptr = void (*)();
|
|
using fref = void (&)();
|
|
|
|
|
|
|
|
// All variables in this function are initialized to constants, as witnessed by
|
|
// the `constexpr` annotation that compiles under C++14.
|
|
void constantAddresses(int param) {
|
|
constexpr int *ptr_int = &int_var;
|
|
constexpr int *ptr_deref_chain = &*&int_var;
|
|
constexpr int *ptr_array = &int_arr[1] + 1;
|
|
constexpr int (*ptr_to_array)[4] = &int_arr_arr[1] + 1;
|
|
constexpr int *array2d = &int_arr_arr[1][1] + 1;
|
|
constexpr int *const_ints = &int_arr_arr[int_const][extern_int_const];
|
|
|
|
// Commented out because clang and EDG disagree on whether this is
|
|
// constant.
|
|
//constexpr int *stmtexpr_int = &int_arr[ ({ 1; }) ];
|
|
|
|
constexpr int *comma_int = &int_arr[ ((void)0, 1) ];
|
|
constexpr int *comma_addr = ((void)0, &int_var);
|
|
constexpr int *ternary_true = int_const ? &int_var : ¶m;
|
|
constexpr int *ternary_false = !int_const ? ¶m : &int_var;
|
|
constexpr int *ternary_overflow = (unsigned char)256 ? ¶m : &int_var;
|
|
constexpr int *ternary_ptr_cond = (&int_arr+1) ? &int_var : ¶m;;
|
|
constexpr int *ptr_subtract = &int_arr[&int_arr[1] - &int_arr[0]];
|
|
|
|
constexpr int *constexpr_va = ptr_subtract + 1;
|
|
|
|
constexpr int &ref_int = int_var;
|
|
constexpr int &ref_array2d = int_arr_arr[1][1];
|
|
constexpr int &ref_va = ref_array2d;
|
|
constexpr int &ref_va_arith = *(&ref_array2d + 1);
|
|
|
|
constexpr fptr fp_implicit = sideEffect;
|
|
constexpr fptr fp_explicit = &sideEffect;
|
|
constexpr fptr fp_chain_addressof = &**&**sideEffect;
|
|
constexpr fptr fp_chain_deref = **&**&**sideEffect;
|
|
constexpr fptr fp_shortchain_deref = *&sideEffect;
|
|
|
|
constexpr fref fr_int = sideEffect;
|
|
constexpr fref fr_deref = *&sideEffect;
|
|
constexpr fref fr_2deref = **sideEffect;
|
|
constexpr fref fr_va = fr_int;
|
|
|
|
constexpr const char *char_ptr = "str";
|
|
constexpr const char *char_ptr_1 = "str" + 1;
|
|
constexpr char char_arr[] = "str";
|
|
}
|
|
|
|
|
|
|
|
|
|
// All variables in this function are initialized to non-const values. Writing
|
|
// `constexpr` in front of any of the variables will be a compile error
|
|
// (C++14).
|
|
void nonConstantAddresses(const int param, int *const pparam, int &rparam, fref frparam) {
|
|
int *int_param = &int_arr[param];
|
|
int *int_noinit = &int_arr[extern_int_const_noinit];
|
|
|
|
int *side_effect_stmtexpr = &int_arr[ ({ sideEffect(); 1; }) ];
|
|
int *side_effect_comma_int = &int_arr[ (sideEffect(), 1) ];
|
|
int *side_effect_comma_addr = (sideEffect(), &int_var);
|
|
int *side_effect_comma_addr2 = ((void)(sideEffect(), 1), &int_var);
|
|
int *ternary_int = &int_arr[int_const ? param : 1];
|
|
const int *ternary_addr = int_const ? ¶m : &int_var;
|
|
int *va_non_constexpr = pparam;
|
|
|
|
int *&&ref_to_temporary = &int_var; // reference to temporary is not a const
|
|
int &ref_param = rparam;
|
|
|
|
fref fr_param = frparam;
|
|
}
|