Магия указателя иногда приводит к SIGSEGV - PullRequest
0 голосов
/ 24 июня 2011

Я пытаюсь найти ошибку в процедуре синтаксического анализа в C. Код:

  #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;
  }

main и getTime являются новыми, mb_mktime только слегка измененот оригинала

Однако, строка ((*next) = '\0';) приводит к SIGSEGV.Я признаю, что совершенно не уверен, почему код выглядит следующим образом ...

Однако код нормально работает в обычном приложении.

Может кто-нибудь объяснить, почему этот код работает в одном приложении и SIGSEGV вдругой?

1 Ответ

4 голосов
/ 24 июня 2011

Вы не должны изменять константу строкового литерала, которая в этом примере равна "startstring". Я предполагаю, что нормальное приложение работает, потому что буферы символов, которые используются там, являются изменяемыми.

...