warning: function returns address of local variable [enabled by default]

aDi Adam picture aDi Adam · Jun 26, 2013 · Viewed 31.6k times · Source
#include <string.h>
#include<stdio.h>
#include<stdlib.h>

char *chktype(char *Buffer, int Size)
{
   char *strng = "Content-Type: ";
   int sz;
   char *found = strstr (Buffer, strng);
   char *found1 = strstr(found, "\r\n");
   sz=strlen(found)-strlen(found1);
   char type[sz];
   strncpy(type, found1, sz-1);

   return(type);
}

void main(){

   char *buffer = "HTTP/1.1 200 OK\r\nDate: Tue, 25 Jun 2013 16:27:16
   GMT\r\nExpires: -1\r\nCache-Control: private,
   max-age=0\r\nContent-Type: text/html; 
   charset=UTF-8\r\nContent-Encoding: gzip\r\nServer: 
   gws\r\nX-XSS-Protection: 1; mode=block\r\nX-Frame-Options:
   SAMEORIGIN\r\nTransfer-Encoding: chunked\r\n\r\n";

   char *extension = chktype (buffer, sizeof(buffer));
   printf("%s\r\n", extension);
}

This yields:

warning: function returns address of local variable [enabled by 
default]

...and i can't figure out what is wrong here. When I run it, I expect the output to be text/html; charset=UTF-8 but its gibberish.

What does the warning mean exactly?

Answer

Cody Gray picture Cody Gray · Jun 26, 2013

The chktype function allocates memory for an automatic variable on the stack, and then returns the address of this variable (i.e., a pointer to this variable).

The problem is that variables allocated on the stack are automatically destroyed whenever they go out of scope (i.e., control passes outside of the curly braces that define the function).

This means that you're essentially returning a pointer to an invalid memory location, which is bad news. In C-speak, it's undefined behavior. In practical speak, it results in bad output or perhaps even a crash.

char *chktype(char *Buffer, int Size)
{
    // This pointer variable is allocated on the stack, but that's okay because
    // it's a pointer to a string literal, which are always constant.
    // (Technically, you should add the "const" qualifier to the declaration.)
    const char *strng = "Content-Type: ";

    int sz;
    char *found = strstr (Buffer, strng);
    char *found1 = strstr(found, "\r\n");
    sz=strlen(found)-strlen(found1);

    // Like all the above variables, the one is also allocated on the stack.
    // But it's the source of your problem here, because it's the one that
    // you are returning at the end of the function.
    // Problem is, it goes away at the end of the function!
    char type[sz];
    strncpy(type, found1, sz-1);
    return(type);
}

The correct way to return a char* from a function is to allocate new memory from the heap using the malloc (or calloc) function. That means that the caller of the function is going to be responsible for freeing the memory used by the returned value, otherwise your program will leak memory.
(Always put this requirement into the documentation for your function! Even if "documentation" means a comment above the declaration.)

For example, change your code to look like this:

char *chktype(char *Buffer, int Size)
{
    // This pointer variable is allocated on the stack, but that's okay because
    // it's a pointer to a string literal, which are always constant.
    // (Technically, you should add the "const" qualifier to the declaration.)
    const char *strng = "Content-Type: ";

    int sz;
    char *found = strstr (Buffer, strng);
    char *found1 = strstr(found, "\r\n");
    sz=strlen(found)-strlen(found1);

    char *type = malloc(sz);  // allocate memory from the heap
    strncpy(type, found1, sz-1);
    return(type);
}

Now, in the caller of the chktype function, you must make sure that you call free whenever you are finished with its return value:

char *type = chktype(...);
// do something
free(type);

Note that robust code should test the result of malloc for a null pointer to make sure that it did not fail to allocate the requested memory. If so, you need to handle the error somehow. For clarity, that isn't shown above.