字符串复制导致分段错误

时间:2019-05-07 11:06:41

标签: c arrays string segmentation-fault

在下面的代码中,代码在第四次执行while循环后崩溃,并在strcpy中崩溃

strcpy(userver_info[location].Tag_Name, field); 

调试时出现以下错误

Can't find a source file at "strcpy-sse2-unaligned.S"

我无法找出导致崩溃的原因是什么,面对上述问题后,我做了结构填充的思考,这可能是问题所在,甚至无法解决,有人可以告诉我为什么是代码崩溃。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


#define BUFFER_SIZE               1024
#define NUM_OF_UNDERLYING_SERVER  0


#define SHM_ADDR_LEN              15
#define SERVER_NAME_LEN           25
#define TAG_NAME_LEN              25
#define TAG_DESC_LEN              30
#define ACCESS_LEVEL_LEN          5
#define DATA_TYPE_NAME_LEN            10

typedef struct {
  char    SHM_Location[SHM_ADDR_LEN];
  char    Server_ID[SERVER_NAME_LEN];
  char    Tag_Name[TAG_NAME_LEN];
  int     Tag_ID;
  char    Tag_Description[TAG_DESC_LEN];
  char    Access_Level[ACCESS_LEVEL_LEN];
  char    Data_Type[DATA_TYPE_NAME_LEN];
}u_server_info;

typedef struct {
  int num_of_tags;
  u_server_info *underlying_server_data;
}opcua_u_server;



void parse_underlying_opcua_server(char * buffer, u_server_info *userver_info) {

  static int location = 0;
  char *field;
  /* get SHM_Location */
  field = strtok(buffer,",");
  strcpy(userver_info[location].SHM_Location, field);

  /* get Server_ID */
  field=strtok(NULL,",");
  strcpy(userver_info[location].Server_ID, field);

  /* get Tag_Name */
  field = strtok(NULL,",");
  strcpy(userver_info[location].Tag_Name, field);

  /* get Tag_ID */
  field=strtok(NULL,",");
  userver_info[location].Tag_ID = atoi(field);

  /* get Tag_Description */
  field = strtok(NULL,",");
  strcpy(userver_info[location].Tag_Description, field);

  /* get Access_Level */
  field = strtok(NULL,",");
  strcpy(userver_info[location].Access_Level, field);

  /* get Data_Type */
  field = strtok(NULL,",");
  strcpy(userver_info[location].Data_Type, field);

  /* display the result */
  printf("%s\t %s\t %s\t %d\t %s\t %s\t %s\n",
          userver_info[location].SHM_Location,
          userver_info[location].Server_ID,
          userver_info[location].Tag_Name,
          userver_info[location].Tag_ID,
          userver_info[location].Tag_Description,
          userver_info[location].Access_Level,
          userver_info[location].Data_Type);

  location++;
}


int get_line_count(char *filename) {

  FILE *fp;
  int line_count = 0;
  char c;
  fp = fopen(filename, "r");
  if (fp == NULL){
      printf("Unable to open file '%s' to count lines\n",filename);
      return -1;
  }
  for (c = getc(fp); c != EOF; c = getc(fp))
      if (c == '\n') // Increment count if this character is newline
          line_count = line_count + 1;
  fclose(fp);
  return line_count;
}

int main(int argc, char **argv)
{
  char filename[] = "underlying_server.csv";
  char buffer[BUFFER_SIZE];
  FILE *fp;
  int tags_count = 0;
  opcua_u_server *ua_server = NULL;

  /* open the CSV file */
  fp = fopen(filename,"r");
  if( fp == NULL) {
      printf("Unable to open file '%s'\n",filename);
      exit(EXIT_FAILURE);
  }

  tags_count = get_line_count(filename);
  /* Allocate memmory for each Underlying server */
  ua_server= malloc(sizeof(opcua_u_server));
  if (ua_server == NULL) {
      printf("Malloc failed");
      exit(EXIT_FAILURE);
  }
  /* Allocate memory for each underlying server tag information */
  ua_server[NUM_OF_UNDERLYING_SERVER].underlying_server_data =
          malloc(tags_count * sizeof(ua_server->underlying_server_data));

  if (ua_server[NUM_OF_UNDERLYING_SERVER].underlying_server_data == NULL) {
      printf("Malloc failed");
      exit(EXIT_FAILURE);
  }
  /* process the data */
  while(fgets(buffer,BUFFER_SIZE,fp)) {

      parse_underlying_opcua_server(buffer,
                      ua_server[NUM_OF_UNDERLYING_SERVER].underlying_server_data);

  }
  ua_server->num_of_tags = tags_count;
  /*Reset the value for next server*/
  tags_count = 0;
  /* close file */
  fclose(fp);

  return(0);
}

我的底层服务器.csv就是这样

1000,Server_1,Tag_1,3000,Created_tag_3000,AR,BOOL
1001,Server_1,Tag_2,3001,Created_tag_3001,AR,BOOL
1002,Server_1,Tag_3,3002,Created_tag_3002,AR,BOOL
1003,Server_1,Tag_4,3003,Created_tag_3003,AR,BOOL
1004,Server_1,Tag_5,3004,Created_tag_3004,AR,REAL
1005,Server_1,Tag_6,3005,Created_tag_3005,AR,REAL
1006,Server_1,Tag_7,3006,Created_tag_3006,AW,REAL
1007,Server_1,Tag_8,3007,Created_tag_3007,AW,REAL
1008,Server_1,Tag_9,3008,Created_tag_3008,AW,REAL
1009,Server_1,Tag_10,3009,Created_tag_3009,AW,REAL
1010,Server_1,Tag_11,3010,Created_tag_3010,AW,REAL
1011,Server_1,Tag_12,3011,Created_tag_3011,AW,DWORD
1012,Server_1,Tag_13,3012,Created_tag_3012,AW,DWORD
1013,Server_1,Tag_14,3013,Created_tag_3013,AR,DWORD
1014,Server_1,Tag_15,3014,Created_tag_3014,AR,DWORD
1015,Server_1,Tag_16,3015,Created_tag_3015,AR,DWORD
1016,Server_1,Tag_17,3016,Created_tag_3016,AR,DWORD
1017,Server_1,Tag_18,3017,Created_tag_3017,AR,DWORD
1018,Server_1,Tag_19,3018,Created_tag_3018,AR,DWORD
1019,Server_1,Tag_20,3019,Created_tag_3019,AR,DWORD
1020,Server_1,Tag_21,3020,Created_tag_3020,AR,DWORD
1021,Server_1,Tag_22,3021,Created_tag_3021,AW,BOOL
1022,Server_1,Tag_23,3022,Created_tag_3022,AW,BOOL
1023,Server_1,Tag_24,3023,Created_tag_3023,AW,BOOL
1024,Server_1,Tag_25,3024,Created_tag_3024,AW,BOOL
1025,Server_1,Tag_26,3025,Created_tag_3025,AW,BOOL
1026,Server_1,Tag_27,3026,Created_tag_3026,AW,DWORD
1027,Server_1,Tag_28,3027,Created_tag_3027,AR,DWORD
1028,Server_1,Tag_29,3028,Created_tag_3028,AR,DWORD
1029,Server_1,Tag_30,3029,Created_tag_3029,AR,DWORD
1030,Server_1,Tag_31,3030,Created_tag_3030,AR,REAL

2 个答案:

答案 0 :(得分:5)

我确定对此有一个dup,您是根据指针的大小分配第二个缓冲区,而不是所指向的对象:

/* Allocate memory for each underlying server tag information */
ua_server[NUM_OF_UNDERLYING_SERVER].underlying_server_data =
      malloc(tags_count * sizeof(ua_server->underlying_server_data));

成为:

/* Allocate memory for each underlying server tag information */
ua_server[NUM_OF_UNDERLYING_SERVER].underlying_server_data =
      malloc(tags_count * sizeof(*(ua_server->underlying_server_data)));

请注意,此时的实际代码*(ua_server->underlying_server_data不好,但是sizeof是编译时的,只是将代码用作模板来获取对象大小。

我有时希望编译器警告“您要求的指针大小”

答案 1 :(得分:-5)

从不使用strcpy,它是不安全的,因为它不执行任何形式的边界约束,并且只会继续复制,直到它在源缓冲区中达到0字节为止。如果源缓冲区不是(正确)以0结尾的,或者源缓冲区的内容太长而无法装入目标,则它将创建不确定的行为(崩溃或容易受到攻击)。

抛开固定大小字段的问题,绝对有必要检查缓冲区操作的大小限制。您将使用的标准功能(尽管仍然不完美)是strncpy(请注意额外的n)。需要注意的是,strncpy如果不适合目的地,将省略终止的0字节。

由于您的字段是固定大小的,因此您可以像这样使用它

strncpy(userver_info[location].SHM_Location, field, SHM_ADDR_LEN-1);
userver_info[location].SHM_Location[SHM_ADDR_LEN-1] = 0;

即它最多可复制SHM_ADDR_LEN-1个字节,并且始终在缓冲区的最后放置一个终止0。