1

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;
    }
Robert Christopher
  • 4,940
  • 1
  • 20
  • 21
liverr1818
  • 27
  • 3
  • How many arguments are you passing to `main()`? have you done basic debugging to see what the value of `argv[2]` is? Have you checked `argc >= 3` ? – John3136 Dec 07 '16 at 04:18
  • passing four arguments, yes done all that error checking to make sure the value of are is correct. – liverr1818 Dec 07 '16 at 04:19
  • 1
    So if `outputName` is valid after the above code, then the problem is somewhere else... – John3136 Dec 07 '16 at 04:21
  • 1
    could you provide a complete block of code? May be complete main function and what you are doing with `outputName` after that. – danishansari Dec 07 '16 at 04:21
  • so it is fine to set a global pointer to NULL and then set that pointer equal to something else in main and use that pointer in other functions as well as main without passing? Sorry just learning C! – liverr1818 Dec 07 '16 at 04:22
  • 1
    It does depend what you set it to. If you set it to a local variable that goes out of scope then you get undefined behavior. – John3136 Dec 07 '16 at 04:25
  • so perhaps it is in setting outputName=argv[2] since that is local and then trying to use that pointer outside of main? – liverr1818 Dec 07 '16 at 04:27
  • You should look into [proper C formatting](http://prohackr112.tk/r/proper-c-formatting). Or learn how to [thoroughly obfuscate your code](//prohackr112.tk/r/proper-c-obfuscation). – MD XF Dec 07 '16 at 05:10
  • 1
    I did compile your code and it works like a charm. Are you sure this exact piece of code crash on your computer? – Joël Hecht Dec 07 '16 at 06:15
  • The duration of `argv` in `main()` is long enough that it is unlikely you'll run into problems with `outputName = argv[2];` — there are ways to run into problems, but you probably wouldn't be asking this question if you were using them (`atexit()`, etc). – Jonathan Leffler Dec 07 '16 at 06:20
  • 1
    Note that you should terminate `printf()` outputs with newlines if you want to be reasonably sure they'll appear; use `fflush(stdout);` as well if you want greater certainty. Then note [How to avoid using `printf()` in a signal handler](http://stackoverflow.com/questions/16891019/). You will probably get away with — it is unlikely to be the cause of your trouble, but since you don't show any code after the assignment to `outputName`, it is hard to know what you're doing. You say you use `outputName`, but the only place shown that uses it is in the signal handler. Are you interrupting it? – Jonathan Leffler Dec 07 '16 at 06:23
  • @JoëlHecht I edited my code to show my whole code..believe maybe it is with errno now? – liverr1818 Dec 07 '16 at 14:49
  • I tried your code and it crashes with segmentation fault in the `isNumber` function : it is because `i` is not initialized to `0` when the number doesn't begin with the `-` sign. I also add a `signal(SIGSEGV, catcher);` line in your code to catch the exception and the catcher works ok, catching the segmentation fault exception. – Joël Hecht Dec 08 '16 at 06:22

2 Answers2

3

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()

Pras
  • 4,047
  • 10
  • 20
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.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547