diff --git a/src/libdredd/src/mutation_replace_expr.cc b/src/libdredd/src/mutation_replace_expr.cc index 79f358e2..6fae9685 100644 --- a/src/libdredd/src/mutation_replace_expr.cc +++ b/src/libdredd/src/mutation_replace_expr.cc @@ -583,6 +583,30 @@ void MutationReplaceExpr::ReplaceExprWithFunctionCall( GetSourceRangeInMainFile(preprocessor, *expr_); assert(expr_source_range_in_main_file.isValid() && "Invalid source range."); + { + // Insert a space before the function call if the preceding character could + // belong to an identifier. This is to guard against the case where the + // expression being mutated comes right after a macro. If this happens, then + // unless a space is added, the function name gets conjoined onto the macro + // name, leading to invalid code. + bool is_invalid = false; + const char* pointer_to_character_before_location = + ast_context.getSourceManager().getCharacterData( + expr_source_range_in_main_file.getBegin().getLocWithOffset(-1), + &is_invalid); + if (!is_invalid) { + // There is a previous character. Check whether it is alphanumeric, or an + // underscore. + const char character_before_location = + pointer_to_character_before_location[0]; + if (character_before_location == '_' || + static_cast(std::isalnum(character_before_location))) { + // A space is needed. + prefix = " " + prefix; + } + } + } + bool rewriter_result = rewriter.InsertTextBefore( expr_source_range_in_main_file.getBegin(), prefix); assert(!rewriter_result && "Rewrite failed.\n"); diff --git a/test/single_file/space_needed_after_macro.c b/test/single_file/space_needed_after_macro.c new file mode 100644 index 00000000..d152556e --- /dev/null +++ b/test/single_file/space_needed_after_macro.c @@ -0,0 +1,6 @@ +#define BEGIN x = + +int main() { + int x, y; + BEGIN(y); +} diff --git a/test/single_file/space_needed_after_macro.c.expected b/test/single_file/space_needed_after_macro.c.expected new file mode 100644 index 00000000..31afb38c --- /dev/null +++ b/test/single_file/space_needed_after_macro.c.expected @@ -0,0 +1,59 @@ +#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(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; +} + +#define BEGIN x = + +int main() { + int x, y; + if (!__dredd_enabled_mutation(6)) { BEGIN __dredd_replace_expr_int((y), 0); } +} diff --git a/test/single_file/space_needed_after_macro.c.noopt.expected b/test/single_file/space_needed_after_macro.c.noopt.expected new file mode 100644 index 00000000..943637f4 --- /dev/null +++ b/test/single_file/space_needed_after_macro.c.noopt.expected @@ -0,0 +1,66 @@ +#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 < 15) { + 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_lvalue(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)); + 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; +} + +#define BEGIN x = + +int main() { + int x, y; + if (!__dredd_enabled_mutation(14)) { __dredd_replace_expr_int(BEGIN __dredd_replace_expr_int( __dredd_replace_expr_int_lvalue(&((y)), 0), 2), 8); } +} diff --git a/test/single_file/space_needed_after_macro2.c b/test/single_file/space_needed_after_macro2.c new file mode 100644 index 00000000..9d38c24a --- /dev/null +++ b/test/single_file/space_needed_after_macro2.c @@ -0,0 +1,6 @@ +#define BEGIN_ x = + +int main() { + int x, y; + BEGIN_(y); +} diff --git a/test/single_file/space_needed_after_macro2.c.expected b/test/single_file/space_needed_after_macro2.c.expected new file mode 100644 index 00000000..e959ab7a --- /dev/null +++ b/test/single_file/space_needed_after_macro2.c.expected @@ -0,0 +1,59 @@ +#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(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; +} + +#define BEGIN_ x = + +int main() { + int x, y; + if (!__dredd_enabled_mutation(6)) { BEGIN_ __dredd_replace_expr_int((y), 0); } +} diff --git a/test/single_file/space_needed_after_macro2.c.noopt.expected b/test/single_file/space_needed_after_macro2.c.noopt.expected new file mode 100644 index 00000000..5f0b206d --- /dev/null +++ b/test/single_file/space_needed_after_macro2.c.noopt.expected @@ -0,0 +1,66 @@ +#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 < 15) { + 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_lvalue(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)); + 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; +} + +#define BEGIN_ x = + +int main() { + int x, y; + if (!__dredd_enabled_mutation(14)) { __dredd_replace_expr_int(BEGIN_ __dredd_replace_expr_int( __dredd_replace_expr_int_lvalue(&((y)), 0), 2), 8); } +}