awatan
awatan

Reputation: 1210

Segmentation fault while accessing the return address from a C function in 64 bit machine

I have code in C (linux(x86_64)) some like this:

typedef struct 
{
   char k[32];
   int v;
}ABC;

ABC states[6] = {0};

ABC* get_abc()
{
   return &states[5];
}  

while in main():

int main()
{
  ABC *p = get_abc();
     .
     .
     .
  printf("%d\n", p->v); 
} 

I am getting segmentation fault at printf statement while accessing p->v. I tried to debug it from gdb and it says "can not access the memory". One important thing here is that when I compile this code, gcc throws me a warning on ABC *p = get_abc(); that I am trying to convert pointer from integer. My question here is that I am returning address of structure from get_abc() then why compiler gives me such warning? why compiler considers it as integer? I think I am getting segmentation fault due to this warning as an integer can not hold memory address in x86_64.

Any help would be appreciated.

Upvotes: 2

Views: 1308

Answers (2)

rashok
rashok

Reputation: 13414

Define the get_abc prototype before main function. If function prototype is not available before that function call means, compiler will treat that function by default as passing int arguments and returning int. Here get_abc actually returning 8 byte address, but that value has been suppressed to 4 bytes and it is stored in ABC *p variable which leads the crash.

ABC* get_abc(); 
int main()
{
    ABC *p = get_abc();
}

Note : This crash will not occur in 32 bit machine where size of int and size of address is 4 bytes, because suppression will not happen. But that warning will be there.

Upvotes: 5

Keith Thompson
Keith Thompson

Reputation: 263177

You haven't shown us all your code, but I can guess with some confidence that the get_abc() and main() functions are defined in separate source files, and that there's no visible declaration of get_abc() visible from the call in main().

You should create a header file that contains a declaration of get_abc():

ABC *get_abc();

and #include that header both in the file that defines get_abc() and in the one that defines main(). (You'll also need header guards.) You'll need to move the definition of the type ABC to that header.

Or, as a quick-and-dirty workaround, you can add an explicit declaration before your definition of main() -- but that's a rather brittle solution, since it depends on you to get the declaration exactly right.

In the absence of a visible declaration, and undeclared function is assumed to return int. The compiler sees your call to get_abc(), generates code to call it as if it returned an int, and implicitly converts that int value to a pointer. Hilarity ensues.

Note: There actually is no implicit conversion from int to pointer types, apart from the special case of a null pointer constant, but many compilers implement such an implicit conversion for historical reasons. Also, the "implicit int" rule was dropped in the 1999 version of the standard, but again, many compilers still implement it for historical reasons. Your compiler should have options to enable better warnings. If you're using gcc, try gcc -pedantic -std=c99 -Wall -Wextra.

Upvotes: 2

Related Questions