SamBkamp
SamBkamp

Reputation: 75

Returning malloc'd structs gives segfault and different address

Im developing a library that deals with certain network connections in C, and my plan was for the init function to return a struct containing all relevant data for the connection that the caller will then pass to any of the library functions. I also want the contents of the struct to be accessible to the caller.

Here is my init (library) code

//here is the struct
typedef struct {
  SSL_CTX* ctx;
  SSL* ssl;
  int socket;
  int usingSSL;
} twitch_connection;


struct twitch_connection* twlibc_init(int usingSSL){ //returns a pointer to a struct that has to be freed
  twitch_connection *temp;
  temp = malloc(sizeof(twitch_connection)); //creates the address for the struct
  struct sockaddr_in twitchaddr;
  ...
  if(usingSSL == 0){
    //not using SSL
    temp->ctx = NULL;
    temp->ssl = NULL;
  }else {
    //using SSL
    temp->ctx = ctx; //how I assign values to the struct
    temp->ssl = ssl;
  }
  
  temp->socket = twitchsock;

  return temp; //returns the struct back to caller
}

here is the code from my demo

int main(){
  
  twitch_connection* twlibc = twlibc_init(1);

  
  printf("address of struct from main of callers code is: %p\n", twlibc);
}

However when I printf the addresses of the struct I get different results when printing from different areas in the code:

address of struct from inside init function: 0x56299befd260
address of struct from main of callers code is: 0xffffffff9befd260

and if I try to printf a member of the struct from the main function I get a segmentation fault.

Upvotes: 0

Views: 35

Answers (1)

dxiv
dxiv

Reputation: 17628

twitch_connection* twlibc = twlibc_init(1);

Since twlibc_init was not declared at this point, C assumes that the return value is an int, so the above is equivalent to twlibc = (twitch_connection*)(int)twlibc_init(1);.

On a 64-bit platform with 32-bit int type this will truncate 0x56299befd260 to a 32-bit integer 0x9befd260 then sign-extend it to a 64-bit pointer 0xffffffff9befd260.

The solution is to declare the function struct twitch_connection* twlibc_init(int usingSSL); in the main file or, even better, move the declarations to a common header included in both places.


[ EDIT ]   The sign-extension when casting an int to a pointer is implementation dependent and not guaranteed by the C standard, so another compiler might have printed 0x9befd260 instead or, indeed, anything. From the cppreference C cast operator page:

Any integer can be cast to any pointer type. Except for the null pointer constants such as NULL (which doesn't need a cast), the result is implementation-defined, may not be correctly aligned, may not point to an object of the referenced type, and may be a trap representation.

Upvotes: 1

Related Questions