/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ struct X { int f; }; void skip(struct X& x) {} void skip_ptr(struct X* x) {} int wraps_read_inner(struct X& x) { return x.f; } int wraps_read(struct X& x) { return wraps_read_inner(x); } void wraps_write_inner(struct X& x, int i) { x.f = i; } void wraps_write(struct X& x, int i) { wraps_write_inner(x, i); } void wraps_delete_inner(struct X* x) { delete x; } void wraps_delete(struct X* x) { wraps_delete_inner(x); } void delete_then_skip_ok(struct X& x) { delete (&x); skip(x); } void delete_then_skip_ptr_ok(struct X* x) { delete x; skip_ptr(x); } void delete_then_read_bad(struct X& x) { delete (&x); wraps_read(x); } void delete_aliased_then_read_bad(struct X& x) { struct X* y = &x; struct X& z = x; delete y; wraps_read(z); } void delete_then_write_bad(struct X& x) { wraps_delete(&x); wraps_read(x); } void delete_inner_then_write_bad(struct X& x) { wraps_delete_inner(&x); wraps_read(x); } // latent because delete(&x) creates a path where &x==0 but it was dereferences // before, but that does not make sense as &x cannot be null void FP_latent_read_write_then_delete_ok(struct X& x) { wraps_write(x, 10); wraps_read(x); wraps_delete(&x); } int two_cells(struct X* x, struct X* y) { x->f = 32; y->f = 52; return x->f * y->f; } void aliasing_call(struct X* x) { two_cells(x, x); } struct Y { int* p; }; void store(struct Y* y, int* p) { y->p = p; } void call_store(struct Y* y) { int x = 42; store(y, &x); } extern bool nondet_choice(); struct Y* may_return_invalid_ptr_ok() { struct Y* y = new Y(); if (nondet_choice()) { delete y; } return y; } void feed_invalid_into_access_bad() { struct Y* y = may_return_invalid_ptr_ok(); call_store(y); } void invalidate_and_set_to_null(struct X** x_ptr) { delete (*x_ptr); *x_ptr = nullptr; } void access_to_invalidated_alias_bad(struct X* x, struct X* y) { y = x; invalidate_and_set_to_null(&x); wraps_read(*y); } void access_to_invalidated_alias2_bad(struct X* x, struct X* y) { y = x; invalidate_and_set_to_null(&y); wraps_read(*x); } void set_first_non_null_ok(int* x, int* y) { if (x) { *x = 42; } else { *y = 42; } } // should get two latent issues here, or at least one for the dereference of // [p=nullptr] void set_x_then_crash_double_latent(int* x) { set_first_non_null_ok(x, nullptr); set_first_non_null_ok(nullptr, x); int* p = nullptr; *p = 42; }