https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109614
Bug ID: 109614 Summary: -Wanalyzer-use-after-free gets confused about a free function in Coreutils Product: gcc Version: 13.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: analyzer Assignee: dmalcolm at gcc dot gnu.org Reporter: eggert at cs dot ucla.edu Target Milestone: --- Created attachment 54915 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=54915&action=edit bug reproducer This is (GCC) 13.0.1 20230401 (Red Hat 13.0.1-0) on x86-64. Compile the attached file (derived from GNU coreutils csplit) with: gzip -d a.i.gz gcc -fanalyzer -S a.i The first warning is a false positive. As near as I can make out, -fanalyzer got confused and is treating free_buffer as if it calls itself or was called twice, which is obviously wrong (the diagnostic is confusing at any rate). The full set of diagnostics is shown below. a.i: In function ‘free_buffer’: a.i:4491:21: warning: use after ‘free_buffer’ of ‘buf’ [CWE-416] [-Wanalyzer-use-after-free] 4491 | for (struct line *l = buf->line_start; l;) | ^ ‘main’: events 1-6 | | 5509 | main (int argc, char **argv) | | ^~~~ | | | | | (1) entry to ‘main’ |...... | 5588 | if (argc - optind < 2) | | ~ | | | | | (2) following ‘false’ branch... |...... | 5598 | idx_t prefix_len = strlen (prefix); | | ~~~~~~~~~~~~~~~ | | | | | (3) ...to here |...... | 5616 | if (__builtin_add_overflow (prefix_len, max_digit_string_len + 1, &filename_size)) | | ~ | | | | | (4) following ‘false’ branch... | 5617 | xalloc_die (); | 5618 | filename_space = ximalloc (filename_size); | | ~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (5) ...to here | 5619 | set_input_file (argv[optind++]); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (6) calling ‘set_input_file’ from ‘main’ | +--> ‘set_input_file’: events 7-11 | | 4708 | set_input_file (char const *name) | | ^~~~~~~~~~~~~~ | | | | | (7) entry to ‘set_input_file’ | 4709 | { | 4710 | if (! (strcmp (name, "-") == 0) && fd_reopen ( | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | | | | | (9) ...to here | | | (10) following ‘false’ branch... | | (8) following ‘true’ branch (when the strings are non-equal)... | 4711 | 0 | | ~ | 4712 | , name, | | ~~~~~~~ | 4713 | 00 | | ~~ | 4714 | , 0) < 0) | | ~~~~~~~~ |...... | 4731 | } | | ~ | | | | | (11) ...to here | <------+ | ‘main’: events 12-21 | | 5619 | set_input_file (argv[optind++]); | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (12) returning to ‘main’ from ‘set_input_file’ |...... | 5651 | for (i = 0; i < nsigs; i++) | | ~~~~~~~~~ | | | | | (13) following ‘true’ branch (when ‘i <= 10’)... | | (15) following ‘true’ branch (when ‘i <= 10’)... | 5652 | { | 5653 | sigaction (sig[i], | | ~~~~~~ | | | | | (14) ...to here | | (16) ...to here |...... | 5668 | for (i = 0; i < nsigs; i++) | | ~~~~~~~~~ | | | | | (17) following ‘true’ branch (when ‘i <= 10’)... | | (19) following ‘true’ branch (when ‘i <= 10’)... | 5669 | if (sigismember (&caught_signals, sig[i])) | | ~~~~~~ | | | | | (18) ...to here | | (20) ...to here |...... | 5674 | split_file (); | | ~~~~~~~~~~~~~ | | | | | (21) calling ‘split_file’ from ‘main’ | +--> ‘split_file’: events 22-29 | | 4953 | split_file (void) | | ^~~~~~~~~~ | | | | | (22) entry to ‘split_file’ | 4954 | { | 4955 | for (idx_t i = 0; i < control_used; i++) | | ~~~~~~~~~~~~~~~~ | | | | | (23) following ‘true’ branch... |...... | 4958 | if (controls[i].regexpr) | | ~ ~ | | | | | | | (24) ...to here | | (25) following ‘true’ branch... | 4959 | { | 4960 | for (j = 0; (controls[i].repeat_forever | | ~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (26) ...to here | 4961 | || j <= controls[i].repeat); j++) | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (27) following ‘true’ branch... | 4962 | process_regexp (&controls[i], j); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (28) ...to here | | (29) calling ‘process_regexp’ from ‘split_file’ | +--> ‘process_regexp’: events 30-33 | | 4845 | process_regexp (struct control *p, intmax_t repetition) | | ^~~~~~~~~~~~~~ | | | | | (30) entry to ‘process_regexp’ |...... | 4853 | if (!ignore) | | ~ | | | | | (31) following ‘true’ branch... | 4854 | create_output_file (); | | ~~~~~~~~~~~~~~~~~~~~~ | | | | | (32) ...to here | | (33) calling ‘create_output_file’ from ‘process_regexp’ | +--> ‘create_output_file’: events 34-38 | | 4986 | create_output_file (void) | | ^~~~~~~~~~~~~~~~~~ | | | | | (34) entry to ‘create_output_file’ |...... | 4993 | if (nfiles == 0x7fffffff | | ~ | | | | | (35) following ‘false’ branch (when ‘nfiles != 2147483647’)... |...... | 5006 | sigprocmask ( | | ~~~~~~~~~~~~~ | | | | | (36) ...to here | 5007 | 0 | | ~ | 5008 | , &caught_signals, &oldset); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ |...... | 5023 | if (! fopen_ok) | | ~ | | | | | (37) following ‘false’ branch... |...... | 5028 | bytes_written = 0; | | ~~~~~~~~~~~~~~~~~ | | | | | (38) ...to here | <------+ | ‘process_regexp’: events 39-42 | | 4854 | create_output_file (); | | ^~~~~~~~~~~~~~~~~~~~~ | | | | | (39) returning to ‘process_regexp’ from ‘create_output_file’ | 4855 | if (p->offset >= 0) | | ~ | | | | | (40) following ‘true’ branch... |...... | 4861 | line = find_line (++current_line); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (41) ...to here | | (42) calling ‘find_line’ from ‘process_regexp’ | +--> ‘find_line’: events 43-46 | | 4654 | find_line (intmax_t linenum) | | ^~~~~~~~~ | | | | | (43) entry to ‘find_line’ |...... | 4657 | if (head == | | ~ | | | | | (44) following ‘true’ branch... | 4658 | ((void *)0) | 4659 | && !load_buffer ()) | | ~~~~~~~~~~~~~~ | | | | | (45) ...to here | | (46) calling ‘load_buffer’ from ‘find_line’ | +--> ‘load_buffer’: events 47-50 | | 4542 | load_buffer (void) | | ^~~~~~~~~~~ | | | | | (47) entry to ‘load_buffer’ | 4543 | { | 4544 | if (have_read_eof) | | ~ | | | | | (48) following ‘false’ branch... |...... | 4549 | ((( | | ~~~ | 4550 | 8191 | | ~~~~ | 4551 | )>( | | ~~~ | 4552 | hold_count + 1 | | ~~~~~~~~~~~~~~ | 4553 | ))?( | | ~~~~ | 4554 | 8191 | | ~~~~ | 4555 | ):( | | ~~~ | | | | | (49) ...to here | 4556 | hold_count + 1 | | ~~~~~~~~~~~~~~ | 4557 | )) | | ~~ |...... | 4563 | struct buffer_record *b = get_new_buffer (bytes_wanted); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (50) calling ‘get_new_buffer’ from ‘load_buffer’ | +--> ‘get_new_buffer’: events 51-52 | | 4502 | get_new_buffer (idx_t min_size) | | ^~~~~~~~~~~~~~ | | | | | (51) entry to ‘get_new_buffer’ | 4503 | { | 4504 | struct buffer_record *new_buffer = xmalloc (sizeof *new_buffer); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (52) state of ‘&HEAP_ALLOCATED_REGION(1452)’: ‘start’ -> ‘nonnull’ (NULL origin) | <------+ | ‘load_buffer’: events 53-56 | | 4563 | struct buffer_record *b = get_new_buffer (bytes_wanted); | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (53) returning to ‘load_buffer’ from ‘get_new_buffer’ |...... | 4567 | if (hold_count) | | ~ | | | | | (54) following ‘false’ branch... |...... | 4574 | b->bytes_used += read_input (p, bytes_avail - 1); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (55) ...to here | | (56) calling ‘read_input’ from ‘load_buffer’ | +--> ‘read_input’: events 57-59 | | 4391 | read_input (char *dest, idx_t max_n_bytes) | | ^~~~~~~~~~ | | | | | (57) entry to ‘read_input’ |...... | 4394 | if (max_n_bytes == 0) | | ~ | | | | | (58) following ‘true’ branch (when ‘max_n_bytes == 0’)... | 4395 | return 0; | | ~ | | | | | (59) ...to here | <------+ | ‘load_buffer’: events 60-61 | | 4574 | b->bytes_used += read_input (p, bytes_avail - 1); | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (60) returning to ‘load_buffer’ from ‘read_input’ | 4575 | if (record_line_starts (b) != 0) | | ~~~~~~~~~~~~~~~~~~~~~~ | | | | | (61) calling ‘record_line_starts’ from ‘load_buffer’ | +--> ‘record_line_starts’: events 62-64 | | 4449 | record_line_starts (struct buffer_record *b) | | ^~~~~~~~~~~~~~~~~~ | | | | | (62) entry to ‘record_line_starts’ |...... | 4454 | if (b->bytes_used == 0) | | ~ | | | | | (63) following ‘true’ branch... | 4455 | return 0; | | ~ | | | | | (64) ...to here | <------+ | ‘load_buffer’: events 65-69 | | 4575 | if (record_line_starts (b) != 0) | | ~^~~~~~~~~~~~~~~~~~~~~~ | | || | | |(65) returning to ‘load_buffer’ from ‘record_line_starts’ | | (66) following ‘false’ branch... |...... | 4582 | free_buffer (b); | | ~~~~~~~~~~~~~~~ | | | | | (67) ...to here | | (68) deallocated here | | (69) calling ‘free_buffer’ from ‘load_buffer’ | +--> ‘free_buffer’: events 70-71 | | 4489 | free_buffer (struct buffer_record *buf) | | ^~~~~~~~~~~ | | | | | (70) entry to ‘free_buffer’ | 4490 | { | 4491 | for (struct line *l = buf->line_start; l;) | | ~ | | | | | (71) use after ‘free_buffer’ of ‘buf’; deallocated at (68) | a.i: In function ‘get_new_buffer’: a.i:4519:10: warning: leak of ‘b’ [CWE-401] [-Wanalyzer-malloc-leak] 4519 | return new_buffer; | ^~~~~~~~~~ ‘main’: events 1-6 | | 5509 | main (int argc, char **argv) | | ^~~~ | | | | | (1) entry to ‘main’ |...... | 5588 | if (argc - optind < 2) | | ~ | | | | | (2) following ‘false’ branch... |...... | 5598 | idx_t prefix_len = strlen (prefix); | | ~~~~~~~~~~~~~~~ | | | | | (3) ...to here |...... | 5616 | if (__builtin_add_overflow (prefix_len, max_digit_string_len + 1, &filename_size)) | | ~ | | | | | (4) following ‘false’ branch... | 5617 | xalloc_die (); | 5618 | filename_space = ximalloc (filename_size); | | ~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (5) ...to here | 5619 | set_input_file (argv[optind++]); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (6) calling ‘set_input_file’ from ‘main’ | +--> ‘set_input_file’: events 7-11 | | 4708 | set_input_file (char const *name) | | ^~~~~~~~~~~~~~ | | | | | (7) entry to ‘set_input_file’ | 4709 | { | 4710 | if (! (strcmp (name, "-") == 0) && fd_reopen ( | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | | | | | (9) ...to here | | | (10) following ‘false’ branch... | | (8) following ‘true’ branch (when the strings are non-equal)... | 4711 | 0 | | ~ | 4712 | , name, | | ~~~~~~~ | 4713 | 00 | | ~~ | 4714 | , 0) < 0) | | ~~~~~~~~ |...... | 4731 | } | | ~ | | | | | (11) ...to here | <------+ | ‘main’: events 12-21 | | 5619 | set_input_file (argv[optind++]); | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (12) returning to ‘main’ from ‘set_input_file’ |...... | 5651 | for (i = 0; i < nsigs; i++) | | ~~~~~~~~~ | | | | | (13) following ‘true’ branch (when ‘i <= 10’)... | | (15) following ‘true’ branch (when ‘i <= 10’)... | 5652 | { | 5653 | sigaction (sig[i], | | ~~~~~~ | | | | | (14) ...to here | | (16) ...to here |...... | 5668 | for (i = 0; i < nsigs; i++) | | ~~~~~~~~~ | | | | | (17) following ‘true’ branch (when ‘i <= 10’)... | | (19) following ‘true’ branch (when ‘i <= 10’)... | 5669 | if (sigismember (&caught_signals, sig[i])) | | ~~~~~~ | | | | | (18) ...to here | | (20) ...to here |...... | 5674 | split_file (); | | ~~~~~~~~~~~~~ | | | | | (21) calling ‘split_file’ from ‘main’ | +--> ‘split_file’: events 22-29 | | 4953 | split_file (void) | | ^~~~~~~~~~ | | | | | (22) entry to ‘split_file’ | 4954 | { | 4955 | for (idx_t i = 0; i < control_used; i++) | | ~~~~~~~~~~~~~~~~ | | | | | (23) following ‘true’ branch... |...... | 4958 | if (controls[i].regexpr) | | ~ ~ | | | | | | | (24) ...to here | | (25) following ‘true’ branch... | 4959 | { | 4960 | for (j = 0; (controls[i].repeat_forever | | ~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (26) ...to here | 4961 | || j <= controls[i].repeat); j++) | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (27) following ‘true’ branch... | 4962 | process_regexp (&controls[i], j); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (28) ...to here | | (29) calling ‘process_regexp’ from ‘split_file’ | +--> ‘process_regexp’: events 30-33 | | 4845 | process_regexp (struct control *p, intmax_t repetition) | | ^~~~~~~~~~~~~~ | | | | | (30) entry to ‘process_regexp’ |...... | 4853 | if (!ignore) | | ~ | | | | | (31) following ‘true’ branch... | 4854 | create_output_file (); | | ~~~~~~~~~~~~~~~~~~~~~ | | | | | (32) ...to here | | (33) calling ‘create_output_file’ from ‘process_regexp’ | +--> ‘create_output_file’: events 34-38 | | 4986 | create_output_file (void) | | ^~~~~~~~~~~~~~~~~~ | | | | | (34) entry to ‘create_output_file’ |...... | 4993 | if (nfiles == 0x7fffffff | | ~ | | | | | (35) following ‘false’ branch (when ‘nfiles != 2147483647’)... |...... | 5006 | sigprocmask ( | | ~~~~~~~~~~~~~ | | | | | (36) ...to here | 5007 | 0 | | ~ | 5008 | , &caught_signals, &oldset); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ |...... | 5023 | if (! fopen_ok) | | ~ | | | | | (37) following ‘false’ branch... |...... | 5028 | bytes_written = 0; | | ~~~~~~~~~~~~~~~~~ | | | | | (38) ...to here | <------+ | ‘process_regexp’: events 39-42 | | 4854 | create_output_file (); | | ^~~~~~~~~~~~~~~~~~~~~ | | | | | (39) returning to ‘process_regexp’ from ‘create_output_file’ | 4855 | if (p->offset >= 0) | | ~ | | | | | (40) following ‘true’ branch... |...... | 4861 | line = find_line (++current_line); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (41) ...to here | | (42) calling ‘find_line’ from ‘process_regexp’ | +--> ‘find_line’: events 43-46 | | 4654 | find_line (intmax_t linenum) | | ^~~~~~~~~ | | | | | (43) entry to ‘find_line’ |...... | 4657 | if (head == | | ~ | | | | | (44) following ‘true’ branch... | 4658 | ((void *)0) | 4659 | && !load_buffer ()) | | ~~~~~~~~~~~~~~ | | | | | (45) ...to here | | (46) calling ‘load_buffer’ from ‘find_line’ | +--> ‘load_buffer’: events 47-51 | | 4542 | load_buffer (void) | | ^~~~~~~~~~~ | | | | | (47) entry to ‘load_buffer’ | 4543 | { | 4544 | if (have_read_eof) | | ~ | | | | | (48) following ‘false’ branch... |...... | 4549 | ((( | | ~~~ | 4550 | 8191 | | ~~~~ | 4551 | )>( | | ~~~ | 4552 | hold_count + 1 | | ~~~~~~~~~~~~~~ | 4553 | ))?( | | ~~~~ | 4554 | 8191 | | ~~~~ | 4555 | ):( | | ~~~ | | | | | (49) ...to here | 4556 | hold_count + 1 | | ~~~~~~~~~~~~~~ | 4557 | )) | | ~~ |...... | 4563 | struct buffer_record *b = get_new_buffer (bytes_wanted); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (50) allocated here | | (51) calling ‘get_new_buffer’ from ‘load_buffer’ | +--> ‘get_new_buffer’: events 52-53 | | 4502 | get_new_buffer (idx_t min_size) | | ^~~~~~~~~~~~~~ | | | | | (52) entry to ‘get_new_buffer’ |...... | 4519 | return new_buffer; | | ~~~~~~~~~~ | | | | | (53) ‘b’ leaks here; was allocated at (50) | a.i: In function ‘load_buffer’: a.i:4582:7: warning: ‘b’ should have been deallocated with ‘free’ but was deallocated with ‘free_buffer’ [CWE-762] [-Wanalyzer-mismatching-deallocation] 4582 | free_buffer (b); | ^~~~~~~~~~~~~~~ ‘main’: events 1-6 | | 5509 | main (int argc, char **argv) | | ^~~~ | | | | | (1) entry to ‘main’ |...... | 5588 | if (argc - optind < 2) | | ~ | | | | | (2) following ‘false’ branch... |...... | 5598 | idx_t prefix_len = strlen (prefix); | | ~~~~~~~~~~~~~~~ | | | | | (3) ...to here |...... | 5616 | if (__builtin_add_overflow (prefix_len, max_digit_string_len + 1, &filename_size)) | | ~ | | | | | (4) following ‘false’ branch... | 5617 | xalloc_die (); | 5618 | filename_space = ximalloc (filename_size); | | ~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (5) ...to here | 5619 | set_input_file (argv[optind++]); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (6) calling ‘set_input_file’ from ‘main’ | +--> ‘set_input_file’: events 7-11 | | 4708 | set_input_file (char const *name) | | ^~~~~~~~~~~~~~ | | | | | (7) entry to ‘set_input_file’ | 4709 | { | 4710 | if (! (strcmp (name, "-") == 0) && fd_reopen ( | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | | | | | (9) ...to here | | | (10) following ‘false’ branch... | | (8) following ‘true’ branch (when the strings are non-equal)... | 4711 | 0 | | ~ | 4712 | , name, | | ~~~~~~~ | 4713 | 00 | | ~~ | 4714 | , 0) < 0) | | ~~~~~~~~ |...... | 4731 | } | | ~ | | | | | (11) ...to here | <------+ | ‘main’: events 12-21 | | 5619 | set_input_file (argv[optind++]); | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (12) returning to ‘main’ from ‘set_input_file’ |...... | 5651 | for (i = 0; i < nsigs; i++) | | ~~~~~~~~~ | | | | | (13) following ‘true’ branch (when ‘i <= 10’)... | | (15) following ‘true’ branch (when ‘i <= 10’)... | 5652 | { | 5653 | sigaction (sig[i], | | ~~~~~~ | | | | | (14) ...to here | | (16) ...to here |...... | 5668 | for (i = 0; i < nsigs; i++) | | ~~~~~~~~~ | | | | | (17) following ‘true’ branch (when ‘i <= 10’)... | | (19) following ‘true’ branch (when ‘i <= 10’)... | 5669 | if (sigismember (&caught_signals, sig[i])) | | ~~~~~~ | | | | | (18) ...to here | | (20) ...to here |...... | 5674 | split_file (); | | ~~~~~~~~~~~~~ | | | | | (21) calling ‘split_file’ from ‘main’ | +--> ‘split_file’: events 22-29 | | 4953 | split_file (void) | | ^~~~~~~~~~ | | | | | (22) entry to ‘split_file’ | 4954 | { | 4955 | for (idx_t i = 0; i < control_used; i++) | | ~~~~~~~~~~~~~~~~ | | | | | (23) following ‘true’ branch... |...... | 4958 | if (controls[i].regexpr) | | ~ ~ | | | | | | | (24) ...to here | | (25) following ‘true’ branch... | 4959 | { | 4960 | for (j = 0; (controls[i].repeat_forever | | ~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (26) ...to here | 4961 | || j <= controls[i].repeat); j++) | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (27) following ‘true’ branch... | 4962 | process_regexp (&controls[i], j); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (28) ...to here | | (29) calling ‘process_regexp’ from ‘split_file’ | +--> ‘process_regexp’: events 30-33 | | 4845 | process_regexp (struct control *p, intmax_t repetition) | | ^~~~~~~~~~~~~~ | | | | | (30) entry to ‘process_regexp’ |...... | 4853 | if (!ignore) | | ~ | | | | | (31) following ‘true’ branch... | 4854 | create_output_file (); | | ~~~~~~~~~~~~~~~~~~~~~ | | | | | (32) ...to here | | (33) calling ‘create_output_file’ from ‘process_regexp’ | +--> ‘create_output_file’: events 34-38 | | 4986 | create_output_file (void) | | ^~~~~~~~~~~~~~~~~~ | | | | | (34) entry to ‘create_output_file’ |...... | 4993 | if (nfiles == 0x7fffffff | | ~ | | | | | (35) following ‘false’ branch (when ‘nfiles != 2147483647’)... |...... | 5006 | sigprocmask ( | | ~~~~~~~~~~~~~ | | | | | (36) ...to here | 5007 | 0 | | ~ | 5008 | , &caught_signals, &oldset); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ |...... | 5023 | if (! fopen_ok) | | ~ | | | | | (37) following ‘false’ branch... |...... | 5028 | bytes_written = 0; | | ~~~~~~~~~~~~~~~~~ | | | | | (38) ...to here | <------+ | ‘process_regexp’: events 39-42 | | 4854 | create_output_file (); | | ^~~~~~~~~~~~~~~~~~~~~ | | | | | (39) returning to ‘process_regexp’ from ‘create_output_file’ | 4855 | if (p->offset >= 0) | | ~ | | | | | (40) following ‘true’ branch... |...... | 4861 | line = find_line (++current_line); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (41) ...to here | | (42) calling ‘find_line’ from ‘process_regexp’ | +--> ‘find_line’: events 43-46 | | 4654 | find_line (intmax_t linenum) | | ^~~~~~~~~ | | | | | (43) entry to ‘find_line’ |...... | 4657 | if (head == | | ~ | | | | | (44) following ‘true’ branch... | 4658 | ((void *)0) | 4659 | && !load_buffer ()) | | ~~~~~~~~~~~~~~ | | | | | (45) ...to here | | (46) calling ‘load_buffer’ from ‘find_line’ | +--> ‘load_buffer’: events 47-50 | | 4542 | load_buffer (void) | | ^~~~~~~~~~~ | | | | | (47) entry to ‘load_buffer’ | 4543 | { | 4544 | if (have_read_eof) | | ~ | | | | | (48) following ‘false’ branch... |...... | 4549 | ((( | | ~~~ | 4550 | 8191 | | ~~~~ | 4551 | )>( | | ~~~ | 4552 | hold_count + 1 | | ~~~~~~~~~~~~~~ | 4553 | ))?( | | ~~~~ | 4554 | 8191 | | ~~~~ | 4555 | ):( | | ~~~ | | | | | (49) ...to here | 4556 | hold_count + 1 | | ~~~~~~~~~~~~~~ | 4557 | )) | | ~~ |...... | 4563 | struct buffer_record *b = get_new_buffer (bytes_wanted); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (50) calling ‘get_new_buffer’ from ‘load_buffer’ | +--> ‘get_new_buffer’: events 51-52 | | 4502 | get_new_buffer (idx_t min_size) | | ^~~~~~~~~~~~~~ | | | | | (51) entry to ‘get_new_buffer’ | 4503 | { | 4504 | struct buffer_record *new_buffer = xmalloc (sizeof *new_buffer); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (52) state of ‘&HEAP_ALLOCATED_REGION(1452)’: ‘start’ -> ‘nonnull’ (NULL origin) | <------+ | ‘load_buffer’: events 53-56 | | 4563 | struct buffer_record *b = get_new_buffer (bytes_wanted); | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (53) returning to ‘load_buffer’ from ‘get_new_buffer’ |...... | 4567 | if (hold_count) | | ~ | | | | | (54) following ‘false’ branch... |...... | 4574 | b->bytes_used += read_input (p, bytes_avail - 1); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (55) ...to here | | (56) calling ‘read_input’ from ‘load_buffer’ | +--> ‘read_input’: events 57-59 | | 4391 | read_input (char *dest, idx_t max_n_bytes) | | ^~~~~~~~~~ | | | | | (57) entry to ‘read_input’ |...... | 4394 | if (max_n_bytes == 0) | | ~ | | | | | (58) following ‘true’ branch (when ‘max_n_bytes == 0’)... | 4395 | return 0; | | ~ | | | | | (59) ...to here | <------+ | ‘load_buffer’: events 60-61 | | 4574 | b->bytes_used += read_input (p, bytes_avail - 1); | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (60) returning to ‘load_buffer’ from ‘read_input’ | 4575 | if (record_line_starts (b) != 0) | | ~~~~~~~~~~~~~~~~~~~~~~ | | | | | (61) calling ‘record_line_starts’ from ‘load_buffer’ | +--> ‘record_line_starts’: events 62-64 | | 4449 | record_line_starts (struct buffer_record *b) | | ^~~~~~~~~~~~~~~~~~ | | | | | (62) entry to ‘record_line_starts’ |...... | 4454 | if (b->bytes_used == 0) | | ~ | | | | | (63) following ‘true’ branch... | 4455 | return 0; | | ~ | | | | | (64) ...to here | <------+ | ‘load_buffer’: events 65-68 | | 4575 | if (record_line_starts (b) != 0) | | ~^~~~~~~~~~~~~~~~~~~~~~ | | || | | |(65) returning to ‘load_buffer’ from ‘record_line_starts’ | | (66) following ‘false’ branch... |...... | 4582 | free_buffer (b); | | ~~~~~~~~~~~~~~~ | | | | | (67) ...to here | | (68) deallocated with ‘free_buffer’ here | a.i:4582:7: warning: leak of ‘<unknown>’ [CWE-401] [-Wanalyzer-malloc-leak] 4582 | free_buffer (b); | ^~~~~~~~~~~~~~~ ‘main’: events 1-6 | | 5509 | main (int argc, char **argv) | | ^~~~ | | | | | (1) entry to ‘main’ |...... | 5588 | if (argc - optind < 2) | | ~ | | | | | (2) following ‘false’ branch... |...... | 5598 | idx_t prefix_len = strlen (prefix); | | ~~~~~~~~~~~~~~~ | | | | | (3) ...to here |...... | 5616 | if (__builtin_add_overflow (prefix_len, max_digit_string_len + 1, &filename_size)) | | ~ | | | | | (4) following ‘false’ branch... | 5617 | xalloc_die (); | 5618 | filename_space = ximalloc (filename_size); | | ~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (5) ...to here | 5619 | set_input_file (argv[optind++]); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (6) calling ‘set_input_file’ from ‘main’ | +--> ‘set_input_file’: events 7-11 | | 4708 | set_input_file (char const *name) | | ^~~~~~~~~~~~~~ | | | | | (7) entry to ‘set_input_file’ | 4709 | { | 4710 | if (! (strcmp (name, "-") == 0) && fd_reopen ( | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | | | | | (9) ...to here | | | (10) following ‘false’ branch... | | (8) following ‘true’ branch (when the strings are non-equal)... | 4711 | 0 | | ~ | 4712 | , name, | | ~~~~~~~ | 4713 | 00 | | ~~ | 4714 | , 0) < 0) | | ~~~~~~~~ |...... | 4731 | } | | ~ | | | | | (11) ...to here | <------+ | ‘main’: events 12-21 | | 5619 | set_input_file (argv[optind++]); | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (12) returning to ‘main’ from ‘set_input_file’ |...... | 5651 | for (i = 0; i < nsigs; i++) | | ~~~~~~~~~ | | | | | (13) following ‘true’ branch (when ‘i <= 10’)... | | (15) following ‘true’ branch (when ‘i <= 10’)... | 5652 | { | 5653 | sigaction (sig[i], | | ~~~~~~ | | | | | (14) ...to here | | (16) ...to here |...... | 5668 | for (i = 0; i < nsigs; i++) | | ~~~~~~~~~ | | | | | (17) following ‘true’ branch (when ‘i <= 10’)... | | (19) following ‘true’ branch (when ‘i <= 10’)... | 5669 | if (sigismember (&caught_signals, sig[i])) | | ~~~~~~ | | | | | (18) ...to here | | (20) ...to here |...... | 5674 | split_file (); | | ~~~~~~~~~~~~~ | | | | | (21) calling ‘split_file’ from ‘main’ | +--> ‘split_file’: events 22-29 | | 4953 | split_file (void) | | ^~~~~~~~~~ | | | | | (22) entry to ‘split_file’ | 4954 | { | 4955 | for (idx_t i = 0; i < control_used; i++) | | ~~~~~~~~~~~~~~~~ | | | | | (23) following ‘true’ branch... |...... | 4958 | if (controls[i].regexpr) | | ~ ~ | | | | | | | (24) ...to here | | (25) following ‘true’ branch... | 4959 | { | 4960 | for (j = 0; (controls[i].repeat_forever | | ~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (26) ...to here | 4961 | || j <= controls[i].repeat); j++) | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (27) following ‘true’ branch... | 4962 | process_regexp (&controls[i], j); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (28) ...to here | | (29) calling ‘process_regexp’ from ‘split_file’ | +--> ‘process_regexp’: events 30-33 | | 4845 | process_regexp (struct control *p, intmax_t repetition) | | ^~~~~~~~~~~~~~ | | | | | (30) entry to ‘process_regexp’ |...... | 4853 | if (!ignore) | | ~ | | | | | (31) following ‘true’ branch... | 4854 | create_output_file (); | | ~~~~~~~~~~~~~~~~~~~~~ | | | | | (32) ...to here | | (33) calling ‘create_output_file’ from ‘process_regexp’ | +--> ‘create_output_file’: events 34-38 | | 4986 | create_output_file (void) | | ^~~~~~~~~~~~~~~~~~ | | | | | (34) entry to ‘create_output_file’ |...... | 4993 | if (nfiles == 0x7fffffff | | ~ | | | | | (35) following ‘false’ branch (when ‘nfiles != 2147483647’)... |...... | 5006 | sigprocmask ( | | ~~~~~~~~~~~~~ | | | | | (36) ...to here | 5007 | 0 | | ~ | 5008 | , &caught_signals, &oldset); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ |...... | 5023 | if (! fopen_ok) | | ~ | | | | | (37) following ‘false’ branch... |...... | 5028 | bytes_written = 0; | | ~~~~~~~~~~~~~~~~~ | | | | | (38) ...to here | <------+ | ‘process_regexp’: events 39-42 | | 4854 | create_output_file (); | | ^~~~~~~~~~~~~~~~~~~~~ | | | | | (39) returning to ‘process_regexp’ from ‘create_output_file’ | 4855 | if (p->offset >= 0) | | ~ | | | | | (40) following ‘true’ branch... |...... | 4861 | line = find_line (++current_line); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (41) ...to here | | (42) calling ‘find_line’ from ‘process_regexp’ | +--> ‘find_line’: events 43-46 | | 4654 | find_line (intmax_t linenum) | | ^~~~~~~~~ | | | | | (43) entry to ‘find_line’ |...... | 4657 | if (head == | | ~ | | | | | (44) following ‘true’ branch... | 4658 | ((void *)0) | 4659 | && !load_buffer ()) | | ~~~~~~~~~~~~~~ | | | | | (45) ...to here | | (46) calling ‘load_buffer’ from ‘find_line’ | +--> ‘load_buffer’: events 47-52 | | 4542 | load_buffer (void) | | ^~~~~~~~~~~ | | | | | (47) entry to ‘load_buffer’ | 4543 | { | 4544 | if (have_read_eof) | | ~ | | | | | (48) following ‘false’ branch... |...... | 4549 | ((( | | ~~~ | 4550 | 8191 | | ~~~~ | 4551 | )>( | | ~~~ | 4552 | hold_count + 1 | | ~~~~~~~~~~~~~~ | 4553 | ))?( | | ~~~~ | 4554 | 8191 | | ~~~~ | 4555 | ):( | | ~~~ | | | | | (49) ...to here | 4556 | hold_count + 1 | | ~~~~~~~~~~~~~~ | 4557 | )) | | ~~ |...... | 4567 | if (hold_count) | | ~ | | | | | (50) following ‘false’ branch... |...... | 4574 | b->bytes_used += read_input (p, bytes_avail - 1); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (51) ...to here | | (52) calling ‘read_input’ from ‘load_buffer’ | +--> ‘read_input’: events 53-57 | | 4391 | read_input (char *dest, idx_t max_n_bytes) | | ^~~~~~~~~~ | | | | | (53) entry to ‘read_input’ |...... | 4394 | if (max_n_bytes == 0) | | ~ | | | | | (54) following ‘false’ branch (when ‘max_n_bytes != 0’)... | 4395 | return 0; | 4396 | bytes_read = safe_read ( | | ~~~~~~~~~~~ | | | | | (55) ...to here | 4397 | 0 | | ~ | 4398 | , dest, max_n_bytes); | | ~~~~~~~~~~~~~~~~~~~~ |...... | 4403 | if (bytes_read == ((size_t) -1)) | | ~ | | | | | (56) following ‘false’ branch (when ‘bytes_read != -1’)... |...... | 4410 | return bytes_read; | | ~~~~~~~~~~ | | | | | (57) ...to here | <------+ | ‘load_buffer’: events 58-59 | | 4574 | b->bytes_used += read_input (p, bytes_avail - 1); | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (58) returning to ‘load_buffer’ from ‘read_input’ | 4575 | if (record_line_starts (b) != 0) | | ~~~~~~~~~~~~~~~~~~~~~~ | | | | | (59) calling ‘record_line_starts’ from ‘load_buffer’ | +--> ‘record_line_starts’: events 60-65 | | 4449 | record_line_starts (struct buffer_record *b) | | ^~~~~~~~~~~~~~~~~~ | | | | | (60) entry to ‘record_line_starts’ |...... | 4454 | if (b->bytes_used == 0) | | ~ | | | | | (61) following ‘false’ branch... | 4455 | return 0; | 4456 | lines = 0; | | ~~~~~~~~~ | | | | | (62) ...to here |...... | 4465 | if (line_end == buffer_end) | | ~ | | | | | (63) following ‘false’ branch (when ‘line_end != buffer_end’)... | 4466 | break; | 4467 | line_length = line_end - line_start + 1; | | ~~~~~~~~~~~~~~~~~~~~~ | | | | | (64) ...to here | 4468 | keep_new_line (b, line_start, line_length); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (65) calling ‘keep_new_line’ from ‘record_line_starts’ | +--> ‘keep_new_line’: events 66-68 | | 4430 | keep_new_line (struct buffer_record *b, char *line_start, idx_t line_len) | | ^~~~~~~~~~~~~ | | | | | (66) entry to ‘keep_new_line’ |...... | 4433 | if (b->line_start == | | ~ | | | | | (67) following ‘false’ branch... |...... | 4437 | if (b->curr_line->used == 80) | | ~~~~~~~~~~~~ | | | | | (68) ...to here | <------+ | ‘record_line_starts’: events 69-72 | | 4465 | if (line_end == buffer_end) | | ~ | | | | | (70) following ‘false’ branch (when ‘line_end != buffer_end’)... | 4466 | break; | 4467 | line_length = line_end - line_start + 1; | | ~~~~~~~~~~~~~~~~~~~~~ | | | | | (71) ...to here | 4468 | keep_new_line (b, line_start, line_length); | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (69) returning to ‘record_line_starts’ from ‘keep_new_line’ | | (72) calling ‘keep_new_line’ from ‘record_line_starts’ | +--> ‘keep_new_line’: events 73-76 | | 4430 | keep_new_line (struct buffer_record *b, char *line_start, idx_t line_len) | | ^~~~~~~~~~~~~ | | | | | (73) entry to ‘keep_new_line’ |...... | 4433 | if (b->line_start == | | ~ | | | | | (74) following ‘true’ branch... |...... | 4436 | b->line_start = b->curr_line = new_line_control (); | | ~~~~~~~~~~~~~~~~~~~ | | | | | (75) ...to here | | (76) calling ‘new_line_control’ from ‘keep_new_line’ | +--> ‘new_line_control’: events 77-78 | | 4420 | new_line_control (void) | | ^~~~~~~~~~~~~~~~ | | | | | (77) entry to ‘new_line_control’ | 4421 | { | 4422 | struct line *p = xmalloc (sizeof *p); | | ~~~~~~~~~~~~~~~~~~~ | | | | | (78) allocated here | <------+ | ‘keep_new_line’: events 79-81 | | 4436 | b->line_start = b->curr_line = new_line_control (); | | ^~~~~~~~~~~~~~~~~~~ | | | | | (79) returning to ‘keep_new_line’ from ‘new_line_control’ | 4437 | if (b->curr_line->used == 80) | | ~ | | | | | (80) following ‘false’ branch... |...... | 4442 | l = b->curr_line; | | ~~~~~~~~~~~~~~~~ | | | | | (81) ...to here | <------+ | ‘record_line_starts’: events 82-83 | | 4465 | if (line_end == buffer_end) | | ~ | | | | | (83) following ‘true’ branch (when ‘line_end == buffer_end’)... |...... | 4468 | keep_new_line (b, line_start, line_length); | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (82) returning to ‘record_line_starts’ from ‘keep_new_line’ | ‘record_line_starts’: event 84 | |cc1: | (84): ...to here | <------+ | ‘load_buffer’: events 85-88 | | 4575 | if (record_line_starts (b) != 0) | | ~^~~~~~~~~~~~~~~~~~~~~~ | | || | | |(85) returning to ‘load_buffer’ from ‘record_line_starts’ | | (86) following ‘false’ branch... |...... | 4582 | free_buffer (b); | | ~~~~~~~~~~~~~~~ | | | | | (87) ...to here | | (88) ‘<unknown>’ leaks here; was allocated at (78) |