Skip to content

Commit

Permalink
Avoid problem with macro expansion
Browse files Browse the repository at this point in the history
Insert a space when mutating an expression directly after a macro
expansion.

Fixes #239.
  • Loading branch information
afd committed Jul 5, 2024
1 parent 76466d1 commit 3eca110
Show file tree
Hide file tree
Showing 7 changed files with 286 additions and 0 deletions.
24 changes: 24 additions & 0 deletions src/libdredd/src/mutation_replace_expr.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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<bool>(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");
Expand Down
6 changes: 6 additions & 0 deletions test/single_file/space_needed_after_macro.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#define BEGIN x =

int main() {
int x, y;
BEGIN(y);
}
59 changes: 59 additions & 0 deletions test/single_file/space_needed_after_macro.c.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#include <inttypes.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>

#ifdef _MSC_VER
#define thread_local __declspec(thread)
#elif __APPLE__
#define thread_local __thread
#else
#include <threads.h>
#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); }
}
66 changes: 66 additions & 0 deletions test/single_file/space_needed_after_macro.c.noopt.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#include <inttypes.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>

#ifdef _MSC_VER
#define thread_local __declspec(thread)
#elif __APPLE__
#define thread_local __thread
#else
#include <threads.h>
#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); }
}
6 changes: 6 additions & 0 deletions test/single_file/space_needed_after_macro2.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#define BEGIN_ x =

int main() {
int x, y;
BEGIN_(y);
}
59 changes: 59 additions & 0 deletions test/single_file/space_needed_after_macro2.c.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#include <inttypes.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>

#ifdef _MSC_VER
#define thread_local __declspec(thread)
#elif __APPLE__
#define thread_local __thread
#else
#include <threads.h>
#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); }
}
66 changes: 66 additions & 0 deletions test/single_file/space_needed_after_macro2.c.noopt.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#include <inttypes.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>

#ifdef _MSC_VER
#define thread_local __declspec(thread)
#elif __APPLE__
#define thread_local __thread
#else
#include <threads.h>
#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); }
}

0 comments on commit 3eca110

Please sign in to comment.