Home > Blockchain >  Why does the char* pointer value change when uncommenting the given line?
Why does the char* pointer value change when uncommenting the given line?

Time:04-25

The address pointed by variable "string" is different to that of argv[1] when commenting and uncommenting line 9.

This behavior was observed in gcc from msys2 11.2.0
However, the result was as expected when compiled from and run in Ubuntu gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0

Is this behavior undefined in C? What is causing the main problem here?

Test Case: compile and run by giving a argument
Eg: gcc main.c -o main.exe <br> .\main.exe test.txt

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
    char *string = argv[1];
    char string2[sizeof(string)];
    //strcpy(string2, argv[1]);     //line 9

    printf("%p\n", string);
    printf("%p\n", argv[1]);
    printf("sizeof(string) = %lu\n", sizeof(argv[1]));
    printf("length of string = %lu\n", strlen(string));
    printf("%s\n", string);

    return 0;
}

Screenshot:
Top --> Before Uncommenting line 9
Bottom --> After Uncommenting line 9

CodePudding user response:

Your code has potential undefined behavior when you uncomment the call to strcpy():

The definition char string2[sizeof(string)]; defines an array of char with a length of 4 or 8 depending on the size of a pointer on your target.

You are probably copying a string that does not fit in the destination array, causing undefined behavior (such as overwriting other data as you observe).

If you want to make a copy of the string in argv[1], you should first check that a command line argument was given and use:

 char string2[strlen(string)   1];

The extra byte is required to store the null terminator copied by strcpy().

Try this modified version:

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]) {
    if (argc > 1) {
        char *string = argv[1];
        char string2[strlen(string)   1];
        strcpy(string2, string);

        printf("%p\n", string);
        printf("%p\n", argv[1]);
        printf("sizeof(string) = %zu\n", sizeof(string));
        printf("strlen(string) = %zu\n", strlen(string));
        printf("%s\n", string);
    }
    return 0;
}

CodePudding user response:

First,

Change this:

char string2[sizeof(string)];

To account for the possibility that string and argv[1] can be undefined or null. Further, you need this array to measure the length of the string, not the size of the pointer - which is always going to be 4 or 8.

char string2[(argc> 1) ? (strlen(string) 1) : 1];

The above will size string2 to be long enough to hold a string copy from string ( 1 for the null char) if it's not null to begin with. Otherwise, it's an array of length 0.

Second, your printf statements using %lu should explicitly push an unsigned long onto the call stack. It probably happens to be ok since only one arg is getting pushed per call. printf does't do great with null arguments either, so we can fix that up too.

Here's a cleaned up version of your code with some suggested corrections.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    char* string = argv[1];
    char string2[(argc> 1) ? (strlen(string) 1) : 0];

    if (argv[1])
    {
        strcpy(string2, argv[1]);
    }

    printf("%p\n", string);
    printf("%p\n", argv[1]);
    printf("sizeof(string) = %lu\n", (unsigned long)(sizeof(argv[1])));
    printf("length of string = %lu\n", (unsigned long)(string ? strlen(string) : 0));
    printf("%s\n", string?string:"<nil>");

    return 0;
}
  • Related