/* * 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. */ #include void init(int* i) { *i = 10; } void init_bool(bool* i) { *i = false; } void no_init(int* i) {} void no_init_bool(bool* i) {} int inc(int x) { return x + 1; } // error is detected before call as we copy x // so no need to put it in the summary int no_init_return_bad() { int x; return x; // error } int bad1() { int a; int b = a; // Error int c = b; // Error but we do not report as it depends from line 20 return c; } int ok3() { int a; int c; init(&a); c = a; // no report since the variable could be initialized when passed by // reference in previous call return c; } int ok4() { int a; int c; init(&a); c = inc(a); // no report since the variable could be initialized when passed // by reference in previous call return c; } void square_init(int x, int& res) { res = x * x; } int square_no_init(int x, int& res) { return res * res; } void use_square_ok1() { int i; square_init(2, i); // OK since i is initialized when passed by reference } int use_square_ok2() { int i; i = square_no_init(2, i); // OK only for intraprocedural case. When analysis // extended to interprocedural, it should report. return i; } bool getOK(void); int branch1_FP() { int size; bool ok = getOK(); if (ok) { size = 1; } if (ok) { return size; // report here because size initialized only on the then-branch // above } return 0; } int loop1_FP() { int size; for (;;) { size = 1; if (getOK()) break; } return size; // report here because size initialized only inside loop } int ok6() { int x; x = 7; return x; } // this crashes HIL if we're not careful void deref_magic_addr_ok() { *(int*)0xdeadbeef = 0; } char ok7() { char buf[1024], *res = buf; // OK, because we copy an address res[1] = 'a'; return res[1]; } void use_an_int(int); void bad2() { int a; use_an_int(a); // Report as we pass an unitialized value } void ok8() { int a; init(&a); // no report since the variable could be initialized when passed by // reference. } struct A { int* ptr; int value; }; void ok9() { int i; A a; a.ptr = &i; // no report since the variable could be initialized when passed // by reference. init(a.ptr); } int field_passed_by_ref_ok() { A a; init(&a.value); return a.value; } void init_double_pointer(int**); int pointer_passed_by_ref_ok() { int* i; init_double_pointer(&i); return *i; } int array_initialized_ok(int N, int index) { int array[N]; std::fill_n(array, N, 0.0f); int value = array[index]; return value; } int array_element_passed_by_ref_ok() { int array[1]; init(&(array[0])); int value = array[0]; return value; } int ret_undef_bad() { int* p; return *p; // report as p was not initialized } int copy_pointer_bad() { int* p; int* q; p = q; // error return *p; } void use_an_int2(int*); int ok10() { int buf[1024]; use_an_int2(buf); // no report as we pass the pointer to buf return 1; } void FN_capture_read_bad() { int x; [x]() { int y = x; return; }(); // We should report that captured x is not init } void init_capture_read_ok() { int x; [x = 0]() { int y = x; return; }(); } void init_capture_ok() { [i = 0]() { return i; }; } void FN_capture_by_ref_reuseBad() { int x; [&x]() { int y = x; }(); // We don't report here as we only do intraprocedural analysis for now } int capture_by_ref_init_FP() { int x; [&x]() { x = 1; }(); return x; } int capture_by_ref_init2_FP() { int x; auto lambda = [&x]() { x = 1; }; lambda(); return x; } int no_warning_on_throw_ok(bool t) { int x; if (t) { x = 2; } else { throw; } return x; } int warning_when_throw_in_other_branch_bad(int t) { int x; if (t > 0) { x = 2; } else if (t < 0) { // reports because x is not initialized in this branch } else { throw; } return x; } [[noreturn]] void noreturn_function() {} int FP_no_warning_noreturn_callee_ok(bool t) { int x; if (t) { x = 2; } else { noreturn_function(); } return x; } void some_f(void* p); int* FP_pointer_param_void_star_ok() { A a; int* res; some_f(&a); // the type of a here is void*, hence no fields are found return a.ptr; // false positive } short union_ok() { union { int* a; short* b; } u; init(u.a); short* p = u.b; return *p; } int condition_no_init_bad() { int x; if (x) { return 1; } return 0; } void call_to_fn_ptr_with_init_arg_good(void (*f)(int)) { int a = 42; f(a); } void FN_call_to_fn_ptr_with_uninit_arg_bad(void (*f)(int)) { int a; f(a); } void call_to_init_fn_ptr_good() { void (*f)(); f = use_square_ok1; f(); } void call_to_init_fn_ptr2_good(bool nondet) { void (*f)(); if (nondet) f = use_square_ok1; else f = deref_magic_addr_ok; f(); } void FN_call_to_uninit_fn_ptr_bad() { void (*f)(); f(); } void FN_call_to_maybe_uninit_fn_ptr_bad(bool nondet) { void (*f)(); if (nondet) f = use_square_ok1; f(); }