Search code examples
cstrcpycalloc

why does strcpy copies more character to the variable than it is supposed to?


I am currently working on with lots of strcpy' and calloc's. And then I heard that strncpy is safer to use. So what I did was create a function that will handle strcpy.. It is shown below.

void safeStrncpy(char * dest, char * src){
    //copy string 
    if(sizeof(dest) >= strlen(src) + 1){
        strncpy(dest, src, strlen(src));
    }else{
        if(realloc(dest, (strlen(src)) + 1) == NULL){
            printf("error");    
        }else{
            strncpy(dest, src, strlen(src));
        }
    }
}

You'll notice that I used sizeof(dest) . What I really want to do with that part is get the size of the memory allocated to dest so I'll know when to use realloc. But then I learned that you can't get the size of memory allocated to dest so I think of a workaround.

char * l = calloc(10,sizeof(char));
printf("%s", strcpy(l,"asdfghjkldfghasdfghjkl"));

The code shown above allocates 10 items to the pointer l. I thought that If I did that and copied more characters than what is allocated, it will just copy what fits to the size.. I was expecting that the value of l would be "asdfghjkld". But, to my surprise, it didn't. It copied the whole string which is this "asdfghjkldfghasdfghjkl".

Now, why use calloc if it will just be overridden? what happens in the background during char pointer declaration, memory allocation and strcpy? does c automatically reallocates the memory? Do I need to worry of this behavior, security issues maybe?


Solution

  • You asked:

    why does strcpy copies more character to the variable than it is supposed to?

    The documentation of strcpy:

    Copies the C string pointed by source into the array pointed by destination, including the terminating null character (and stopping at that point).

    To avoid overflows, the size of the array pointed by destination shall be long enough to contain the same C string as source (including the terminating null character), and should not overlap in memory with source.

    It doesn't specify how a program should behave should the destination be not long enough to contain the source. Most likely, your implementation simply writes over memory that is out of bounds, which would lead to undefined behavior.

    Here's a possible solution.

    1. Create a struct that hold the char* and a size.

      typedef struct _MyString
      {
         char* data;
         size_t size;
      } MyString;
      
    2. Use it in the safeStrncpy

      void safeStrncpy(MyString* dest, char * src){
        if(dest->size < strlen(src) + 1){
          dest->size = strlen(src)+1;
          dest->data = realloc(dest->data, dest->size);
        }
        strcpy(dest->data, src);
      }