(please keep me in CC, I'm not subscribed...) On Thu Feb 18, 2021 Qing Zhao said: > Initialize automatic variables with new first class option > -ftrivial-auto-var-init=[uninitialized|pattern|zero]
Yay! I'm really excited to see this. Thank you for working on it! I've built GCC with this applied, and it works out of the box for a Linux kernel build, which correctly detects the availability of -ftrivial-auto-var-init=[pattern|zero] for the respective CONFIG_INIT_STACK_ALL_PATTERN and CONFIG_INIT_STACK_ALL_ZERO options. The output from the kernel's CONFIG_TEST_STACKINIT module shows coverage for most uninitialized cases. Yay! :) It looks like there is still some issues with padding and pre-case switch variables. Here's the test output, FWIW: test_stackinit: u8_zero ok test_stackinit: u16_zero ok test_stackinit: u32_zero ok test_stackinit: u64_zero ok test_stackinit: char_array_zero ok test_stackinit: small_hole_zero ok test_stackinit: big_hole_zero ok test_stackinit: trailing_hole_zero ok test_stackinit: packed_zero ok test_stackinit: small_hole_dynamic_partial ok test_stackinit: big_hole_dynamic_partial ok test_stackinit: trailing_hole_dynamic_partial ok test_stackinit: packed_dynamic_partial ok test_stackinit: small_hole_static_partial ok test_stackinit: big_hole_static_partial ok test_stackinit: trailing_hole_static_partial ok test_stackinit: packed_static_partial ok test_stackinit: small_hole_static_all FAIL (uninit bytes: 3) test_stackinit: big_hole_static_all FAIL (uninit bytes: 61) test_stackinit: trailing_hole_static_all FAIL (uninit bytes: 7) test_stackinit: packed_static_all ok test_stackinit: small_hole_dynamic_all FAIL (uninit bytes: 3) test_stackinit: big_hole_dynamic_all FAIL (uninit bytes: 61) test_stackinit: trailing_hole_dynamic_all FAIL (uninit bytes: 7) test_stackinit: packed_dynamic_all ok test_stackinit: small_hole_runtime_partial ok test_stackinit: big_hole_runtime_partial ok test_stackinit: trailing_hole_runtime_partial ok test_stackinit: packed_runtime_partial ok test_stackinit: small_hole_runtime_all ok test_stackinit: big_hole_runtime_all ok test_stackinit: trailing_hole_runtime_all ok test_stackinit: packed_runtime_all ok test_stackinit: u8_none ok test_stackinit: u16_none ok test_stackinit: u32_none ok test_stackinit: u64_none ok test_stackinit: char_array_none ok test_stackinit: switch_1_none FAIL (uninit bytes: 8) test_stackinit: switch_2_none FAIL (uninit bytes: 8) test_stackinit: small_hole_none ok test_stackinit: big_hole_none ok test_stackinit: trailing_hole_none ok test_stackinit: packed_none ok test_stackinit: user ok test_stackinit: failures: 8 The kernel's test for this is a mess[1] of macros I used to avoid losing my sanity from cut/pasting, but it makes the tests hard to read. To break it out, the failing cases are due to padding, as seen with the "test_small_hole", "test_big_hole", and "test_trailing_hole" structures: /* Simple structure with padding likely to be covered by compiler. */ struct test_small_hole { size_t one; char two; /* 3 byte padding hole here. */ int three; unsigned long four; }; /* Try to trigger unhandled padding in a structure. */ struct test_aligned { u32 internal1; u64 internal2; } __aligned(64); struct test_big_hole { u8 one; u8 two; u8 three; /* 61 byte padding hole here. */ struct test_aligned four; } __aligned(64); struct test_trailing_hole { char *one; char *two; char *three; char four; /* "sizeof(unsigned long) - 1" byte padding hole here. */ }; They fail when they're statically initialized (either fully or partially), for example: struct test_..._hole instance = { .two = ..., }; or struct test_..._hole instance = { .one = ..., .two = ..., .three = ..., .four = ..., }; The last case is for switch variables outside of case statements, like "var" here: switch (path) { unsigned long var; case ..: ... case ..: ... ... } I'm really looking forward to having this available. Thanks again! -Kees [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/lib/test_stackinit.c -- Kees Cook