liverr1818
liverr1818

Reputation: 27

Segmentation fault with global pointers

I am trying to define a global pointer variable that can then truly be set in the main function as seen below. However I am getting a segmentation fault anytime I try to use outputName after this. I know it probably has to do with setting the pointer equal to NULL at the beginning... any help on how I could have a global pointer that is then set in main would be very helpful! Here is the part of my code that is giving me errors:

    char* outputName = NULL;

    int isNumber(char number[]){
        int i;
        if (number[0] == '-')
            i = 1;
        
        while(number[i] != '\0'){
            if (!isdigit(number[i]))
                return 0;

            i++;
        }

        return 1;
    }

    void catcher(int signo){
        printf("The program is exiting early");
        remove(outputName);
        exit(1);
    }

    int main(int argc, char *argv[]){
        if (argc != 4){
            fprintf(stderr,"Incorrect number of arguments, must supply three.\n");
            exit(1);
        }

        char* inputName = argv[1];
        outputName = argv[2];
        signal(SIGINT, catcher);
        int result = isNumber(argv[3]);
        
        if (result == 0){
            fprintf(stderr, "Invalid maximum line length, please enter an integer\n");
            exit(1);
        }
        
        int maxChars = (atoi(argv[3])) + 1;
        if ((maxChars-1) < 1){
            fprintf(stderr, "Invalid third maximum line length, please enter an integer greater than zero\                                          
    .\n");
            exit(1);
        }

        FILE* inFile = fopen(inputName, "r");
        if (inFile == NULL){
            fprintf(stderr, "Error while opening %s.\n", inputName);
            exit(1);
        }

        FILE* outFile = fopen(outputName, "w");
        if (outFile == NULL){
            fprintf(stderr, "Error while opening %s.\n", outputName);
            exit(1);
        }                                                                                               
        
        char line[maxChars];
        int done = 0;
        while (!done){
            char *readLine = fgets(line, maxChars, inFile);
            if (readLine == NULL){
                if (errno == 0){
                    done = 1;
                } else {
                    fprintf(stderr, "Error when reading line from input file");
                    exit(1);
                }
            }

            int len = strlen(line);
            if (line[len-1] != '\n'){
                line[len] = '\n';
                line[len+1] = '\0';
                char current = ' ';

                while (current != '\n')
                    current = getc(inFile);
            }

            if (!done){
                fputs(line, outFile);
                if (errno != 0){
                    fprintf(stderr, "Error when writing line to output file");
                    exit(1);
                }
            }
        }

        return 0;
    }

Upvotes: 1

Views: 868

Answers (2)

Read carefully signal(7): since your catcher calls printf which is not an async signal safe function, your code has undefined behavior. Also, your printf control string don't end with \n, and since stdout is line-buffered, no output would be done. Prefer sigaction(2) to signal, and install your signal handler after having assigned outputName.

Global variables used in signal handlers should be declared volatile. So declare your char* volatile outputName; at global scope. Then you might have a test like if (outputName != NULL) remove(outputName); in the handler. A common practice is just to set some volatile sig_atomic_t global flag in the signal handler, and test that flag elsewhere.

And your program is likely to not have time to get any signal. You probably should end your main function with some wait (e.g. read from stdin, or usleep(3), or pause(2), or poll(2)....).

Of course, compile your code with all warnings and debug info (gcc -Wall -g) and use the debugger (gdb); I guess that debugger watchpoints should be very useful to find your bug.

The program you are showing is likely to not exhibit any SEGV. So your actual bug is very probably elsewhere.

Perhaps using strace(1) and/or valgrind could also help.

Upvotes: 2

Pras
Pras

Reputation: 4044

May be signal handler is getting called prior to outputName getting set to non null value, you can try setting signal handler after outputName = argv[2]; in main()

Upvotes: 3

Related Questions