Pointer magic sometimes results in SIGSEGV
I am trying to find an error in a parsing-routine in C. The code is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
static const char * month_abb_names[] =
{
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
};
static const char * wday_abb_names[] =
{
"Mon",
"Tue",
"Wed",
"Thu",
"Fri",
"Sat",
"Sun",
};
time_t mb_mktime(char * time_str)
{
struct tm msg_time;
char * cur, * next, *tmp_cur, *tmp_next, oldval;
int counter = 0, tmp_counter = 0, i;
int cur_timezone = 0, sign = 1;
time_t retval;
msg_time.tm_isdst = 0;
cur = time_str;
next = strchr(cur, ' ');
while(next)
{
oldval = (*next);
(*next) = '\0';
switch(counter)
{
case 0 :
// day of week
for(i = 0; i < 7; i++)
{
if(strncasecmp(cur, wday_abb_names[i], 3) == 0)
{
msg_time.tm_wday = i +1;
break;
}
}
break;
case 1 :
//month name
for(i = 0; i < 12; i++)
{
if(strncasecmp(cur, month_abb_names[i], 3) == 0)
{
msg_time.tm_mon = i;
break;
}
}
break;
case 2 :
// day of month
msg_time.tm_mday = strtoul(cur, NULL, 10);
break;
case 3 :
// HH:MM:SS
tmp_cur = cur;
tmp_next = strchr(cur, ':');
tmp_counter = 0;
while(tmp_next)
{
switch(tmp_counter)
{
case 0 :
msg_time.tm_hour = strtoul(tmp_cur, NULL, 10);
break;
case 1 :
msg_time.tm_min = strtoul(tmp_cur, NULL, 10);
break;
}
tmp_cur = tmp_next + 1;
tmp_next =strchr(tmp_cur, ':');
tmp_counter++;
}
msg_time.tm_sec = strtoul(tmp_cur, NULL, 10);
break;
case 4 :
// timezone
if( (*cur) == '+')
{
cur++;
}
else if ( (*cur) == '-')
{
sign = -1;
cur++;
}
cur_timezone = (int)strtol(cur, NULL, 10);
cur_timezone = sign * (cur_timezone / 100) * 60 * 60 + (cur_timezone % 100) * 60;
break;
}
(*next) = oldval;
cur = next + 1;
next = strchr(cur, ' ');
counter++;
}
// what's left is year
msg_time.tm_year = strtoul(cur, NULL, 10) - 1900;
#ifndef __WIN32
retval = timegm(&msg_time) - cur_timezone;
#else
retval = mktime(&msg_time) - cur_timezone; // + some adjustments....
#endif
printf("final msg_time = %ld\n", retval);
return retval;
}
void getTime(char * time_str)
{
time_t time = mb_mktime(time_str);
struct tm *ts;
char buf[80];
/* Format and print the time, "ddd yyyy-mm-dd hh:mm:ss zzz" */
ts = localtime(&time);
strftime(buf, sizeof(buf), "%a %Y-%m-%d %H:%M:%S %Z", ts);
printf("%s --> %s\n", time_str, buf);
}
int main()
{
getTime("Thu Jun 16 04:53:00 +0000 2011");
printf("done.");
return 0;
}
The main
and getTime
are new, the mb_mktime
is only slightly modified from the original
However, the line ((*next) = '\0';
) results in a SIGSEGV. 开发者_如何学JAVAI admit I am fairly uncertain why the code looks like this...
The code however works fine in the normal app.
Can someone explain why this code works in one app and SIGSEGVs in another?
You should not be modifying a constant string literal, which is "startstring"
in this example. I suppose the normal app works because char buffers which are used there are mutable.
精彩评论