1
votes

I have below code where I have commented when I get segmentation fault and when not.

Originally I got segmentation fault and then I could figure out that probably I cannot initialize my char pointer locations like "abcd". But I am not able to understand - WHY?

I thought testString = "abcd"; will put a at first memory address, b at second and so on ...

Segmentation fault occurs when trying to free memory, based on how I initialize memory location.

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

int main(void)
{
    char* testString = malloc(sizeof(char) * 5);

    printf("Size of char is: %d\n", sizeof(char));
    printf("Size of int is: %d\n", sizeof(int));

    for(int i = 0; i < 5; i++)
    {
        printf("Pointer addresses are: %p\n", testString + i);
    }

    char* tempPtr = testString + 2;
    printf("My temp pointer address = %p\n", tempPtr);

    // This gives me segmentation fault ....
    testString = "abcd";

    // This will not give me segmentation fault ....    
    //int count = 65;
    //for(int i = 0; i < 5; i++)
    //{
    //    testString[i] = count + i;
    //}

    printf("Printing character...\n");

    for(int i = 0; i < 5; i++)
    {
        printf("Characters are: %c\n", testString[i]);
    }

    printf("Freeing memory...\n");
    free(testString);

    //printf("Access after freeing >>%c<<\n", tempPtr[0]);
    //free(testString);
}


Based on @M.M. and @Jonathan's comment I understood that with testString = "abcd"; my testString will point to a memory location where string "abcd" was created and since I didn't malloc'ed it I cannot free it. Also, since my original pointer to heap memory (which I got using malloc) is gone, so it is waste of memory or memory lead.

So, does it means that when I use printf statement like printf("Printing character...\n");, this is also a memory leak? Then how do I avoid it? Looping and inserting into char* is certainly a bad idea.

3
testString = "abcd" means that the pointer testString will now point to the memory location containing "abcd". Then you try to free that location, causing segmentation fault. - M.M
Note that testString = "abcd"; throws away the pointer to the allocated memory (a memory leak). You need strcpy() instead, perhaps. And since the string literal (pointer value) was not returned by malloc() (or calloc() or realloc()), you can't free it. - Jonathan Leffler
@l3x I didn't want to use some build-in functions and wanted to achieve most basic ways. Thanks for comment though. - hagrawal
The memory leak occurs because testString contains the only pointer to the allocated memory. When you assign testString = "abcd", you assign a new, different pointer value to testString. You can no longer free the pointer that was returned by malloc() because you no longer have a record of what it was. The string "abcd" exists in your program's memory space somewhere; it isn't a memory leak. It's the pointer overwrite that causes the leak. The printf("…") operation does not leak memory. - Jonathan Leffler
The string "abcd" will exist somewhere in memory. It is quite likely to be in the text segment since string literals are read-only, but the standard doesn't mandate anything about segments. It won't be in the heap area managed by malloc(); it probably won't be on the stack, either. It will most likely either be in the data segment or in the text segment — these days, in the text segment, though historically, it would have been in the data segment. - Jonathan Leffler

3 Answers

1
votes

this line:

testString = "abcd";

is overlaying the pointer given by the call to malloc() with the address of the string literal: "abcd" this results in a memory leak because the original pointer to the allocated memory is lost.

In C, when copying a string, it 'should' be handled by the functions: strcpy() and strncpy() which will not corrupt the pointer contained in testString.

strcpy( testString, "abcd" );
strncpy( testString, "abcd", strlen( "abcd" ) );

Naturally, once the pointer to the allocated memory has been overlayed/destroyed by the assignment statement: testString = "abcd";, the new value placed into testString must not be passed to free()

the seg fault would be happening at the call to free(), not at the incorrect assignment of a new pointer to testString.

1
votes

Using printf is not a memory leak. Memory leaks occur when a pointer is allocated via malloc [or, herein, strdup] and there is no corresponding free call for it.

Also, trying to free a pointer that has not been allocated is another type of error. It [probably] won't segfault, but free will complain.

Here's a simplified version of your program that illustrates some of the ways you can do this:

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

int opt_segv;

char *temp = "abcd";

void
dostr(char *str,int modflg)
{

    printf("\n");
    printf("dostr: %s\n",str);
    if (modflg)
        str[modflg] = 'm';
    printf("dostr: %s\n",str);
}

void
test1(void)
{
    int len;
    char *testString;

    len = strlen(temp);
    testString = malloc(len + 1);
    strcpy(testString,temp);

    dostr(testString,1);

    free(testString);
}

void
test2(void)
{
    char *testString;

    testString = strdup(temp);

    dostr(testString,2);

    free(testString);
}

void
test3(void)
{
    char *testString;

    // passing a pointer to a string _constant_ -- do _not_ modify
    testString = temp;

    dostr(testString,opt_segv ? 3 : 0);
}

int
main(int argc,char **argv)
{
    char *cp;

    --argc;
    ++argv;

    for (;  argc > 0;  --argc, ++argv) {
        cp = *argv;
        if (*cp != '-')
            break;

        switch (cp[1]) {
        case 's':  // generate segfault
            opt_segv = 1;
            break;
        }
    }

    test1();
    test2();
    test3();

    return 0;
}

You can run the program with -s to simulate the string constant modification that caused your segfault.

1
votes

This question has content relevant to answer of my question but doesn't have detailed answer. @Jonathan's comments answers all my questions but he hasn't put forward a detailed answer so I am writing my answer so that folks who will visit further can have detailed explanation:

I created a pointer and allocated some space on "heap segment" of the memory, now my pointer was pointing to that memory location on heap.
Code relevant for all this is - char* testString = malloc(sizeof(char) * 5);.

Now, when I dis this - testString = "abcd"; then string "abcd" is created in "text/code segment" (or in some implementation data segment) of the memory and memory address is returned and assigned to my pointer testString.
What happens is that my original pointer which was pointing a memory location on heap is lost and the pointer started pointing to a memory location on text/code segment of the memory.

Implication of all this:

  • It has resulted in memory leak because my original pointer which was pointing to the heap memory is lost, so now I have no way to free that heap memory and hence memory leak.
  • When I will try to free that memory using free(testString); then I will get segmentation fault (this is exactly what has happened to me) because free() can only be used to free the memory which is allocated using either malloc, calloc or realloc. Now, since the pointer testString is pointing to a memory location on text/code segment and I had not allocated that memory using some C memory allocation method, so I cannot free it using free() and if I do so then I get segmentation fault.
  • When I do testString = "abcd" (when testString is a pointer) then I cannot access the memory location pointed by testString because the memory allocated is read-only in text/code segment of the memory. So, testString[0] = 'x' will also result in segmentation fault.

What happens when I do printf("hello, world")?:
This will create "hello, world" string as read-only in text/code segment of memory. I verified that it does create in text/code segment in C99 implementation using size command.