mc-imperial / dredd

Framework for evaluating C/C++ compiler testing tools
Apache License 2.0
11 stars 3 forks source link

Mutation of expression used in initializer list results in ill-formed program #270

Closed JonathanFoo0523 closed 1 month ago

JonathanFoo0523 commented 1 month ago

Applying Dredd to

#include <initializer_list>
#include <cstdint>

template <typename T> class foo {
public:
  foo(std::initializer_list<T>) {}
};

int main() { 
    foo<uint64_t>{+2}; 
}

change the sole statement in main() to

if (!__dredd_enabled_mutation(5)) { foo<uint64_t>{+__dredd_replace_expr_int_constant(2, 0)}; } 

This causes the following compilation error:

non-constant-expression cannot be narrowed from type 'int' to 'unsigned long' in initializer list
JonathanFoo0523 commented 1 month ago

Note that + in +2 is required to replicate the issue. Otherwise, Dredd will not mutate the expression 2, and thus avoid this issue.

JonathanFoo0523 commented 1 month ago

While we can reduce this bug by avoiding mutation of expression in such case, I think this approach will further reduce the number of mutants.

Is it possible to change the prelude function to a templated version

template <typename T> 
static T __dredd_replace_expr_int_like_constant(T 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 0;
  if (__dredd_enabled_mutation(local_mutation_id + 3)) return 1;
  if (__dredd_enabled_mutation(local_mutation_id + 4)) return -1;
  return arg;
}

and mutate the fault-causing expression to:

+__dredd_replace_expr_int_like_constant<uint64_t>(2, 0)
afd commented 1 month ago

I am worried that having templated mutator functions may end up getting very complicated and leading to unexpected issues. On the other hand, it might actually turn out to provide a simple and elegant solution to certain issues. @JonathanFoo0523 can you experiment with the template idea?

If it turns out to be non-trivial then I would prefer to work around this by detecting the special case and avoiding a mutation in that special case, and opening a "stretch goal" issue to consider a better solution in the longer term.

JonathanFoo0523 commented 1 month ago

A slightly simpler example

#include <initializer_list>

class foo {
public:
  foo(std::initializer_list<unsigned int>) {}
};

int main() { 
    foo{+2}; 
}
JonathanFoo0523 commented 1 month ago

Another Example:

struct a {
  short b;
};
a c() { return {6 * 4}; }