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
On the guess that that's a serious question, something like so:
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...).Code:int main() { struct in_addr address; struct hostent test; SomeMythicalFunctionThatTakesAnAddress(&address); SomeOtherFunction(&test); }
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.
No. The actual main() looks like this:
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.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, "%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; }
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
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.
enlightenment.
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
They return a pointer to a struct, yes. According to the bottom of the man page:
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 doCode:These functions use static data storage; if the data is needed for future use, it should be copied before any subsequent calls overwrite it.
or whatever your parseaddr does, without any extra memory.Code:struct hostent *test; test = gethostbyname(argv[1]);
(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.)
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:
It passes the compiler but the contents of netaddr end up bogus. I have to do this:Code:struct in_addr netaddr; char *ascaddr; inet_aton(ascaddr,&netaddr);
to get it to workCode:struct in_addr netaddr, *ptr=&netaddr; char *ascaddr; inet_aton(ascaddr,ptr);
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.
You'll have to show more with that example; the following works as I would expect:
And yes, the reassigning test then freeing would cause a corruption error at runtime.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("%lx\n", netaddr.s_addr); return 0; }
Okay, how do you like this behaviour (maybe it's my code...)!
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.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 %s from %s...\n",imname,addr); info=gethostbyname(addr); inet_aton(info->h_addr,&address); printf("**%s**\n",inet_ntoa(address)); return 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
Alright, I don't know about your gethostbyname, but my gethostbyname doesn't actually return readable things in the h_addr field. Code:
and output: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; }
Code:$ ./temp Gethostbyname says name: cprogramming.com Gethostbyname says addr: @"?X **64.34.169.88**
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:
...and...Code:struct in_addr netaddr; char* ascaddr; inet_aton(ascaddr, &netaddr);
...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.Code:struct in_addr netaddr; struct in_addr* ptr = &netaddr; char* ascaddr; inet_aton(ascaddr, ptr);
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**.
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
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:
I just can't see where I went wrong in the other code.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)); }
Unless I'm wrong about this bit. Again, the function (should) look like this (except for the red bit):
*addr points to argv[1]. pretrunc is just this: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; }
"*end" is kind of extraneous, I could really just use the global "imagepath":Code:void pretrunc (char *string, int chs) { int i; for (i=0;i<strlen(string);i++) string[i]=string[i+chs]; string[i]='\0'; }
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:if ((imagepath=strchr(addr,'/'))==NULL) fatal(-2,"Grab what image?"); imagepath[0]=0; imagepath++;
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?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]);
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
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.
No, they don't, since you are changing the pointer, not the pointee.