From e41677b13cd8d4428dc73ffc0060fc0ee030bdc8 Mon Sep 17 00:00:00 2001 From: James Lee-Jones Date: Wed, 29 May 2024 13:59:29 +0100 Subject: [PATCH 1/5] Fix incorrect mutation of comma expressions in C++ --- src/libdredd/src/mutation_replace_expr.cc | 22 +++---- test/single_file/comma_initialization.c | 3 + .../comma_initialization.c.expected | 60 ++++++++++++++++++ .../comma_initialization.c.noopt.expected | 56 +++++++++++++++++ test/single_file/comma_initialization.cc | 3 + .../comma_initialization.cc.expected | 62 +++++++++++++++++++ .../comma_initialization.cc.noopt.expected | 58 +++++++++++++++++ 7 files changed, 253 insertions(+), 11 deletions(-) create mode 100644 test/single_file/comma_initialization.c create mode 100644 test/single_file/comma_initialization.c.expected create mode 100644 test/single_file/comma_initialization.c.noopt.expected create mode 100644 test/single_file/comma_initialization.cc create mode 100644 test/single_file/comma_initialization.cc.expected create mode 100644 test/single_file/comma_initialization.cc.noopt.expected diff --git a/src/libdredd/src/mutation_replace_expr.cc b/src/libdredd/src/mutation_replace_expr.cc index 79f358e2..cbd1c68f 100644 --- a/src/libdredd/src/mutation_replace_expr.cc +++ b/src/libdredd/src/mutation_replace_expr.cc @@ -538,18 +538,18 @@ void MutationReplaceExpr::ReplaceExprWithFunctionCall( suffix.append("; }"); } - if (!ast_context.getLangOpts().CPlusPlus) { - if (expr_->isLValue() && input_type.ends_with('*')) { - prefix.append("&("); + if (!ast_context.getLangOpts().CPlusPlus && expr_->isLValue() && + input_type.ends_with('*')) { + prefix.append("&("); + suffix.append(")"); + } + + if (const auto* binary_expr = llvm::dyn_cast(expr_)) { + // The comma operator requires special care in C, to avoid it appearing to + // provide multiple parameters for an enclosing function call. + if (binary_expr->isCommaOp()) { + prefix.append("("); suffix.append(")"); - } else if (const auto* binary_expr = - llvm::dyn_cast(expr_)) { - // The comma operator requires special care in C, to avoid it appearing to - // provide multiple parameters for an enclosing function call. - if (binary_expr->isCommaOp()) { - prefix.append("("); - suffix.append(")"); - } } } diff --git a/test/single_file/comma_initialization.c b/test/single_file/comma_initialization.c new file mode 100644 index 00000000..9843f02a --- /dev/null +++ b/test/single_file/comma_initialization.c @@ -0,0 +1,3 @@ +int main() { + int x = (1,0); +} diff --git a/test/single_file/comma_initialization.c.expected b/test/single_file/comma_initialization.c.expected new file mode 100644 index 00000000..4ebe758b --- /dev/null +++ b/test/single_file/comma_initialization.c.expected @@ -0,0 +1,60 @@ +#include +#include +#include +#include + +#ifdef _MSC_VER +#define thread_local __declspec(thread) +#elif __APPLE__ +#define thread_local __thread +#else +#include +#endif + +static thread_local int __dredd_some_mutation_enabled = 1; +static int __dredd_enabled_mutation(int local_mutation_id) { + static thread_local int initialized = 0; + static thread_local uint64_t enabled_bitset[1]; + if (!initialized) { + int some_mutation_enabled = 0; + const char* dredd_environment_variable = getenv("DREDD_ENABLED_MUTATION"); + if (dredd_environment_variable) { + char* temp = malloc(strlen(dredd_environment_variable) + 1); + strcpy(temp, dredd_environment_variable); + char* token; + token = strtok(temp, ","); + while(token) { + int value = atoi(token); + int local_value = value - 0; + if (local_value >= 0 && local_value < 7) { + enabled_bitset[local_value / 64] |= (1 << (local_value % 64)); + some_mutation_enabled = 1; + } + token = strtok(NULL, ","); + } + free(temp); + } + initialized = 1; + __dredd_some_mutation_enabled = some_mutation_enabled; + } + return enabled_bitset[local_mutation_id / 64] & (1 << (local_mutation_id % 64)); +} + +static int __dredd_replace_expr_int_zero(int arg, int local_mutation_id) { + if (!__dredd_some_mutation_enabled) return arg; + if (__dredd_enabled_mutation(local_mutation_id + 0)) return 1; + if (__dredd_enabled_mutation(local_mutation_id + 1)) return -1; + return arg; +} + +static int __dredd_replace_expr_int_one(int arg, int local_mutation_id) { + if (!__dredd_some_mutation_enabled) return arg; + if (__dredd_enabled_mutation(local_mutation_id + 0)) return ~(arg); + if (__dredd_enabled_mutation(local_mutation_id + 1)) return 0; + if (__dredd_enabled_mutation(local_mutation_id + 2)) return -1; + return arg; +} + +int main() { + int x = (__dredd_replace_expr_int_zero((__dredd_replace_expr_int_one(1, 0),__dredd_replace_expr_int_zero(0, 3)), 5)); +} diff --git a/test/single_file/comma_initialization.c.noopt.expected b/test/single_file/comma_initialization.c.noopt.expected new file mode 100644 index 00000000..e16fe37e --- /dev/null +++ b/test/single_file/comma_initialization.c.noopt.expected @@ -0,0 +1,56 @@ +#include +#include +#include +#include + +#ifdef _MSC_VER +#define thread_local __declspec(thread) +#elif __APPLE__ +#define thread_local __thread +#else +#include +#endif + +static thread_local int __dredd_some_mutation_enabled = 1; +static int __dredd_enabled_mutation(int local_mutation_id) { + static thread_local int initialized = 0; + static thread_local uint64_t enabled_bitset[1]; + if (!initialized) { + int some_mutation_enabled = 0; + const char* dredd_environment_variable = getenv("DREDD_ENABLED_MUTATION"); + if (dredd_environment_variable) { + char* temp = malloc(strlen(dredd_environment_variable) + 1); + strcpy(temp, dredd_environment_variable); + char* token; + token = strtok(temp, ","); + while(token) { + int value = atoi(token); + int local_value = value - 0; + if (local_value >= 0 && local_value < 24) { + enabled_bitset[local_value / 64] |= (1 << (local_value % 64)); + some_mutation_enabled = 1; + } + token = strtok(NULL, ","); + } + free(temp); + } + initialized = 1; + __dredd_some_mutation_enabled = some_mutation_enabled; + } + return enabled_bitset[local_mutation_id / 64] & (1 << (local_mutation_id % 64)); +} + +static int __dredd_replace_expr_int(int arg, int local_mutation_id) { + if (!__dredd_some_mutation_enabled) return arg; + if (__dredd_enabled_mutation(local_mutation_id + 0)) return !(arg); + if (__dredd_enabled_mutation(local_mutation_id + 1)) return ~(arg); + if (__dredd_enabled_mutation(local_mutation_id + 2)) return -(arg); + if (__dredd_enabled_mutation(local_mutation_id + 3)) return 0; + if (__dredd_enabled_mutation(local_mutation_id + 4)) return 1; + if (__dredd_enabled_mutation(local_mutation_id + 5)) return -1; + return arg; +} + +int main() { + int x = __dredd_replace_expr_int((__dredd_replace_expr_int((__dredd_replace_expr_int(1, 0),__dredd_replace_expr_int(0, 6)), 12)), 18); +} diff --git a/test/single_file/comma_initialization.cc b/test/single_file/comma_initialization.cc new file mode 100644 index 00000000..37226a11 --- /dev/null +++ b/test/single_file/comma_initialization.cc @@ -0,0 +1,3 @@ +int main() { + int b((1,0)); +} diff --git a/test/single_file/comma_initialization.cc.expected b/test/single_file/comma_initialization.cc.expected new file mode 100644 index 00000000..56c094e8 --- /dev/null +++ b/test/single_file/comma_initialization.cc.expected @@ -0,0 +1,62 @@ +#include +#include +#include +#include + + +#ifdef _MSC_VER +#define thread_local __declspec(thread) +#elif __APPLE__ +#define thread_local __thread +#endif + +static thread_local bool __dredd_some_mutation_enabled = true; +static bool __dredd_enabled_mutation(int local_mutation_id) { + static thread_local bool initialized = false; + static thread_local uint64_t enabled_bitset[1]; + if (!initialized) { + bool some_mutation_enabled = false; + const char* dredd_environment_variable = std::getenv("DREDD_ENABLED_MUTATION"); + if (dredd_environment_variable != nullptr) { + std::string contents(dredd_environment_variable); + while (true) { + size_t pos = contents.find(","); + std::string token = (pos == std::string::npos ? contents : contents.substr(0, pos)); + if (!token.empty()) { + int value = std::stoi(token); + int local_value = value - 0; + if (local_value >= 0 && local_value < 7) { + enabled_bitset[local_value / 64] |= (1 << (local_value % 64)); + some_mutation_enabled = true; + } + } + if (pos == std::string::npos) { + break; + } + contents.erase(0, pos + 1); + } + } + initialized = true; + __dredd_some_mutation_enabled = some_mutation_enabled; + } + return (enabled_bitset[local_mutation_id / 64] & (1 << (local_mutation_id % 64))) != 0; +} + +static int __dredd_replace_expr_int_zero(int arg, int local_mutation_id) { + if (!__dredd_some_mutation_enabled) return arg; + if (__dredd_enabled_mutation(local_mutation_id + 0)) return 1; + if (__dredd_enabled_mutation(local_mutation_id + 1)) return -1; + return arg; +} + +static int __dredd_replace_expr_int_one(int arg, int local_mutation_id) { + if (!__dredd_some_mutation_enabled) return arg; + if (__dredd_enabled_mutation(local_mutation_id + 0)) return ~(arg); + if (__dredd_enabled_mutation(local_mutation_id + 1)) return 0; + if (__dredd_enabled_mutation(local_mutation_id + 2)) return -1; + return arg; +} + +int main() { + int b((__dredd_replace_expr_int_zero((__dredd_replace_expr_int_one(1, 0),__dredd_replace_expr_int_zero(0, 3)), 5))); +} diff --git a/test/single_file/comma_initialization.cc.noopt.expected b/test/single_file/comma_initialization.cc.noopt.expected new file mode 100644 index 00000000..350d23cb --- /dev/null +++ b/test/single_file/comma_initialization.cc.noopt.expected @@ -0,0 +1,58 @@ +#include +#include +#include +#include + + +#ifdef _MSC_VER +#define thread_local __declspec(thread) +#elif __APPLE__ +#define thread_local __thread +#endif + +static thread_local bool __dredd_some_mutation_enabled = true; +static bool __dredd_enabled_mutation(int local_mutation_id) { + static thread_local bool initialized = false; + static thread_local uint64_t enabled_bitset[1]; + if (!initialized) { + bool some_mutation_enabled = false; + const char* dredd_environment_variable = std::getenv("DREDD_ENABLED_MUTATION"); + if (dredd_environment_variable != nullptr) { + std::string contents(dredd_environment_variable); + while (true) { + size_t pos = contents.find(","); + std::string token = (pos == std::string::npos ? contents : contents.substr(0, pos)); + if (!token.empty()) { + int value = std::stoi(token); + int local_value = value - 0; + if (local_value >= 0 && local_value < 24) { + enabled_bitset[local_value / 64] |= (1 << (local_value % 64)); + some_mutation_enabled = true; + } + } + if (pos == std::string::npos) { + break; + } + contents.erase(0, pos + 1); + } + } + initialized = true; + __dredd_some_mutation_enabled = some_mutation_enabled; + } + return (enabled_bitset[local_mutation_id / 64] & (1 << (local_mutation_id % 64))) != 0; +} + +static int __dredd_replace_expr_int(int arg, int local_mutation_id) { + if (!__dredd_some_mutation_enabled) return arg; + if (__dredd_enabled_mutation(local_mutation_id + 0)) return !(arg); + if (__dredd_enabled_mutation(local_mutation_id + 1)) return ~(arg); + if (__dredd_enabled_mutation(local_mutation_id + 2)) return -(arg); + if (__dredd_enabled_mutation(local_mutation_id + 3)) return 0; + if (__dredd_enabled_mutation(local_mutation_id + 4)) return 1; + if (__dredd_enabled_mutation(local_mutation_id + 5)) return -1; + return arg; +} + +int main() { + int b(__dredd_replace_expr_int((__dredd_replace_expr_int((__dredd_replace_expr_int(1, 0),__dredd_replace_expr_int(0, 6)), 12)), 18)); +} From de39859fe0d5b866f02d46774a453630389eda95 Mon Sep 17 00:00:00 2001 From: James Lee-Jones Date: Wed, 29 May 2024 21:33:04 +0100 Subject: [PATCH 2/5] Prepend to suffix instead of appending --- src/dredd/src/main.cc | 36 +++---- src/libdredd/src/mutation_replace_expr.cc | 12 +-- test/single_file/comma_side_effects.c | 4 + .../single_file/comma_side_effects.c.expected | 89 +++++++++++++++++ .../comma_side_effects.c.noopt.expected | 82 ++++++++++++++++ test/single_file/comma_side_effects.cc | 4 + .../comma_side_effects.cc.expected | 91 ++++++++++++++++++ .../comma_side_effects.cc.noopt.expected | 95 +++++++++++++++++++ 8 files changed, 389 insertions(+), 24 deletions(-) create mode 100644 test/single_file/comma_side_effects.c create mode 100644 test/single_file/comma_side_effects.c.expected create mode 100644 test/single_file/comma_side_effects.c.noopt.expected create mode 100644 test/single_file/comma_side_effects.cc create mode 100644 test/single_file/comma_side_effects.cc.expected create mode 100644 test/single_file/comma_side_effects.cc.noopt.expected diff --git a/src/dredd/src/main.cc b/src/dredd/src/main.cc index 4e20ba48..a8f634a6 100644 --- a/src/dredd/src/main.cc +++ b/src/dredd/src/main.cc @@ -103,23 +103,23 @@ int main(int argc, const char** argv) { const int return_code = Tool.run(factory.get()); - if (return_code == 0) { - // Application of mutations was successful, so write out the mutation info - // in JSON format. - std::string json_string; - auto json_options = google::protobuf::util::JsonOptions(); - json_options.add_whitespace = true; - json_options.always_print_primitive_fields = true; - auto json_generation_status = google::protobuf::util::MessageToJsonString( - mutation_info, &json_string, json_options); - if (json_generation_status.ok()) { - std::ofstream transformations_json_file(mutation_info_file); - transformations_json_file << json_string; - } else { - llvm::errs() << "Error writing JSON data to " << mutation_info_file - << "\n"; - return 1; - } - } +// if (return_code == 0) { +// // Application of mutations was successful, so write out the mutation info +// // in JSON format. +// std::string json_string; +// auto json_options = google::protobuf::util::JsonOptions(); +// json_options.add_whitespace = true; +// json_options.always_print_primitive_fields = true; +// auto json_generation_status = google::protobuf::util::MessageToJsonString( +// mutation_info, &json_string, json_options); +// if (json_generation_status.ok()) { +// std::ofstream transformations_json_file(mutation_info_file); +// transformations_json_file << json_string; +// } else { +// llvm::errs() << "Error writing JSON data to " << mutation_info_file +// << "\n"; +// return 1; +// } +// } return return_code; } diff --git a/src/libdredd/src/mutation_replace_expr.cc b/src/libdredd/src/mutation_replace_expr.cc index cbd1c68f..0e864587 100644 --- a/src/libdredd/src/mutation_replace_expr.cc +++ b/src/libdredd/src/mutation_replace_expr.cc @@ -530,10 +530,10 @@ void MutationReplaceExpr::ReplaceExprWithFunctionCall( if (ast_context.getLangOpts().CPlusPlus && expr_->HasSideEffects(ast_context)) { prefix.append(+"[&]() -> " + input_type + " { return " + - // We don't need to static cast constant expressions - (IsCxx11ConstantExpr(*expr_, ast_context) - ? "" - : "static_cast<" + input_type + ">(")); + // We don't need to static cast constant expressions + (IsCxx11ConstantExpr(*expr_, ast_context) + ? "" + : "static_cast<" + input_type + ">(")); suffix.append(IsCxx11ConstantExpr(*expr_, ast_context) ? "" : ")"); suffix.append("; }"); } @@ -541,7 +541,7 @@ void MutationReplaceExpr::ReplaceExprWithFunctionCall( if (!ast_context.getLangOpts().CPlusPlus && expr_->isLValue() && input_type.ends_with('*')) { prefix.append("&("); - suffix.append(")"); + suffix = ")" + suffix; } if (const auto* binary_expr = llvm::dyn_cast(expr_)) { @@ -549,7 +549,7 @@ void MutationReplaceExpr::ReplaceExprWithFunctionCall( // provide multiple parameters for an enclosing function call. if (binary_expr->isCommaOp()) { prefix.append("("); - suffix.append(")"); + suffix = ")" + suffix; } } diff --git a/test/single_file/comma_side_effects.c b/test/single_file/comma_side_effects.c new file mode 100644 index 00000000..56cbc44c --- /dev/null +++ b/test/single_file/comma_side_effects.c @@ -0,0 +1,4 @@ +int main() { + int x = 0; + x = (0, x++); +} diff --git a/test/single_file/comma_side_effects.c.expected b/test/single_file/comma_side_effects.c.expected new file mode 100644 index 00000000..62b43b77 --- /dev/null +++ b/test/single_file/comma_side_effects.c.expected @@ -0,0 +1,89 @@ +#include +#include +#include +#include + +#ifdef _MSC_VER +#define thread_local __declspec(thread) +#elif __APPLE__ +#define thread_local __thread +#else +#include +#endif + +static thread_local int __dredd_some_mutation_enabled = 1; +static int __dredd_enabled_mutation(int local_mutation_id) { + static thread_local int initialized = 0; + static thread_local uint64_t enabled_bitset[1]; + if (!initialized) { + int some_mutation_enabled = 0; + const char* dredd_environment_variable = getenv("DREDD_ENABLED_MUTATION"); + if (dredd_environment_variable) { + char* temp = malloc(strlen(dredd_environment_variable) + 1); + strcpy(temp, dredd_environment_variable); + char* token; + token = strtok(temp, ","); + while(token) { + int value = atoi(token); + int local_value = value - 0; + if (local_value >= 0 && local_value < 32) { + enabled_bitset[local_value / 64] |= (1 << (local_value % 64)); + some_mutation_enabled = 1; + } + token = strtok(NULL, ","); + } + free(temp); + } + initialized = 1; + __dredd_some_mutation_enabled = some_mutation_enabled; + } + return enabled_bitset[local_mutation_id / 64] & (1 << (local_mutation_id % 64)); +} + +static int __dredd_replace_unary_operator_PostInc_int(int* arg, int local_mutation_id) { + if (!__dredd_some_mutation_enabled) return (*arg)++; + if (__dredd_enabled_mutation(local_mutation_id + 0)) return (*arg)--; + if (__dredd_enabled_mutation(local_mutation_id + 1)) return ~(*arg); + if (__dredd_enabled_mutation(local_mutation_id + 2)) return -(*arg); + if (__dredd_enabled_mutation(local_mutation_id + 3)) return !(*arg); + if (__dredd_enabled_mutation(local_mutation_id + 4)) return (*arg); + return (*arg)++; +} + +static int __dredd_replace_expr_int_zero(int arg, int local_mutation_id) { + if (!__dredd_some_mutation_enabled) return arg; + if (__dredd_enabled_mutation(local_mutation_id + 0)) return 1; + if (__dredd_enabled_mutation(local_mutation_id + 1)) return -1; + return arg; +} + +static int __dredd_replace_expr_int(int arg, int local_mutation_id) { + if (!__dredd_some_mutation_enabled) return arg; + if (__dredd_enabled_mutation(local_mutation_id + 0)) return !(arg); + if (__dredd_enabled_mutation(local_mutation_id + 1)) return ~(arg); + if (__dredd_enabled_mutation(local_mutation_id + 2)) return -(arg); + if (__dredd_enabled_mutation(local_mutation_id + 3)) return 0; + if (__dredd_enabled_mutation(local_mutation_id + 4)) return 1; + if (__dredd_enabled_mutation(local_mutation_id + 5)) return -1; + return arg; +} + +static int __dredd_replace_binary_operator_Assign_arg1_int_arg2_int(int* arg1, int arg2, int local_mutation_id) { + if (!__dredd_some_mutation_enabled) return (*arg1) = arg2; + if (__dredd_enabled_mutation(local_mutation_id + 0)) return (*arg1) += arg2; + if (__dredd_enabled_mutation(local_mutation_id + 1)) return (*arg1) &= arg2; + if (__dredd_enabled_mutation(local_mutation_id + 2)) return (*arg1) /= arg2; + if (__dredd_enabled_mutation(local_mutation_id + 3)) return (*arg1) *= arg2; + if (__dredd_enabled_mutation(local_mutation_id + 4)) return (*arg1) |= arg2; + if (__dredd_enabled_mutation(local_mutation_id + 5)) return (*arg1) %= arg2; + if (__dredd_enabled_mutation(local_mutation_id + 6)) return (*arg1) <<= arg2; + if (__dredd_enabled_mutation(local_mutation_id + 7)) return (*arg1) >>= arg2; + if (__dredd_enabled_mutation(local_mutation_id + 8)) return (*arg1) -= arg2; + if (__dredd_enabled_mutation(local_mutation_id + 9)) return (*arg1) ^= arg2; + return (*arg1) = arg2; +} + +int main() { + int x = __dredd_replace_expr_int_zero(0, 0); + if (!__dredd_enabled_mutation(31)) { __dredd_replace_binary_operator_Assign_arg1_int_arg2_int(&(x) , (__dredd_replace_expr_int((__dredd_replace_expr_int_zero(0, 2), __dredd_replace_expr_int(__dredd_replace_unary_operator_PostInc_int(&(x), 4), 9)), 15)), 21); } +} diff --git a/test/single_file/comma_side_effects.c.noopt.expected b/test/single_file/comma_side_effects.c.noopt.expected new file mode 100644 index 00000000..ec6b399f --- /dev/null +++ b/test/single_file/comma_side_effects.c.noopt.expected @@ -0,0 +1,82 @@ +#include +#include +#include +#include + +#ifdef _MSC_VER +#define thread_local __declspec(thread) +#elif __APPLE__ +#define thread_local __thread +#else +#include +#endif + +static thread_local int __dredd_some_mutation_enabled = 1; +static int __dredd_enabled_mutation(int local_mutation_id) { + static thread_local int initialized = 0; + static thread_local uint64_t enabled_bitset[1]; + if (!initialized) { + int some_mutation_enabled = 0; + const char* dredd_environment_variable = getenv("DREDD_ENABLED_MUTATION"); + if (dredd_environment_variable) { + char* temp = malloc(strlen(dredd_environment_variable) + 1); + strcpy(temp, dredd_environment_variable); + char* token; + token = strtok(temp, ","); + while(token) { + int value = atoi(token); + int local_value = value - 0; + if (local_value >= 0 && local_value < 52) { + enabled_bitset[local_value / 64] |= (1 << (local_value % 64)); + some_mutation_enabled = 1; + } + token = strtok(NULL, ","); + } + free(temp); + } + initialized = 1; + __dredd_some_mutation_enabled = some_mutation_enabled; + } + return enabled_bitset[local_mutation_id / 64] & (1 << (local_mutation_id % 64)); +} + +static int __dredd_replace_unary_operator_PostInc_int(int* arg, int local_mutation_id) { + if (!__dredd_some_mutation_enabled) return (*arg)++; + if (__dredd_enabled_mutation(local_mutation_id + 0)) return (*arg)--; + if (__dredd_enabled_mutation(local_mutation_id + 1)) return ~(*arg); + if (__dredd_enabled_mutation(local_mutation_id + 2)) return -(*arg); + if (__dredd_enabled_mutation(local_mutation_id + 3)) return !(*arg); + if (__dredd_enabled_mutation(local_mutation_id + 4)) return (*arg); + return (*arg)++; +} + +static int __dredd_replace_expr_int(int arg, int local_mutation_id) { + if (!__dredd_some_mutation_enabled) return arg; + if (__dredd_enabled_mutation(local_mutation_id + 0)) return !(arg); + if (__dredd_enabled_mutation(local_mutation_id + 1)) return ~(arg); + if (__dredd_enabled_mutation(local_mutation_id + 2)) return -(arg); + if (__dredd_enabled_mutation(local_mutation_id + 3)) return 0; + if (__dredd_enabled_mutation(local_mutation_id + 4)) return 1; + if (__dredd_enabled_mutation(local_mutation_id + 5)) return -1; + return arg; +} + +static int __dredd_replace_binary_operator_Assign_arg1_int_arg2_int(int* arg1, int arg2, int local_mutation_id) { + if (!__dredd_some_mutation_enabled) return (*arg1) = arg2; + if (__dredd_enabled_mutation(local_mutation_id + 0)) return (*arg1) += arg2; + if (__dredd_enabled_mutation(local_mutation_id + 1)) return (*arg1) &= arg2; + if (__dredd_enabled_mutation(local_mutation_id + 2)) return (*arg1) /= arg2; + if (__dredd_enabled_mutation(local_mutation_id + 3)) return (*arg1) *= arg2; + if (__dredd_enabled_mutation(local_mutation_id + 4)) return (*arg1) |= arg2; + if (__dredd_enabled_mutation(local_mutation_id + 5)) return (*arg1) %= arg2; + if (__dredd_enabled_mutation(local_mutation_id + 6)) return (*arg1) <<= arg2; + if (__dredd_enabled_mutation(local_mutation_id + 7)) return (*arg1) >>= arg2; + if (__dredd_enabled_mutation(local_mutation_id + 8)) return (*arg1) -= arg2; + if (__dredd_enabled_mutation(local_mutation_id + 9)) return (*arg1) ^= arg2; + return (*arg1) = arg2; +} + +int main() { + int x = __dredd_replace_expr_int(0, 0); + if (!__dredd_enabled_mutation(51)) { __dredd_replace_expr_int(__dredd_replace_binary_operator_Assign_arg1_int_arg2_int(&(x) , __dredd_replace_expr_int((__dredd_replace_expr_int((__dredd_replace_expr_int(0, 6), __dredd_replace_expr_int(__dredd_replace_unary_operator_PostInc_int(&(x), 12), 17)), 23)), 29), 35), 45); } +} diff --git a/test/single_file/comma_side_effects.cc b/test/single_file/comma_side_effects.cc new file mode 100644 index 00000000..56cbc44c --- /dev/null +++ b/test/single_file/comma_side_effects.cc @@ -0,0 +1,4 @@ +int main() { + int x = 0; + x = (0, x++); +} diff --git a/test/single_file/comma_side_effects.cc.expected b/test/single_file/comma_side_effects.cc.expected new file mode 100644 index 00000000..cbd5db97 --- /dev/null +++ b/test/single_file/comma_side_effects.cc.expected @@ -0,0 +1,91 @@ +#include +#include +#include +#include + + +#ifdef _MSC_VER +#define thread_local __declspec(thread) +#elif __APPLE__ +#define thread_local __thread +#endif + +static thread_local bool __dredd_some_mutation_enabled = true; +static bool __dredd_enabled_mutation(int local_mutation_id) { + static thread_local bool initialized = false; + static thread_local uint64_t enabled_bitset[1]; + if (!initialized) { + bool some_mutation_enabled = false; + const char* dredd_environment_variable = std::getenv("DREDD_ENABLED_MUTATION"); + if (dredd_environment_variable != nullptr) { + std::string contents(dredd_environment_variable); + while (true) { + size_t pos = contents.find(","); + std::string token = (pos == std::string::npos ? contents : contents.substr(0, pos)); + if (!token.empty()) { + int value = std::stoi(token); + int local_value = value - 0; + if (local_value >= 0 && local_value < 32) { + enabled_bitset[local_value / 64] |= (1 << (local_value % 64)); + some_mutation_enabled = true; + } + } + if (pos == std::string::npos) { + break; + } + contents.erase(0, pos + 1); + } + } + initialized = true; + __dredd_some_mutation_enabled = some_mutation_enabled; + } + return (enabled_bitset[local_mutation_id / 64] & (1 << (local_mutation_id % 64))) != 0; +} + +static int& __dredd_replace_binary_operator_Assign_arg1_int_arg2_int(int& arg1, std::function arg2, int local_mutation_id) { + if (!__dredd_some_mutation_enabled) return arg1 = arg2(); + if (__dredd_enabled_mutation(local_mutation_id + 0)) return arg1 += arg2(); + if (__dredd_enabled_mutation(local_mutation_id + 1)) return arg1 &= arg2(); + if (__dredd_enabled_mutation(local_mutation_id + 2)) return arg1 /= arg2(); + if (__dredd_enabled_mutation(local_mutation_id + 3)) return arg1 *= arg2(); + if (__dredd_enabled_mutation(local_mutation_id + 4)) return arg1 |= arg2(); + if (__dredd_enabled_mutation(local_mutation_id + 5)) return arg1 %= arg2(); + if (__dredd_enabled_mutation(local_mutation_id + 6)) return arg1 <<= arg2(); + if (__dredd_enabled_mutation(local_mutation_id + 7)) return arg1 >>= arg2(); + if (__dredd_enabled_mutation(local_mutation_id + 8)) return arg1 -= arg2(); + if (__dredd_enabled_mutation(local_mutation_id + 9)) return arg1 ^= arg2(); + return arg1 = arg2(); +} + +static int __dredd_replace_unary_operator_PostInc_int(std::function arg, int local_mutation_id) { + if (!__dredd_some_mutation_enabled) return arg()++; + if (__dredd_enabled_mutation(local_mutation_id + 0)) return arg()--; + if (__dredd_enabled_mutation(local_mutation_id + 1)) return ~arg(); + if (__dredd_enabled_mutation(local_mutation_id + 2)) return -arg(); + if (__dredd_enabled_mutation(local_mutation_id + 3)) return !arg(); + if (__dredd_enabled_mutation(local_mutation_id + 4)) return arg(); + return arg()++; +} + +static int __dredd_replace_expr_int_zero(int arg, int local_mutation_id) { + if (!__dredd_some_mutation_enabled) return arg; + if (__dredd_enabled_mutation(local_mutation_id + 0)) return 1; + if (__dredd_enabled_mutation(local_mutation_id + 1)) return -1; + return arg; +} + +static int __dredd_replace_expr_int(std::function arg, int local_mutation_id) { + if (!__dredd_some_mutation_enabled) return arg(); + if (__dredd_enabled_mutation(local_mutation_id + 0)) return !(arg()); + if (__dredd_enabled_mutation(local_mutation_id + 1)) return ~(arg()); + if (__dredd_enabled_mutation(local_mutation_id + 2)) return -(arg()); + if (__dredd_enabled_mutation(local_mutation_id + 3)) return 0; + if (__dredd_enabled_mutation(local_mutation_id + 4)) return 1; + if (__dredd_enabled_mutation(local_mutation_id + 5)) return -1; + return arg(); +} + +int main() { + int x = __dredd_replace_expr_int_zero(0, 0); + if (!__dredd_enabled_mutation(31)) { __dredd_replace_binary_operator_Assign_arg1_int_arg2_int(x , [&]() -> int { return static_cast((__dredd_replace_expr_int([&]() -> int { return static_cast((__dredd_replace_expr_int_zero(0, 2), __dredd_replace_expr_int([&]() -> int { return static_cast(__dredd_replace_unary_operator_PostInc_int([&]() -> int& { return static_cast(x); }, 4)); }, 9))); }, 15))); }, 21); } +} diff --git a/test/single_file/comma_side_effects.cc.noopt.expected b/test/single_file/comma_side_effects.cc.noopt.expected new file mode 100644 index 00000000..4fe5c605 --- /dev/null +++ b/test/single_file/comma_side_effects.cc.noopt.expected @@ -0,0 +1,95 @@ +#include +#include +#include +#include + + +#ifdef _MSC_VER +#define thread_local __declspec(thread) +#elif __APPLE__ +#define thread_local __thread +#endif + +static thread_local bool __dredd_some_mutation_enabled = true; +static bool __dredd_enabled_mutation(int local_mutation_id) { + static thread_local bool initialized = false; + static thread_local uint64_t enabled_bitset[1]; + if (!initialized) { + bool some_mutation_enabled = false; + const char* dredd_environment_variable = std::getenv("DREDD_ENABLED_MUTATION"); + if (dredd_environment_variable != nullptr) { + std::string contents(dredd_environment_variable); + while (true) { + size_t pos = contents.find(","); + std::string token = (pos == std::string::npos ? contents : contents.substr(0, pos)); + if (!token.empty()) { + int value = std::stoi(token); + int local_value = value - 0; + if (local_value >= 0 && local_value < 46) { + enabled_bitset[local_value / 64] |= (1 << (local_value % 64)); + some_mutation_enabled = true; + } + } + if (pos == std::string::npos) { + break; + } + contents.erase(0, pos + 1); + } + } + initialized = true; + __dredd_some_mutation_enabled = some_mutation_enabled; + } + return (enabled_bitset[local_mutation_id / 64] & (1 << (local_mutation_id % 64))) != 0; +} + +static int& __dredd_replace_binary_operator_Assign_arg1_int_arg2_int(int& arg1, std::function arg2, int local_mutation_id) { + if (!__dredd_some_mutation_enabled) return arg1 = arg2(); + if (__dredd_enabled_mutation(local_mutation_id + 0)) return arg1 += arg2(); + if (__dredd_enabled_mutation(local_mutation_id + 1)) return arg1 &= arg2(); + if (__dredd_enabled_mutation(local_mutation_id + 2)) return arg1 /= arg2(); + if (__dredd_enabled_mutation(local_mutation_id + 3)) return arg1 *= arg2(); + if (__dredd_enabled_mutation(local_mutation_id + 4)) return arg1 |= arg2(); + if (__dredd_enabled_mutation(local_mutation_id + 5)) return arg1 %= arg2(); + if (__dredd_enabled_mutation(local_mutation_id + 6)) return arg1 <<= arg2(); + if (__dredd_enabled_mutation(local_mutation_id + 7)) return arg1 >>= arg2(); + if (__dredd_enabled_mutation(local_mutation_id + 8)) return arg1 -= arg2(); + if (__dredd_enabled_mutation(local_mutation_id + 9)) return arg1 ^= arg2(); + return arg1 = arg2(); +} + +static int __dredd_replace_unary_operator_PostInc_int(std::function arg, int local_mutation_id) { + if (!__dredd_some_mutation_enabled) return arg()++; + if (__dredd_enabled_mutation(local_mutation_id + 0)) return arg()--; + if (__dredd_enabled_mutation(local_mutation_id + 1)) return ~arg(); + if (__dredd_enabled_mutation(local_mutation_id + 2)) return -arg(); + if (__dredd_enabled_mutation(local_mutation_id + 3)) return !arg(); + if (__dredd_enabled_mutation(local_mutation_id + 4)) return arg(); + return arg()++; +} + +static int __dredd_replace_expr_int(std::function arg, int local_mutation_id) { + if (!__dredd_some_mutation_enabled) return arg(); + if (__dredd_enabled_mutation(local_mutation_id + 0)) return !(arg()); + if (__dredd_enabled_mutation(local_mutation_id + 1)) return ~(arg()); + if (__dredd_enabled_mutation(local_mutation_id + 2)) return -(arg()); + if (__dredd_enabled_mutation(local_mutation_id + 3)) return 0; + if (__dredd_enabled_mutation(local_mutation_id + 4)) return 1; + if (__dredd_enabled_mutation(local_mutation_id + 5)) return -1; + return arg(); +} + +static int __dredd_replace_expr_int(int arg, int local_mutation_id) { + if (!__dredd_some_mutation_enabled) return arg; + if (__dredd_enabled_mutation(local_mutation_id + 0)) return !(arg); + if (__dredd_enabled_mutation(local_mutation_id + 1)) return ~(arg); + if (__dredd_enabled_mutation(local_mutation_id + 2)) return -(arg); + if (__dredd_enabled_mutation(local_mutation_id + 3)) return 0; + if (__dredd_enabled_mutation(local_mutation_id + 4)) return 1; + if (__dredd_enabled_mutation(local_mutation_id + 5)) return -1; + return arg; +} + +int main() { + int x = __dredd_replace_expr_int(0, 0); + if (!__dredd_enabled_mutation(45)) { __dredd_replace_binary_operator_Assign_arg1_int_arg2_int(x , [&]() -> int { return static_cast(__dredd_replace_expr_int([&]() -> int { return static_cast((__dredd_replace_expr_int([&]() -> int { return static_cast((__dredd_replace_expr_int(0, 6), __dredd_replace_expr_int([&]() -> int { return static_cast(__dredd_replace_unary_operator_PostInc_int([&]() -> int& { return static_cast(x); }, 12)); }, 17))); }, 23))); }, 29)); }, 35); } +} From 2ba43c573496a389dc8b683b3b9c3e9df11eab83 Mon Sep 17 00:00:00 2001 From: James Lee-Jones Date: Wed, 29 May 2024 21:41:59 +0100 Subject: [PATCH 3/5] Formatting --- src/dredd/src/main.cc | 38 ++++++++++++----------- src/libdredd/src/mutation_replace_expr.cc | 8 ++--- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/dredd/src/main.cc b/src/dredd/src/main.cc index a8f634a6..93687084 100644 --- a/src/dredd/src/main.cc +++ b/src/dredd/src/main.cc @@ -103,23 +103,25 @@ int main(int argc, const char** argv) { const int return_code = Tool.run(factory.get()); -// if (return_code == 0) { -// // Application of mutations was successful, so write out the mutation info -// // in JSON format. -// std::string json_string; -// auto json_options = google::protobuf::util::JsonOptions(); -// json_options.add_whitespace = true; -// json_options.always_print_primitive_fields = true; -// auto json_generation_status = google::protobuf::util::MessageToJsonString( -// mutation_info, &json_string, json_options); -// if (json_generation_status.ok()) { -// std::ofstream transformations_json_file(mutation_info_file); -// transformations_json_file << json_string; -// } else { -// llvm::errs() << "Error writing JSON data to " << mutation_info_file -// << "\n"; -// return 1; -// } -// } + // if (return_code == 0) { + // // Application of mutations was successful, so write out the mutation + // info + // // in JSON format. + // std::string json_string; + // auto json_options = google::protobuf::util::JsonOptions(); + // json_options.add_whitespace = true; + // json_options.always_print_primitive_fields = true; + // auto json_generation_status = + // google::protobuf::util::MessageToJsonString( + // mutation_info, &json_string, json_options); + // if (json_generation_status.ok()) { + // std::ofstream transformations_json_file(mutation_info_file); + // transformations_json_file << json_string; + // } else { + // llvm::errs() << "Error writing JSON data to " << mutation_info_file + // << "\n"; + // return 1; + // } + // } return return_code; } diff --git a/src/libdredd/src/mutation_replace_expr.cc b/src/libdredd/src/mutation_replace_expr.cc index 0e864587..9c6808c0 100644 --- a/src/libdredd/src/mutation_replace_expr.cc +++ b/src/libdredd/src/mutation_replace_expr.cc @@ -530,10 +530,10 @@ void MutationReplaceExpr::ReplaceExprWithFunctionCall( if (ast_context.getLangOpts().CPlusPlus && expr_->HasSideEffects(ast_context)) { prefix.append(+"[&]() -> " + input_type + " { return " + - // We don't need to static cast constant expressions - (IsCxx11ConstantExpr(*expr_, ast_context) - ? "" - : "static_cast<" + input_type + ">(")); + // We don't need to static cast constant expressions + (IsCxx11ConstantExpr(*expr_, ast_context) + ? "" + : "static_cast<" + input_type + ">(")); suffix.append(IsCxx11ConstantExpr(*expr_, ast_context) ? "" : ")"); suffix.append("; }"); } From dd414429b7ebda50b314da6e8cf637abbbd5861e Mon Sep 17 00:00:00 2001 From: James Lee-Jones Date: Wed, 29 May 2024 21:48:18 +0100 Subject: [PATCH 4/5] Remove comments --- src/dredd/src/main.cc | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/src/dredd/src/main.cc b/src/dredd/src/main.cc index 93687084..4e20ba48 100644 --- a/src/dredd/src/main.cc +++ b/src/dredd/src/main.cc @@ -103,25 +103,23 @@ int main(int argc, const char** argv) { const int return_code = Tool.run(factory.get()); - // if (return_code == 0) { - // // Application of mutations was successful, so write out the mutation - // info - // // in JSON format. - // std::string json_string; - // auto json_options = google::protobuf::util::JsonOptions(); - // json_options.add_whitespace = true; - // json_options.always_print_primitive_fields = true; - // auto json_generation_status = - // google::protobuf::util::MessageToJsonString( - // mutation_info, &json_string, json_options); - // if (json_generation_status.ok()) { - // std::ofstream transformations_json_file(mutation_info_file); - // transformations_json_file << json_string; - // } else { - // llvm::errs() << "Error writing JSON data to " << mutation_info_file - // << "\n"; - // return 1; - // } - // } + if (return_code == 0) { + // Application of mutations was successful, so write out the mutation info + // in JSON format. + std::string json_string; + auto json_options = google::protobuf::util::JsonOptions(); + json_options.add_whitespace = true; + json_options.always_print_primitive_fields = true; + auto json_generation_status = google::protobuf::util::MessageToJsonString( + mutation_info, &json_string, json_options); + if (json_generation_status.ok()) { + std::ofstream transformations_json_file(mutation_info_file); + transformations_json_file << json_string; + } else { + llvm::errs() << "Error writing JSON data to " << mutation_info_file + << "\n"; + return 1; + } + } return return_code; } From 1a81e339d57cf5a934605cb3fe08f962b588841d Mon Sep 17 00:00:00 2001 From: James Lee-Jones Date: Fri, 5 Jul 2024 12:38:17 +0100 Subject: [PATCH 5/5] Update comma op explination --- src/libdredd/src/mutation_replace_expr.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libdredd/src/mutation_replace_expr.cc b/src/libdredd/src/mutation_replace_expr.cc index 9c6808c0..32d18c42 100644 --- a/src/libdredd/src/mutation_replace_expr.cc +++ b/src/libdredd/src/mutation_replace_expr.cc @@ -545,7 +545,7 @@ void MutationReplaceExpr::ReplaceExprWithFunctionCall( } if (const auto* binary_expr = llvm::dyn_cast(expr_)) { - // The comma operator requires special care in C, to avoid it appearing to + // The comma operator requires special care to avoid it appearing to // provide multiple parameters for an enclosing function call. if (binary_expr->isCommaOp()) { prefix.append("(");