LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Problems in C with free( ) (https://www.linuxquestions.org/questions/programming-9/problems-in-c-with-free-355040/)

zaichik 08-19-2005 08:19 PM

Problems in C with free( )
 
Hello everyone,

Hoping to get some help with a function I have written. It takes a string which is an IP address in dotted decimal notation and returns the equivalent integer value, i.e. given "1.0.0.1" it should return 16777217.

The problem I am having is memory allocation (standard n00b problem). The string gets tokenized with strtok() into its four octets, each of which is char*. I malloc memory to each octet, and strtok() the address into them. For example, when I enter the IP address "1.2.3.4", output in the debugger is as follows:
Code:

89      printf( "tempAddr = %s\n", tempAddr );
(gdb)
tempAddr = 1.2.3.4
90              octet1 = strtok( tempAddr, "." );
(gdb)
91              octet2 = strtok( NULL, "." );
(gdb)
92              octet3 = strtok( NULL, "." );
(gdb)
93              octet4 = strtok( NULL, "\0" );
(gdb)
95              free( tempAddr );
(gdb) print octet1
$1 = 0x8287020 "1"
(gdb) print octet2
$2 = 0x8287022 "2"
(gdb) print octet3
$3 = 0x8287024 "3"
(gdb) print octet4
$4 = 0x8287026 "4"

That's fine. But look what happens when I push on, and try to print out the values of the string octets with printf():
Code:

(gdb) step
97      printf( "String octets:\toctet1 = %s\toctet2 = %s\toctet3 = %s\t octet4 = %s\n", octet1, octet2, octet3, octet4 );   
(gdb)
String octets:  octet1 =        octet2 =        octet3 = 3      octet4 = 4

Oops. octet1 and octet2 suddenly have no value. What the...?
Finally, when I try to free the memory allocated to the octets, it seems that kernel says "No way!" and the program segfaults on free( octet2 ):
Code:

(gdb) step
105            free( octet1 );
(gdb)
106            free( octet2 );
(gdb)

Program received signal SIGSEGV, Segmentation fault.
0x00e78057 in _int_free () from /lib/tls/libc.so.6

I'm lost. I have copied and pasted this code from another function I have that needs to parse an IP address into octets, and it works fine in that function.

Looking at the above output, the addresses look right. The allocation is
Code:

octetX = ( char * ) malloc( 4 );
and it looks like they have each gotten 4 bytes.

I have posted the code at http://zaichik.org/convert_ip.c along with a few sample runs in a comment block at the bottom. Let me know if that is not kosher and I will post it here.

TIA for any ideas.

sind 08-20-2005 12:41 AM

Hi zaichik,

IIRC strtok() returns a pointer to the substring that it finds, which means that free()ing the memory for the original string (tempAddr) will make those pointers invalid - there is no guarantee that the data will remain there, and it is possible that accessing that area of memory will raise a segmentation fault.

When you call strtok() and put the return value in one of your octet pointers, you are overwriting the address stored in those pointers, not storing the octet characters in the memory that you have allocated. This creates two problems; first, it makes a memory hole, as you've allocated memory and no longer have the address to it, thus the memory cannot be freed until the process is finished. Secondly, a call to free() on one of your octet pointers will be invalid, because they are pointing to an area of memory that has not been allocated by a call to malloc() (you might get away with it for octet1 because it will likely point to the address allocated by malloc() for tempAddr - Edit: although seeing as you have already free()d that memory this can cause even more trouble).

I hope that that makes some kind of sense... I'm a bit tired today. ;) I didn't look at your code thouroughly so there might be some other problems...

HTH

~sind

Edit:
BTW, as you can read elsewhere in this forum, it is not necessarily a good idea to cast the return value of malloc(). See http://www.linuxquestions.org/questi...99#post1727999

Also, it might be worthwhile using sscanf() rather than strtok(), like so:

Code:

char *ip = "12.34.56.789";
int oct1, oct2, oct3, oct4;

sscanf(ip, "%d.%d.%d.%d", &oct1, &oct2, &oct3, &oct4);

printf("oct1: %d, oct2: %d, oct3: %d, oct4: %d\n", oct1, oct2, oct3, oct4);


zaichik 08-20-2005 05:55 PM

Hello sind,

OMG...

I feel stupid now. I was even using sscanf in the original code. I used strtok to break the IP into string octets, and then
sscanf to read the string octets into int octets. Original code has gone from:
Code:

int dotted_to_int( char *addr ) {

        char *tempAddr;
        int answer;
        char *octet1;
        char *octet2;
        char *octet3;
        char *octet4;
        int oct1 = 0, oct2 = 0, oct3 = 0, oct4 = 0;
        int FIRST_OCT_MULTIPLIER = 16777216;
        int SECOND_OCT_MULTIPLIER = 65536;
        int THIRD_OCT_MULTIPLIER = 256;
        char *myName = "convert_ip";

        tempAddr = ( char * ) malloc( MAX_SIZE_IPADDR );
        if( tempAddr == NULL ) {
        fprintf( stderr, "%s: Out of memory in dotted_to_int()\n", myName );
        exit( -1 );
        }

        octet1 = ( char * ) malloc( MAX_SIZE_OCTET );
        if( octet1 == NULL ) {
                fprintf( stderr, "%s: Out of memory in dotted_to_int()\n", myName );
        free( tempAddr );
                exit( -1 );
        }

        octet2 = ( char * ) malloc( MAX_SIZE_OCTET );
        if( octet2 == NULL ) {
                fprintf( stderr, "%s: Out of memory in dotted_to_int()\n", myName );
                free( tempAddr );
        free( octet1 );
                exit( -1 );
        }
       
        octet3 = ( char * ) malloc( MAX_SIZE_OCTET );
        if( octet3 == NULL ) {
                fprintf( stderr, "%s: Out of memory in dotted_to_int()\n", myName );
                free( tempAddr );
                free( octet1 );
        free( octet2 );
                exit( -1 );
        }

        octet4 = ( char * ) malloc( MAX_SIZE_OCTET );
        if( octet4 == NULL ) {
                fprintf( stderr, "%s: Out of memory in dotted_to_int()\n", myName );
                free( tempAddr );
                free( octet1 );
        free( octet2 );
        free( octet3 );
                exit( -1 );
        }

        strcpy( tempAddr, addr );
        octet1 = strtok( tempAddr, "." );
        octet2 = strtok( NULL, "." );
        octet3 = strtok( NULL, "." );
        octet4 = strtok( NULL, "\0" );

        free( tempAddr );
                 
        sscanf( octet1, "%d", &oct1 );
        sscanf( octet2, "%d", &oct2 );
        sscanf( octet3, "%d", &oct3 );
        sscanf( octet4, "%d", &oct4 );

        answer = oct1 * FIRST_OCT_MULTIPLIER + oct2 * SECOND_OCT_MULTIPLIER + oct3 * THIRD_OCT_MULTIPLIER + oct4;
        free( octet1 );
        free( octet2 );
        free( octet3 );
        free( octet4 );
        return( answer );
}

to

Code:

int dotted_to_int( char *addr ) {

        int answer;
        int oct1 = 0, oct2 = 0, oct3 = 0, oct4 = 0;
        int FIRST_OCT_MULTIPLIER = 16777216;
        int SECOND_OCT_MULTIPLIER = 65536;
        int THIRD_OCT_MULTIPLIER = 256;

        sscanf( addr, "%d.%d.%d.%d", &oct1, &oct2, &oct3, &oct4 );
        answer = oct1 * FIRST_OCT_MULTIPLIER + oct2 * SECOND_OCT_MULTIPLIER + oct3 * THIRD_OCT_MULTIPLIER + oct4;
        return( answer );
}

Embarrassing, really. :o

Thanks again, sind. Good stuff!

jonaskoelker 08-20-2005 08:56 PM

That's why you *don't* measure programmer productivity in #lines of code :D

--Jonas

sind 08-21-2005 06:25 AM

Quote:

zaichik wrote:
Thanks again, sind. Good stuff!
Glad that I could help. :)

~sind


All times are GMT -5. The time now is 01:38 AM.