int user_input(); void sink(int); struct S { int m1, m2; }; void pointerSetter(S *s) { s->m1 = user_input(); } void referenceSetter(S &s) { s.m1 = user_input(); } void copySetter(S s) { s.m1 = user_input(); } void callSetters() { S s1 = { 0, 0 }; S s2 = { 0, 0 }; S s3 = { 0, 0 }; pointerSetter(&s1); referenceSetter(s2); copySetter(s3); sink(s1.m1); // $ ast,ir sink(s2.m1); // $ ast,ir sink(s3.m1); // no flow } void assignAfterAlias() { S s1 = { 0, 0 }; S &ref1 = s1; ref1.m1 = user_input(); sink(s1.m1); // $ MISSING: ast,ir S s2 = { 0, 0 }; S &ref2 = s2; s2.m1 = user_input(); sink(ref2.m1); // $ MISSING: ast,ir } void assignAfterCopy() { S s1 = { 0, 0 }; S copy1 = s1; copy1.m1 = user_input(); sink(s1.m1); // no flow S s2 = { 0, 0 }; S copy2 = s2; s2.m1 = user_input(); sink(copy2.m1); // no flow } void assignBeforeCopy() { S s2 = { 0, 0 }; s2.m1 = user_input(); S copy2 = s2; sink(copy2.m1); // $ ast,ir } struct Wrapper { S s; }; void copyIntermediate() { Wrapper w = { { 0, 0 } }; S s = w.s; s.m1 = user_input(); sink(w.s.m1); // no flow } void pointerIntermediate() { Wrapper w = { { 0, 0 } }; S *s = &w.s; s->m1 = user_input(); sink(w.s.m1); // $ MISSING: ast,ir } void referenceIntermediate() { Wrapper w = { { 0, 0 } }; S &s = w.s; s.m1 = user_input(); sink(w.s.m1); // $ MISSING: ast,ir } void nestedAssign() { Wrapper w = { { 0, 0 } }; w.s.m1 = user_input(); sink(w.s.m1); // $ ast,ir } void addressOfField() { S s; s.m1 = user_input(); S s_copy = s; int* px = &s_copy.m1; sink(*px); // $ ir MISSING: ast } void taint_a_ptr(int* pa) { *pa = user_input(); } void test_field_conflation_array_content() { S s; taint_a_ptr(&s.m1); sink(s.m2); } struct S_with_pointer { int m1, m2; int* data; }; void pointer_deref(int* xs) { taint_a_ptr(xs); sink(xs[0]); // $ ir MISSING: ast } void pointer_deref_sub(int* xs) { taint_a_ptr(xs - 2); sink(*(xs - 2)); // $ ir MISSING: ast } void pointer_many_addrof_and_deref(int* xs) { taint_a_ptr(xs); sink(*&*&*xs); // $ ir MISSING: ast } void pointer_unary_plus(int* xs) { taint_a_ptr(+xs); sink(*+xs); // $ ir MISSING: ast } void pointer_member_index(S_with_pointer s) { taint_a_ptr(s.data); // `s.data` is points to all-aliased-memory sink(s.data[0]); // $ ir MISSING: ast } void member_array_different_field(S_with_pointer* s) { taint_a_ptr(&s[0].m1); sink(s[0].m2); } struct S_with_array { int m1, m2; int data[10]; }; void pointer_member_deref() { S_with_array s; taint_a_ptr(s.data); sink(*s.data); // $ ast,ir } void array_member_deref() { S_with_array s; taint_a_ptr(s.data); sink(s.data[0]); // $ ast,ir } struct S2 { S s; int m3; }; void deep_member_field_dot() { S2 s2; taint_a_ptr(&s2.s.m1); sink(s2.s.m1); // $ ir,ast } void deep_member_field_dot_different_fields() { S2 s2; taint_a_ptr(&s2.s.m1); sink(s2.s.m2); } void deep_member_field_dot_2() { S2 s2; taint_a_ptr(&s2.s.m1); S2 s2_2 = s2; sink(s2_2.s.m1); // $ ir,ast } void deep_member_field_dot_different_fields_2() { S2 s2; taint_a_ptr(&s2.s.m1); S2 s2_2 = s2; sink(s2_2.s.m2); } void deep_member_field_arrow(S2 *ps2) { taint_a_ptr(&ps2->s.m1); sink(ps2->s.m1); // $ ir,ast } void deep_member_field_arrow_different_fields(S2 *ps2) { taint_a_ptr(&ps2->s.m1); sink(ps2->s.m2); } namespace GlobalFieldFlow { S global_s; S2 global_s2; void set_field() { global_s.m1 = user_input(); } void read_field() { sink(global_s.m1); // $ ir MISSING: ast } void set_nested_field() { global_s2.s.m1 = user_input(); } void read_nested_field() { sink(global_s2.s.m1); // $ ir MISSING: ast } S* global_s_ptr; S2* global_s2_ptr; void set_field_ptr() { global_s_ptr->m1 = user_input(); } void read_field_ptr() { sink(global_s_ptr->m1); // $ ir MISSING: ast } void set_nested_field_ptr() { global_s2_ptr->s.m1 = user_input(); } void read_nested_field_ptr() { sink(global_s2_ptr->s.m1); // $ ir MISSING: ast } S_with_pointer global_s_with_pointer; void set_field_indirect() { *global_s_with_pointer.data = user_input(); } void read_field_indirect() { sink(*global_s_with_pointer.data); // $ ir MISSING: ast } S_with_array global_s_with_array; void set_field_array() { *global_s_with_array.data = user_input(); } void read_field_array() { sink(*global_s_with_array.data); // $ ir MISSING: ast } }