Thread: can't free struct

  1. #16
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by tabstop View Post
    (And you wouldn't cast the struct to a pointer -- you would just hand the function the address of the variable instead.)
    &What?!!!?
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  2. #17
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Quote Originally Posted by MK27 View Post
    &What?!!!?
    On the guess that that's a serious question, something like so:
    Code:
    int main() {
        struct in_addr address;
        struct hostent test;
        SomeMythicalFunctionThatTakesAnAddress(&address);
        SomeOtherFunction(&test);
    }
    You weren't using &address with the code you had, were you? That wouldn't pass a pointer to a struct, that would pass a pointer to a pointer to a struct, which means that your function would cheerfully write to where your malloc information was (which means that when you tried to free it, bad things would happen ... wait a minute...).

    Edit: I should be more clear, there, I think: you'll cheerfully write to where your pointer that came back from malloc was. So instead of freeing your pointer, you're going to try to free your IP address (or whatever the first four bytes of that structure are).
    Last edited by tabstop; 11-27-2008 at 09:27 PM.

  3. #18
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by tabstop View Post
    You weren't using &address with the code you had, were you? That wouldn't pass a pointer to a struct, that would pass a pointer to a pointer to a struct, which means that your function would cheerfully write to where your malloc information was (which means that when you tried to free it, bad things would happen ... wait a minute...).
    No. The actual main() looks like this:
    Code:
    int main (int argc, char *argv[]) {
            char request[256], ascadd[4];
            int sock, bytes;
            struct in_addr *address=ec_malloc(sizeof(struct in_addr));
            struct sockaddr_in connto;
            struct hostent *test=ec_malloc(sizeof(struct hostent));    
    
            if (argc < 2) fatal(-1,"Grab what image?");
            if ((sock=socket(PF_INET,SOCK_STREAM,0))==-1) perror("socket");
            address=parseaddr(argv[1]);
    
            sprintf(ascadd, "&#37;s", inet_ntoa(*address));    
            printf("Connecting to %s\n",ascadd);
            connto.sin_family=AF_INET;
            connto.sin_port=htons(80);
            connto.sin_addr.s_addr=address->s_addr;
            memset(&(connto.sin_zero),0,8);
            if (connect(sock,(struct sockaddr*)&connto,sizeof(struct sockaddr))==-1) {
                    perror("!connect");
                    fatal(-3,"...failed.");}
        
            sprintf(request,"GET %s HTTP/1.0\r\n\r\n",imagepath);
            printf("sending %s",request);
            if (Transmit(sock,request)!=0) perror("!send");
            bytes=getpage(sock);
            printf("____PARTIAL HEADER____\n%s\n----------------------\n\nGrabbed Image Size: %d\n",reply,bytes);
            free(reply);
        
            if ((test=gethostbyaddr((const char*)&connto.sin_addr.s_addr,4,AF_INET))==NULL) printf("gethostbyaddr error: %d\n",h_
            else printf("server hostname: %s\n",test->h_name);
    
            return 0;
    }
    I guess this is a bad habit I had started to acquire w/r/t not just using a static struct. I think it comes from using lots of gtk+ structs which really are just pointers to parts of other, already allocated material. I actually remember tacking the malloc calls in there at some point because of this. Thanks. I still haven't found the original corruption source tho.
    Last edited by MK27; 11-27-2008 at 09:34 PM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  4. #19
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    So that's what we mean -- assigning the result of parseaddr to address completely clobbers the pointer that came back from malloc (meaning those freshly malloc'ed bytes are gone forever), leaving address pointing to something that may or may not exist (if the address struct is local to the function, then NOT).

    If the function parseaddr is to return a pointer, then parseaddr needs to malloc the memory (NOT main), and you can free that memory later.

  5. #20
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by tabstop View Post
    So that's what we mean -- assigning the result of parseaddr to address completely clobbers the pointer that came back from malloc (meaning those freshly malloc'ed bytes are gone forever), leaving address pointing to something that may or may not exist (if the address struct is local to the function, then NOT).
    enlightenment.

    Quote Originally Posted by tabstop View Post
    If the function parseaddr is to return a pointer, then parseaddr needs to malloc the memory (NOT main), and you can free that memory later.
    Okay, that's actually what I would usually do. Now here's a related question (I'm sure this is how I ended up here, because I just tried changing *test). gethostbyname() (and gethostbyaddr) requires a pointer to a struct hostent and you can't declare one and try (struct hostent*)info=gethostbyname or &info=gethostbyname. So does the pointer returned by gethostbyname() need to be freed? I think it can't so, I guess there's the answer...
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  6. #21
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    They return a pointer to a struct, yes. According to the bottom of the man page:
    Code:
    These functions use static data storage; if the data is needed for future
         use, it should be copied before any subsequent calls overwrite it.
    So the memory is owned by gethostbyname -- but its declared static, so one copy with program lifetime storage, not malloc'ed memory. So no, it can't be freed. So you should be able to do
    Code:
    struct hostent *test;
    test = gethostbyname(argv[1]);
    or whatever your parseaddr does, without any extra memory.

    (Now, if you do need to save it, you would want to copy it into a "real" struct, but it sounded like you don't.)

  7. #22
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Okay, so as long I don't call gethostbyname() again, I can just pass around pointers to its stuff?

    Here's a weird thing about in_addr: inet_aton() actually outputs into a struct in_addr*. If you do this:
    Code:
    struct in_addr netaddr;
    char *ascaddr;
    inet_aton(ascaddr,&netaddr);
    It passes the compiler but the contents of netaddr end up bogus. I have to do this:
    Code:
    struct in_addr netaddr, *ptr=&netaddr;
    char *ascaddr;
    inet_aton(ascaddr,ptr);
    to get it to work

    ps. would malloc'ing "test" then etc. explain why freeing them would be a double free? Or should I still be looking for memory corruption?
    Last edited by MK27; 11-27-2008 at 10:51 PM.

  8. #23
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Quote Originally Posted by MK27 View Post
    Okay, so as long I don't call gethostbyname() again, I can just pass around pointers to its stuff?

    Here's a weird thing about in_addr: inet_aton() actually outputs into a struct in_addr*. If you do this:
    Code:
    struct in_addr netaddr;
    char *ascaddr;
    inet_aton(ascaddr,&netaddr);
    It passes the compiler but the contents of netaddr end up bogus. I have to do this:
    Code:
    struct in_addr netaddr, *ptr=&netaddr;
    char *ascaddr;
    inet_aton(ascaddr,ptr);
    to get it to work

    ps. would malloc'ing "test" then etc. explain why freeing them would be a double free? Or should I still be looking for memory corruption?
    You'll have to show more with that example; the following works as I would expect:
    Code:
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    
    int main(void) {
        struct in_addr netaddr;
        char *ascaddr = "127.0.0.1";
        inet_aton(ascaddr, &netaddr);
        printf("&#37;lx\n", netaddr.s_addr);
        return 0;
    }
    And yes, the reassigning test then freeing would cause a corruption error at runtime.

  9. #24
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Okay, how do you like this behaviour (maybe it's my code...)!

    Code:
    struct in_addr parseaddr (char *addr) {
            struct hostent *info;
            struct in_addr address, *ptr=&address;
            char *end;
            if ((strncmp(addr,"http",4))==0) pretrunc(addr,7);
            if ((end=strchr(addr,'/'))==NULL) fatal(-2,"Grab what image?");
            end[0]=0;
            imagepath=++end;
            if (strlen(imagepath)<6) fatal(-22,"Grab what image?");
            if ((imname=strrchr(imagepath,'/'))==NULL) imname=imagepath;
            imname++;
            printf("Grabbing &#37;s from %s...\n",imname,addr);
            info=gethostbyname(addr);
            inet_aton(info->h_addr,&address);
            printf("**%s**\n",inet_ntoa(address));
            return address;
    }
    Witness *ptr is actually unused because you're right, &address works BUT ONLY IF I LEAVE *ptr=&address in. Otherwise I repeatedly get **2.0.0.0** regardless of the address.
    I just tried this all three ways like five or ten times and then went thru them again. And again. Definately the way I had it works, inet_aton(info->h_addr,ptr), then after I change it to inet_aton(info->h_addr,&address) it works, but after I remove the unused *ptr=&address it won't...could it be memory corruption again and the extra pointer is a space that takes the damage?

    ps. no this is not quite the original "struct in_addr *parseaddr ()"
    Last edited by MK27; 11-27-2008 at 11:23 PM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  10. #25
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Alright, I don't know about your gethostbyname, but my gethostbyname doesn't actually return readable things in the h_addr field. Code:
    Code:
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #include <netdb.h>
    int main(void) {
        struct hostent *info;
        struct in_addr address;
        info = gethostbyname("www.cprogramming.com");
        printf("Gethostbyname says name: %s\n", info->h_name);
        printf("Gethostbyname says addr: %s\n", info->h_addr);
        /* inet_aton(info->h_addr, &address);
        printf("%lx\n", address.s_addr); */
        address.s_addr = *((int *)info->h_addr);
        printf("**%s**\n", inet_ntoa(address));
        return 0;
    }
    and output:
    Code:
    $ ./temp
    Gethostbyname says name: cprogramming.com
    Gethostbyname says addr: @"?X
    **64.34.169.88**

  11. #26
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    It's no wonder you get errors.
    You need to differentiate between pointer and pointee. The former is the actual variable that stores a memory address. It is not a of the type, so you can't store anything in it.
    If you must store something in it, you must first ask for a of the type, and store its address in the pointer, so it points to a pointee (malloc).
    However, seeing as a pointer is a variable that stores addresses, it is possible to assign another address to it. That will change what pointee it points to, it will not change the pointee itself.

    http://cboard.cprogramming.com/showp...3&postcount=31
    http://cboard.cprogramming.com/showp...65&postcount=4
    http://apps.sourceforge.net/mediawik...er_on_pointers
    http://cslibrary.stanford.edu/104/

    Some resources about pointers.
    And you must realize that:

    Code:
    struct in_addr netaddr;
    char* ascaddr;
    inet_aton(ascaddr, &netaddr);
    ...and...
    Code:
    struct in_addr netaddr;
    struct in_addr* ptr = &netaddr;
    char* ascaddr;
    inet_aton(ascaddr, ptr);
    ...does the very same thing. You are just storing the address of the struct in a temporary pointer and passing it as opposed to directly.
    And the first argument should probably be an address - ie a char array, and not an empty pointer. No function ever takes an empty pointer unless it takes an argument of type T**.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  12. #27
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by Elysia View Post
    And you must realize that:

    ...does the very same thing. .
    Yes. Did you actually read the question I was asking?
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  13. #28
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    If you mean
    It passes the compiler but the contents of netaddr end up bogus. I have to do this:
    to get it to work
    Then yes, and it can only (probably) be explained by undefined behavior.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  14. #29
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by Elysia View Post
    If you mean...

    Then yes, and it can only (probably) be explained by undefined behavior.
    Hopefully we're on the same page now then altho I may not be completely out of the woods.

    Anyway, I presume it is corruption, since this works:

    Code:
    #include <stdio.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <netdb.h>
    
    int main (int argc, char *argv[]) {
    	struct hostent *info=gethostbyname(argv[1]);
    	struct in_addr address;
    	inet_aton(info->h_addr,&address);
    	printf("%s is %s\n", info->h_name, inet_ntoa(address));
    }
    I just can't see where I went wrong in the other code.

    Unless I'm wrong about this bit. Again, the function (should) look like this (except for the red bit):
    Code:
    struct in_addr parseaddr (char *addr) {
    	struct hostent *info;
    	struct in_addr address, *ptr=NULL;  //unused 
    	char *end;
    	if ((strncmp(addr,"http",4))==0) pretrunc(addr,7);
    	if ((end=strchr(addr,'/'))==NULL) fatal(-2,"Grab what image?");
    	end[0]=0;
    	imagepath=++end;
    	if (strlen(imagepath)<6) fatal(-22,"Grab what image?");
    	if ((imname=strrchr(imagepath,'/'))==NULL) imname=imagepath;
    	else imname++;
    	printf("Grabbing %s from %s...\n",imname,addr);
    	info=gethostbyname(addr);
    	inet_aton(info->h_addr,&address);
    	printf("**%s**\n",inet_ntoa(address));
    	return address;
    }
    *addr points to argv[1]. pretrunc is just this:
    Code:
    void pretrunc (char *string, int chs) {
    	int i;
    	for (i=0;i<strlen(string);i++) string[i]=string[i+chs];
    	string[i]='\0';
    }
    "*end" is kind of extraneous, I could really just use the global "imagepath":
    Code:
    	if ((imagepath=strchr(addr,'/'))==NULL) fatal(-2,"Grab what image?");
    	imagepath[0]=0;
    	imagepath++;
    But guess what happens if I remove char *end? (Almost) the same thing as if I had removed *ptr=NULL, address is left overwritten. But all that happened up until now is this:
    Code:
    int main (int argc, char *argv[]) {
    	char request[256], ascadd[4];
    	int sock, bytes;
    	struct in_addr address;
    	struct sockaddr_in connto;
    	struct hostent *test;		
    
    	if (argc < 2) fatal(-1,"Grab what image?");
    	if ((sock=socket(PF_INET,SOCK_STREAM,0))==-1) perror("socket");
    	address=parseaddr(argv[1]);
    There's only two things I have any doubts about here: 1) I'm returning a struct wrong...not. 2) imagepath and imname are both global char* that I use to point into argv[1]. So they don't need any allocated space of their own, right?

    What else could be causing memory corruption at this point, such that I need this extra 4-8 bytes to protect address? I guess I'm untarring valgrind real soon...
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  15. #30
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by MK27 View Post
    What else could be causing memory corruption at this point, such that I need this extra 4-8 bytes to protect address? I guess I'm untarring valgrind real soon...
    That's why I said use a debugger. They are made for purposes such as this.
    A good debugger can detect whenever something is written in "those extra bytes."
    Or if you want, you can just step through the code with a debugger and watch those bytes.

    Quote Originally Posted by MK27 View Post
    2) imagepath and imname are both global char* that I use to point into argv[1]. So they don't need any allocated space of their own, right?
    No, they don't, since you are changing the pointer, not the pointee.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 16
    Last Post: 10-29-2006, 05:04 AM
  2. Dikumud
    By maxorator in forum C++ Programming
    Replies: 1
    Last Post: 10-01-2005, 06:39 AM
  3. Binary Search Tree
    By penance in forum C Programming
    Replies: 4
    Last Post: 08-05-2005, 05:35 PM
  4. Passing pointers between functions
    By heygirls_uk in forum C Programming
    Replies: 5
    Last Post: 01-09-2004, 06:58 PM
  5. Request for comments
    By Prelude in forum A Brief History of Cprogramming.com
    Replies: 15
    Last Post: 01-02-2004, 10:33 AM