Thread: segmentation fault depending on location of file

  1. #1
    Registered User
    Join Date
    Oct 2017
    Posts
    22

    segmentation fault depending on location of file

    I am running a C script which calls many subroutines. I have tested and used without problems this script before with slightly different inputs. Now I noticed I get a "segmentation fault (core dumped)" and the script fails.

    It has two input files, let's call them file1 and file2. It would be quite difficult to make a simple example of the script so I am asking a general question.

    I started debugging and noticed that the segmentation fault does not happen when file2 is located somewhere else and the script finishes successfully.
    Particularly, when file2 is located in the directory where I am running the script, it finishes sucessfully.
    When it is more than a few directories up and then more of the path, a segmentation fault occurs.

    So if I run it as:

    Code:
    myscript -a file1 -b file2
    or

    Code:
    myscript -a file1 -b ../file2
    it is fine.
    When I run it as e.g.

    Code:
    myscript -a file1 -b ../../../home/server/disk1/user7/software/inputs/file2
    Is there a reason why the location of the file could affect the running?

  2. #2
    Registered User
    Join Date
    Dec 2017
    Posts
    1,626
    Are you testing that the file opened?
    If you are copying the argv string to another place, is the destination buffer big enough? (It should be at least a few hundred chars.)
    Instead of copying it you could assign it to a pointer.
    Code:
    const char *fileb;
    ...
    fileb = argv[4];  // 4 would probably not be hardcoded here!
    ...
    FILE *fb = fopen(fileb, "r");
    if (!fb)
    {
        perror("Cannot open file b");
        exit(EXIT_FAILURE);
    }
    A little inaccuracy saves tons of explanation. - H.H. Munro

  3. #3
    Registered User
    Join Date
    Oct 2017
    Posts
    22
    Thank you for the answer. No I am not testing that the file opened because it opens every time. The segmentation fault happens actually after the script had read the second file (file 2 or b) and while the script is processing the first file (file a or 1) and not the second file,but for some reason it only happens when the second file has such locations.

    Could it mean that I have assigned some memory in the wrong way and it only gets detected when the location is such? Still,why would location matter?

  4. #4
    Registered User
    Join Date
    Mar 2019
    Posts
    5
    I guess you'll have to share your code...

  5. #5
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    Without seeing the code, expect nothing but ineffectual guessing on our part.

    There are hundreds of ways to screw up.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  6. #6
    Registered User
    Join Date
    Oct 2017
    Posts
    22
    I am debugging a lot of scripts that I hadn't written myself and there are hundreds of functions so it would be impossible to copy everything and I am not sure even if copying this will help at all.
    I suppose the best is to show one of the last parts of code that I see being executed before segmentation fault:

    The main script calls the function as:

    Code:
    tokenise(line, tok, 10);
    where line is the line number of the file that it is reading, and tok is gotten from:

    Code:
    strtok(line, "\n");
    The function is defined as:

    Code:
    int tokenise(char *line, char **tok, int form_block) {
    
        int co1, co2, co3, line_len, no_tok;
     
        line_len = strlen(line + 1);
        no_tok = blocks[form_block].no_field;
        
        /* Copy tokens from line by column position */
    
        for (co1 = 0; co1 < no_tok; ++co1) {
            
            tok[co1] = line - 1 + blocks[form_block].field_start[co1];
            
            if ((*(tok[co1] + blocks[form_block].field_width[co1]) != '\0') &&
                (*(tok[co1] + blocks[form_block].field_width[co1]) != ' ')    ) {
                
                fprintf(stdout, "\nWarning: field-separator placed over non-space character '%c' (line %d, char %d, token %d) block %s",
                        *(tok[co1] + blocks[form_block].field_width[co1]), line_co, 
                        blocks[form_block].field_start[co1] + blocks[form_block].field_width[co1], co1 + 1, blocks[form_block].name);
            }
                                    
            sprintf(tok[co1] + blocks[form_block].field_width[co1], "");            
                
    
            /* If token is empty, spaces or dng chars, set to DNG chars */
    
            if (strspn(tok[co1], " -") == strlen(tok[co1])) {
            
                for (co2 = 0; co2 < strlen(tok[co1]); ++co2) tok[co1][co2] = '-';
    
            } else {
            
                /*Strip leading and trailing spaces */
    
                if (strlen(tok[co1]) > 0) {
                    tok[co1] += strspn(tok[co1], " ");
                    while (strcmp(tok[co1] + (strlen(tok[co1]) - 1), " ") == 0) strcpy(tok[co1] + (strlen(tok[co1]) - 1), "");
                }
            }
        }
    
        return EXIT_SUCCESS;
    
    }

  7. #7
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    Are you compiling with the -g flag?

    That enables the compiler to store a lot of debug in the executable.

    Then you can do
    gdb myprogram

    At the (gdb) prompt, type
    run -a file1 -b file2

    GDB will trap at the exact instruction causing the segfault.
    From there, you can use the 'bt' command to get a stack trace, and the 'p' command to print variables.
    Use 'up' and 'down' to navigate the stack.

    > sprintf(tok[co1] + blocks[form_block].field_width[co1], "");
    Does an empty format do anything?
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  8. #8
    Registered User
    Join Date
    Oct 2017
    Posts
    22
    For your last question, I don't know if the empty format does anything.

    I've tried with gdb and I get:

    Code:
    Program received signal SIGSEGV, Segmentation fault.
    0x00000000004899a3 in ?? ()
    Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.209.el6_9.1.x86_64
    (gdb) bt
    #0  0x00000000004899a3 in ?? ()
    #1  0x0000003000000000 in ?? ()
    #2  0x00007fff00000000 in ?? ()
    #3  0x00007fff00000000 in ?? ()
    #4  0x000000000000000b in ?? ()
    #5  0x00000000000000d2 in ?? ()
    #6  0x0000000000000000 in ?? ()

  9. #9
    Registered User
    Join Date
    Feb 2019
    Posts
    1,078
    Did you compile your code with -g?

  10. #10
    Registered User
    Join Date
    Dec 2017
    Posts
    1,626
    The location as such should not matter, as long as you have access to it.

    You didn't answer my question about whether you copy the filename to another string. If you do, make sure it has plenty of space.

    And please add code to test that both files have actually opened. This is crucial. When the user supplies a filename you cannot assume that it will be correct and accessible.

    Here's a bit of a rewrite of your tokenise function. I haven't tested it but it's not meant to change any of the logic or fix any problems except the pointless sprintf call (which I'm assuming you meant to zero-terminate the string).

    Obviously the code you've shown will not depend on the location of the file in the filesystem. And there's nothing we can say is wrong with it without a lot more information about the program. You could post a link to a zip of the entire program that you've uploaded somewhere.
    Code:
    void tokenise(char *line, char **tok, int form_block) {
     
        int line_len = strlen(line + 1);          //// this is never used ////
        int no_tok = blocks[form_block].no_field;
     
        /* Copy tokens from line by column position */
     
        for (int co1 = 0; co1 < no_tok; ++co1) {
     
            int start = blocks[form_block].field_start[co1];
            int width = blocks[form_block].field_width[co1];
     
            tok[co1] = line - 1 + start;
     
            char *p = tok[co1] + width;
            if (*p && *p != ' ') {
                fprintf(stdout, "\nWarning: field-separator placed over non-space "
                        "character '%c' (line %d, char %d, token %d) block %s",
                        *p, line_co, start + width co1 + 1, blocks[form_block].name);
     
                //// should the code continue here ????
            }
     
            //// I'm assuming you meant the pointless sprintf
            //// to zero terminate the string. (Is that correct?)
     
            *p = '\0';
     
            /* If token is empty, spaces or dng chars, set to DNG chars */
     
            if (strspn(tok[co1], " -") == width) {
     
                memset(tok[co1], '-', width);
     
            } else {
     
                /* Strip leading and trailing spaces */
     
                if (*tok[co1]) {
                    tok[co1] += strspn(tok[co1], " ");
                    int len = strlen(tok[co1]); // we know it must be at least 1
                    while (tok[co1][--len] == ' ' && len) ;
                    tok[co1][len] = '\0';
                }
            }
        }
    }
    Last edited by john.c; 03-07-2019 at 10:06 AM.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  11. #11
    Registered User
    Join Date
    Oct 2017
    Posts
    22
    As for compiling, the script is a part of a software and I don't compile directly with a compiler but with a script that compiles more things at once and sets everything so I don't know how to add that option correctly.
    I'm a beginner in C debugging a code written by someone else so I am not managing to follow up the suggestions so it would be fair that I stop asking questions.

    Just a couple of last things to check:
    1) When I run the script, if I print the output of running into a log file, the script stops earlier than when I simply print the output to the terminal. Should I be trying to debug in the part where it stops in the terminal or in the time where it stops when it is directed to a log file?

    2) for the input filename. @john.c for your question about reading the file, there are other functions through which I can see that the file is actually read. The filename does get copied to a string - I thought a string defined this way shouldn't have limitations:

    Code:
    char *batname;


    Code:
    if (strcmp(*(argv + co1), "-b") == 0) {
                batname = (char *)strdup(argv[co1 + 1]);
                bat_flag = 1;
                ++co1;
                continue;
            }
    Could this string be limited in length?

  12. #12
    Registered User
    Join Date
    Dec 2017
    Posts
    1,626
    No, that string will not be limited in length. It should be fine. (Although there is obviously no reason to cast to char* since that's what it returns anyway.)

    Did you at least fix the sprintf error? Did you mean it to zero-terminate the string at that point?

    Other than that I doubt anyone can help you unless you upload the entire thing somewhere.
    When you say it "compiles with a script", do you mean a makefile?
    If so, post that and we can show you where to add the -g.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  13. #13
    Registered User
    Join Date
    Oct 2017
    Posts
    22
    I don't really understand what the code writer meant with sprintf, but the lines of the file are meant to be of a certain max length, so if this is, as you say, terminating the string at that point, then it make sense.

  14. #14
    Registered User
    Join Date
    Oct 2017
    Posts
    22
    There is a c shell mak_mak script that creates a makefile from another file. I've added the cshell script in the attachment (saved as txt just because of upload permissions)


    And this is in the makefile it uses:


    Code:
    vpath %.c /home/users/tnz/capu/src
    vpath %.f /home/users/tnz/capu/src
    vpath %.h /home/users/tnz/capu/src
    all: capu capuk
    ...
    CC = gcc 
    
    # 32 bit binaries for tn mixed cluster
    # Static binaries to avoid job being killed unexpectedly by kernel
        OLDCFLAGS = -ansi -DNESFIVE 
        SUBOLDCFLAGS = -ansi -DNESFIVE
        CFLAGS = -ansi -DNESTWO_TWO -lm 
        SUBCFLAGS = -ansi -DNESTWO_TWO 
    
    %.o: %.c 
        $(CC) -c $(SUBCFLAGS) $<
    Attached Files Attached Files

  15. #15
    Registered User
    Join Date
    Dec 2017
    Posts
    1,626
    I actually thought that the sprintf was doing nothing at all, but now that I think about it (and test it), it does seem to terminate the string, although it's a very strange way of doing it.

    Where did you get this code?
    Did you make changes to it?
    What does it do?
    Is it supposed to be working correctly?
    Can you post a link to the code?

    You can just add -g at the end of the compile line in the makefile (the last line, right after the $<).

    EDIT: That mak_mak file makes it more complicated; You could try adding the -g here:
    Code:
        printf "\t"'$(CC) $(CFLAGS) -g -o '"$file:r ../src/$file:r"'.c ./libcapu.a ' >> makefile
    And what is the ... in the makefile you posted?
    Last edited by john.c; 03-07-2019 at 12:07 PM.
    A little inaccuracy saves tons of explanation. - H.H. Munro

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 6
    Last Post: 10-28-2014, 10:01 PM
  2. Reading from file, segmentation fault
    By atac in forum C Programming
    Replies: 2
    Last Post: 05-08-2013, 10:34 PM
  3. Segmentation fault in Header file
    By Marc Oleson in forum C Programming
    Replies: 12
    Last Post: 04-26-2013, 05:39 PM
  4. Segmentation Fault. When trying to open file.
    By guyle in forum C Programming
    Replies: 5
    Last Post: 02-25-2013, 12:55 PM
  5. Segmentation fault with a file pointer?
    By Matt13 in forum C Programming
    Replies: 14
    Last Post: 07-31-2004, 05:53 AM

Tags for this Thread