Thread: scanf and fgets interference

  1. #1
    Registered User
    Join Date
    Jan 2019
    Posts
    4

    scanf and fgets interference

    Hello,


    I am stuck with a weird segfault since yesterday. I call scanf, then the program crashes instantly, but only if another fgets is referenced later in the code.


    Here are some snippets:


    main.c
    Code:
     
    #include "../misc.h"
    #include "../parse_maps.h"
    #include "../search.h"
     
    int main(int argc, char *argv[])
    {
        unsigned long remote_offset;
        pid_t remote_pid;
        map_line_t map_line;
        FILE* map_file = NULL;
     
        validate_start(argc, argv, &remote_pid); // The scanf call is within this function's body
     
        open_map_file(remote_pid, map_file);
     
        load_map_data_for_filename(map_file, &map_line, "[heap]"); // The fgets call is within this function's body
     
       //remote_offset = memory_offsets_where_string_equals(remote_pid, map_line, "heapvartwo");
        //printf("Offset is at %#lx\n", remote_offset);
        //fclose(map_file);
        return 0;
    }

    misc.c
    Code:
    #include "misc.h"
     
    #include <stdio.h>
    #include <stdlib.h> // atoi
     
    void validate_start(int argc, char* argv[], pid_t* pid)
    {
        char tmp[100];
     
        if (argc == 2) {
            sprintf(tmp, "%s", argv[1]);
            *pid = atoi(tmp);
        }
        else
        {
            puts("Enter the PID of target process: ");
            int lol;
            while(scanf("%d", &lol) == 0) // This is a little bugged, but gets the job done. The program crashes immediately after scanf succeeds
            {
                puts("Not a valid number, try again:");
                getchar();
            }
        }
     
        printf("yeye"); // This never prints, except when I comment out the fgets in the function below
     
    }

    Finally, parse_maps.c
    Code:
    #include "parse_maps.h"
     
    #include <stdio.h>
    #include <fcntl.h>
    #include <string.h>
    #include "valuetypes.h"
     
    void open_map_file(pid_t pid, FILE* map_file)
    {
    //code
    }
     
    void read_map_line(char* line, map_line_t* map_line)
    {
    //code
    }
     
    void load_map_data_for_filename(FILE* map_file, map_line_t* map_line, char* filename)
    {
        char tmp[1000];
        map_line_t curr_map;
     
        while (fgets(tmp, 999, map_file) != NULL) // This line makes the scanf above crash for some reason
        {
            // read_map_line(tmp, &curr_map);
     
            // if(strcmp(curr_map.filename, filename) == 0)
            // {
            //     read_map_line(tmp, map_line);
            //     return;
            // }
        }
    }

    I really struggle to understand what is going on, I'm sure it's something really stupid like a bad pointer, but I've tried many things without success..


    I use GCC 8.2.1 or tcc 0.9.27 to compile, without any difference

    Do you need more info to reproduce the issue, or find out something?


    Thanks for your replies!

  2. #2
    Registered User john.c's Avatar
    Join Date
    Dec 2017
    Posts
    616
    Post a link to a zip of the entire program, including input files.
    The world hangs on a thin thread, and that is the psyche of man. - Carl Jung

  3. #3
    Registered User
    Join Date
    Jan 2019
    Posts
    4
    test.zip

    You can use this to compile the main_test.c file

    Code:
    gcc src/debug_funcs/main_test.c src/memory.c src/misc.c src/parse_maps.c src/search.c -o bin/debug && bin/debug

  4. #4
    Registered User john.c's Avatar
    Join Date
    Dec 2017
    Posts
    616
    I guess I should've asked what it's supposed to do.

    But there are some warnings when compiling with -Wall -W -pedantic:
    Code:
    src/debug_funcs/main_test.c: In function ‘main’:
    src/debug_funcs/main_test.c:7:19: warning: unused variable ‘remote_offset’ [-Wunused-variable]
         unsigned long remote_offset;
                       ^
    src/parse_maps.c: In function ‘open_map_file’:
    src/parse_maps.c:8:37: warning: parameter ‘map_file’ set but not used [-Wunused-but-set-parameter]
     void open_map_file(pid_t pid, FILE* map_file)
                                         ^
    src/parse_maps.c: In function ‘load_map_data_for_filename’:
    src/parse_maps.c:34:16: warning: unused variable ‘curr_map’ [-Wunused-variable]
         map_line_t curr_map;
                    ^
    src/parse_maps.c:31:61: warning: unused parameter ‘map_line’ [-Wunused-parameter]
     void load_map_data_for_filename(FILE* map_file, map_line_t* map_line, char* filename)
                                                                 ^
    src/parse_maps.c:31:77: warning: unused parameter ‘filename’ [-Wunused-parameter]
     void load_map_data_for_filename(FILE* map_file, map_line_t* map_line, char* filename)
                                                                                 ^
    src/search.c: In function ‘memory_offsets_where_string_equals’:
    src/search.c:63:13: warning: implicit declaration of function ‘write’ [-Wimplicit-function-declaration]
                 write(1, (buffer + read_byte)->chars, sizeof(int64_t));
                 ^
    Just looking at open_map_file (in parse_maps.c):
    Code:
    void open_map_file(pid_t pid, FILE* map_file)
    {
        char tmp[100];
     
        sprintf(tmp, "/proc/%d/maps", pid);
     
        map_file = fopen(tmp, "r");
    }
    Simply setting the parameter to something sn't going to return it. It would be more sensible to declare map_file as a local and return it. perhaps checking that it actually opened first.
    Code:
    FILE *open_map_file(pid_t pid)
    {
        char tmp[100];
        sprintf(tmp, "/proc/%d/maps", pid);
        FILE *map_file =  fopen(tmp, "r");
        if (!map_file)
        {
            // problem
        }
        return map_file;
    }
    Why don't you fix all of those warnings and see if there's still a problem.
    Last edited by john.c; 01-23-2019 at 02:23 PM.
    The world hangs on a thin thread, and that is the psyche of man. - Carl Jung

  5. #5
    Registered User
    Join Date
    Jan 2019
    Posts
    4
    Ok, I've fixed it, there's only unused variables and parameters now, but I don't think this should interfere at all with my issues.

    I've attached a zip with the updated code, but the same issue remains

    test2.zip

  6. #6
    Registered User john.c's Avatar
    Join Date
    Dec 2017
    Posts
    616
    Firstly, add a newline after "yeye" since it won't flush without it which is probably why you aren't seeing it.

    Secondly, you didn't check properly in open_map_file. You need to check *map_file. And it makes a lot more sense to return a local then pass in a FILE**.

    If you still need help, you really need to tell me exactly how to run it (I assume prog.cpp is involved somehow) and what it's supposed to do.
    Last edited by john.c; 01-23-2019 at 03:07 PM.
    The world hangs on a thin thread, and that is the psyche of man. - Carl Jung

  7. #7
    Registered User john.c's Avatar
    Join Date
    Dec 2017
    Posts
    616
    I just noticed that you aren't ever setting *pid to lol in validate_start.
    The world hangs on a thin thread, and that is the psyche of man. - Carl Jung

  8. #8
    Registered User
    Join Date
    Jan 2019
    Posts
    4
    Yeah, I had multiple versions of this because I tried a lot of different things, so there might be some incoherences in the files I sent.

    I found the issue, found a fix, but did not understand everything. The issue wasn't about the scanf at all, it's just that the printf "yeye" wasn't working, and the execution kept going. It crashed because maps_file wasn't properly initialized.

    Though I don't get why this:

    fflush(stdin); fflush(stdout); printf("yeye"); printf("yoouuo");
    did not work as expected after the scanf..

    Anyway thanks for your help, and if you know why this happened, I'd be glad to hear it

  9. #9
    Registered User john.c's Avatar
    Join Date
    Dec 2017
    Posts
    616
    In the code you show, fflush(stdin) is undefined behavior in the standard (although it is apparently defined for Microsoft systems), and the fflush(stdout) would obviously need to come after the printf's. But as I've already said, simply adding a newline (as most people would) will also flush the output buffer when writing to the terminal. Actually, we would usually write debug output to stderr, since that is unbuffered by default.
    The world hangs on a thin thread, and that is the psyche of man. - Carl Jung

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. fgets after scanf, skips over fgets?
    By willane1965 in forum C Programming
    Replies: 1
    Last Post: 08-17-2014, 11:13 PM
  2. fgets and scanf
    By kkk in forum C Programming
    Replies: 10
    Last Post: 07-29-2011, 10:11 AM
  3. scanf vs fgets?
    By Matus in forum C Programming
    Replies: 65
    Last Post: 11-17-2008, 04:02 PM
  4. what happens after 'fgets' and 'scanf'
    By the bassinvader in forum C Programming
    Replies: 4
    Last Post: 07-30-2006, 03:04 PM
  5. Scanf->Fgets
    By 00Sven in forum C Programming
    Replies: 2
    Last Post: 04-21-2006, 02:39 PM

Tags for this Thread