Hi everyone,
I am writing a program in standard C that uses the MySQL library and the arpa/inet.h header to read some IP addresses stored as decimals, convert them to their respective dotted-format IPaddress with inet_ntop(), and store the results in another column of the same table with a MySQL query. That query string, which is called update_query, is concatenated from the original decimal value, the converted value, and some necessary syntax.
I developed this code in the Unix environent and compiled it with gcc. For some reason, it works on my 512MB Ubuntu 8.04 server, but it doesn't run (it gets a segmentation fault) on an ancient 512MB CentOS v4 server.
A backtrace via "gdb -q (filename)" reveals that the segmentation error happens when I first call realloc() in the while loop. Can someone please help me understand why, and what I can do to get this working on the older CentOS server?
Code:/* Simple C program that connects to MySQL Database server*/ #include <stdlib.h> #include </usr/include/mysql/mysql.h> #include <stdio.h> #include <arpa/inet.h> #include <string.h> #define MAX_QUERY_LENGTH 81 main() { MYSQL *conn; MYSQL_RES *res; MYSQL_ROW row; int i=0, j; char converted_addr[INET_ADDRSTRLEN]; unsigned long row_dec; char **updatearray; int uparr_size=1; char *server = "localhost"; char *user = "ipplan"; char *password = "*****"; /* password for database */ char *database = "ipplan"; conn = mysql_init(NULL); /* Connect to database */ if (!mysql_real_connect(conn, server, user, password, database, 0, NULL, 0)) { fprintf(stderr, "%s\n", mysql_error(conn)); exit(1); } /* send SQL query */ if (mysql_query(conn, "select ipaddr from ipaddr")) { fprintf(stderr, "%s\n", mysql_error(conn)); exit(1); } res = mysql_use_result(conn); /* output Decimal - Dotted IP addresses */ while ((row = mysql_fetch_row(res)) != NULL) { /* This is a test of inet_ntop() */ row_dec = htonl(atol(row[0])); inet_ntop(AF_INET, &row_dec, converted_addr, INET_ADDRSTRLEN); printf("%s\t-\t%s\n", row[0], converted_addr); char update_query[MAX_QUERY_LENGTH] = "update ipaddr set location=\'"; strcat(update_query, converted_addr); strcat(update_query, "\' where ipaddr=\'"); strcat(update_query, row[0]); strcat(update_query, "\'"); /* printf("%s\n", update_query); */ if ((updatearray = (char **)realloc(updatearray, (uparr_size++)*sizeof(char *)) ) == NULL ) { fprintf(stderr, "%s\n", "Error: Could not dynamically realloc() char **updatearray!"); exit(1); } if ((updatearray[i] = (char *)malloc(MAX_QUERY_LENGTH)) == NULL) { fprintf(stderr, "%s\n", "Error: Could not dynamically malloc() updatearray[i]!"); exit(1); } strncpy(updatearray[i], update_query, MAX_QUERY_LENGTH); i++; } /* free results from query */ mysql_free_result(res); for (j=0; j < i; j++) { printf("%s\n", updatearray[j]); if (mysql_query(conn, updatearray[j])) { fprintf(stderr, "%s\n", mysql_error(conn)); exit(1); } } /* close connection */ mysql_close(conn); return 0; }
You may want to initialize updatearray to NULL initially.
One idiom you want to avoid is this:Originally Posted by n1124
This will leak memory if realloc fails.Code:ptr = realloc(ptr, newsize);
Thank you for that! This is what my code now looks like, and it runs perfectly:
Code:/* Simple C program that connects to MySQL Database server*/ #include <stdlib.h> #include </usr/include/mysql/mysql.h> #include <stdio.h> #include <arpa/inet.h> #include <string.h> #define MAX_QUERY_LENGTH 81 main() { MYSQL *conn; MYSQL_RES *res; MYSQL_ROW row; int i=0, j; char converted_addr[INET_ADDRSTRLEN]; unsigned long row_dec; char **updatearray = NULL, **tmp; char *server = "localhost"; char *user = "ipplan"; char *password = "*****"; /* set me first */ char *database = "ipplan"; conn = mysql_init(NULL); /* Connect to database */ if (!mysql_real_connect(conn, server, user, password, database, 0, NULL, 0)) { fprintf(stderr, "%s\n", mysql_error(conn)); exit(1); } /* send SQL query */ if (mysql_query(conn, "select ipaddr from ipaddr")) { fprintf(stderr, "%s\n", mysql_error(conn)); exit(1); } res = mysql_use_result(conn); /* output Decimal - Dotted IP addresses */ while ((row = mysql_fetch_row(res)) != NULL) { /* This is a test of inet_ntop() */ row_dec = htonl(atol(row[0])); inet_ntop(AF_INET, &row_dec, converted_addr, INET_ADDRSTRLEN); printf("%s\t-\t%s\n", row[0], converted_addr); char update_query[MAX_QUERY_LENGTH] = "update ipaddr set location=\'"; strcat(update_query, converted_addr); strcat(update_query, "\' where ipaddr=\'"); strcat(update_query, row[0]); strcat(update_query, "\'"); if ((tmp = realloc(updatearray, (i+1)*sizeof(*updatearray)) ) == NULL ) { fprintf(stderr, "%s\n", "Error: Could not dynamically realloc() char **updatearray!"); exit(1); } updatearray = tmp; if ((updatearray[i] = malloc(MAX_QUERY_LENGTH)) == NULL) { fprintf(stderr, "%s\n", "Error: Could not dynamically malloc() updatearray[i]!"); exit(1); } strncpy(updatearray[i], update_query, MAX_QUERY_LENGTH); i++; } /* free results from query */ mysql_free_result(res); for (j=0; j < i; j++) { printf("%s\n", updatearray[j]); if (mysql_query(conn, updatearray[j])) { fprintf(stderr, "%s\n", mysql_error(conn)); exit(1); } } /* close connection */ mysql_close(conn); return 0; }
Should I call free() after using malloc() and realloc() or does it not matter in this case? What would be right way to do it if I should? (This program is going to be run as a cronjob on an hourly basis every day.)
I'm embarrassed, thank you again. You could not have answered my questions any better!
There are currently 1 users browsing this thread. (0 members and 1 guests)
Bookmarks