【问题标题】:Valgrind: Invalid write of size 1 on a strcpyValgrind:在 strcpy 上写入大小为 1 的无效
【发布时间】:2017-02-02 21:06:00
【问题描述】:

代码正在尝试将大型 uint8_t 数组序列化为二进制字符流。我应该在缓冲区中有足够的空间来复制这些数据;为什么我会收到这些错误?发布的是带有输出错误的完整可运行代码。使用的 valgrind 命令是:

valgrind --leak-check=yes --track-origins=yes ./prog

主要:

#include "string.h"
#include "stdio.h"
#include "stdlib.h"
#include "stdint.h"
#include <unistd.h>

#define MAX_FRAME_SIZE 9236
#define DAT_LEN 8202

void create_bit_stream(uint8_t frame[], size_t frame_size, char *frame_bits)
{
  /*
   * Takes in uint8_t array of data and converts to binary stream of characters
   * frame        : input array of uint8_t type data
   * frame_size   : size_t length of frame --> sizeof(frame)/sizeof(frame[0])
   * frame_bits   : pointer for returning the character string
   *
   * RETURNS string of binary values generated from input array
  */

  uint8_t tmp[frame_size];
  memset(tmp,0,frame_size);
  memcpy(tmp,frame,frame_size);
  // char bit_string[frame_size*8+1];
  char *bit_string = malloc(frame_size*8+1);
  memset(bit_string,'\0',frame_size*8 + 1);
  for (int i = 0; i < frame_size; i++)
  {
    for (int j = 0; j < 8; j++)
    {
      bit_string[i*8+j] = '0' + (tmp[i] >> 7);
      tmp[i] <<= 1;
    }
  }
  bit_string[frame_size*8] = '\0';
  strcpy(frame_bits, bit_string);
  free(bit_string);
  return;

}

int main(int argc, char *argv[])
{

 char *frame_bits = malloc(MAX_FRAME_SIZE + 1);
 if(!frame_bits)
 {exit(EXIT_FAILURE);}
 memset(frame_bits,'\0',MAX_FRAME_SIZE + 1);

 uint8_t *DAT_frame = malloc(DAT_LEN);
 if(!DAT_frame)
 {exit(EXIT_FAILURE);}
 memset(DAT_frame,0,DAT_LEN);

 //fill with arbitrary data
 for(int i = 0; i < DAT_LEN; i++)
 {
   DAT_frame[i] = i % 255;
 }

 create_bit_stream(DAT_frame, DAT_LEN, frame_bits);

 free(frame_bits); free(DAT_frame);
 return 0;
}

错误:

==2994== Invalid write of size 1
==2994==    at 0x4C31060: strcpy (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2994==    by 0x40088B: create_bit_stream (stack.c:36)
==2994==    by 0x400993: main (stack.c:61)
==2994==  Address 0x5205455 is 0 bytes after a block of size 9,237 alloc'd
==2994==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2994==    by 0x4008CE: main (stack.c:45)
==2994== 
==2994== Source and destination overlap in strcpy(0x5203040, 0x52074f0)
==2994==    at 0x4C310E6: strcpy (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2994==    by 0x40088B: create_bit_stream (stack.c:36)
==2994==    by 0x400993: main (stack.c:61)

【问题讨论】:

  • 这不是你的问题,但仅供参考,sizeof(char)按定义为 1,因此 foo * sizeof(char) 是多余的,并且代码味道不好。
  • 你将不得不减少这个问题中的太多噪音
  • @RyanHaining 不确定您要我删除什么。有两个指针初始化和一个非常小的函数。这里实际上没有任何多余的东西。
  • 进一步解释:您可能不认为sizeof(uint8_t)sizeof(char) 相同,但它必须是,因为char 不能小于 比@987654330 @(需要CHAR_BIT &gt;= 8),如果更大(即CHAR_BIT &gt; 8),则要求实现不提供uint8_t
  • 我可以重现问题(在放回#includes 和顶级文件结构后——请不要让人们以后这样做,提供minimal but complete example)并且正在调查。

标签: c valgrind


【解决方案1】:

您的create_bit_stream 获取字节流并将其扩展为ASCII 编码 位流。也就是说,如果你输入字节 0x42 ('B'),它将产生 string "01000010",它有 9 个字节长(计算终止的 nul)。您在为frame_bits 分配空间时忘记考虑这一点——不是在create_bit_stream 中,而是在main 中:

char *frame_bits = (char *)malloc((MAX_FRAME_SIZE + 1)*sizeof(char));

应该阅读

char *frame_bits = malloc(MAX_FRAME_SIZE * 8 + 1);

(Don't cast the result of malloc.)

(正如我在问题的 cmets 中指出的那样,sizeof(char) == 1sizeof(uint8_t) == 1根据定义;明确地写其中任何一个都是多余的,而且代码味道不好。)

(像这样的 API,其中调用者提供了一个可变长度的缓冲区,被调用者写入其中,应该始终传递输出缓冲区的大小。您的设计很危险,原因与 getssprintf 相同很危险。)

【讨论】:

  • 使用这个更正 valgrind 仍然在strcpy 函数中抱怨Invalid write of size 1。编辑:我正在使用valgrind --leak-check=yes --track-origins=yes ./program
  • @gutelfuldead 进行上述更改后,我没有收到来自valgrind 的进一步投诉。剩下的问题可能是我必须重建的代码部分。请编辑您的问题并将完整源代码提供给您的测试程序。
  • 你是对的。我不确定问题出在哪里;我将它重构为一个单一的来源,它工作。谢谢。
猜你喜欢
  • 2014-11-30
  • 1970-01-01
  • 2020-08-19
  • 1970-01-01
  • 1970-01-01
  • 2016-02-24
  • 2016-07-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多