主题 : tiny6410 自己实现的缓冲区致Segmentation fault,未调用任何代码哦,只是包含代码编译 复制链接 | 浏览器收藏 | 打印
级别: 新手上路
UID: 58759
精华: 0
发帖: 20
金钱: 100 两
威望: 20 点
综合积分: 40 分
注册时间: 2011-11-13
最后登录: 2012-03-18
楼主  发表于: 2011-12-18 15:31

 tiny6410 自己实现的缓冲区致Segmentation fault,未调用任何代码哦,只是包含代码编译

系统环境:ubuntu 11.04   tiny6410: 2.6.38
软件环境:
arm-linux-gcc 4.5.1
问题描述:
为读入音频数据,自己实现了一个缓冲区代码,但包括此代码,当执行read函数时,就会报内存溢出:Segmentation fault,我测试只包含缓冲区代码,不调用任何函数也如此,只有不包括此代码才不会。
并且我写了一个简单的单独程序实现从audio读入数据存入文件中,如果我编译的时候,把缓存区代码的.o文件包括过来,同样到read的时候就会出现Segmentation fault
用GDB进行测试, bt显示以下信息:

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 1253]
0xfebd2222 in ?? ()
(gdb) bt
#0  0xfebd2222 in ?? ()
#1  0x0008900c in ?? ()
#2  0x0008900c in ?? ()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
小弟才疏学浅,还望各位高手相助。
以下为缓冲区实现的代码 audio_pool.c
同时我将audio_pool.o做附件上传(非rar文件,请直接mv audio_pool.o.rar  audio_pool.o),大家可以尝试在自己的项目中链接时包括此文件,执行read会不会导致内存出错。
复制代码
  1. #include "audio_pool.h"
  2. pthread_mutex_t read_mx;            /*缓冲池互斥体*/
  3. int read;                           /*当前已读缓充区数*/
  4. int write;                          /*当前已写入数据缓冲区数*/
  5. audio_package * audio_package_ptr[MAX_POOL_SIZE]={NULL};  /*缓存区指针*/
  6. /*
  7.   缓冲区初始化函数
  8.   参数:缓冲区数据指针
  9.   返回值:1:success || 0:failed
  10. */
  11. int init_pool(void)
  12. {
  13.     /*分配MAX_AUDIO_BUF个AUDIO_PACKAGE_SIZE, 当前配置能存储5秒钟数据*/
  14.     int i;
  15.     for(i=0; i<MAX_POOL_SIZE; i++){
  16.             audio_package_ptr[i] = calloc(1,AUDIO_PACKAGE_SIZE);
  17.             if(audio_package_ptr[i]==NULL)
  18.             {
  19.                 return 0;
  20.             }
  21.             audio_package_ptr[i]->readed=1;
  22.             audio_package_ptr[i]->writed=1;
  23.     }
  24.     pthread_mutex_init(&read_mx,NULL);
  25.     read=0;
  26.     write=0;
  27.     return 1;
  28. }
  29. /*
  30. 获取缓冲区中一个未处理的数据进行编码
  31. 从缓冲区中找下一个应该读的数据,如果当前的block的write为1,表示已写入新数据,即返回此block,否则返回NULL,表示此空间还未写入数据
  32. 参数:无
  33. 返回值:数据block:success || NULL:failed
  34. */
  35. audio_package * read_pool(void)
  36. {
  37.     audio_package* ret;
  38.     pthread_mutex_lock(&read_mx);    //进入临界区
  39.     ret  =  audio_package_ptr[read];
  40.     if(ret->writed!=1)                  //当前缓存block还未读入数据
  41.     {
  42.         pthread_mutex_unlock(&read_mx); //获取失败,解锁
  43.         return NULL;
  44.     }
  45.     read = (read+1 >= MAX_POOL_SIZE) ? 0 : read+1;//判断read是否轮一圈了
  46.     return ret;
  47. }
  48. /*
  49. 当读出数据之后,释放互斥锁 并设置相应标识位
  50. 参数:完成读出数据的缓冲区
  51. 返回值:无
  52. */
  53. void readed_pool(audio_package * read_package)
  54. {
  55.    read_package->readed=1;                      //当前区己经读过
  56.    read_package->writed=0;                      //当前区未写入新数据
  57.    pthread_mutex_unlock(&read_mx);              //退出临界区
  58. }
  59. /*
  60. 获取缓冲区中一个空白或未读区域用于写入新数据
  61. 参数:无
  62. 返回值:数据block:success || NULL:failed
  63. */
  64. audio_package * write_pool(void)
  65. {
  66.     audio_package* ret;
  67.     pthread_mutex_lock(&read_mx);    //进入临界区
  68.     ret  = audio_package_ptr[write];
  69.     if(ret->readed!=1)                  //当前缓存区数据还未读出进行处理
  70.     {
  71.         pthread_mutex_unlock(&read_mx); //获取失败,解锁
  72.         return NULL;
  73.     }
  74.     write = (write+1 >= MAX_POOL_SIZE) ? 0 : write+1;
  75.     return ret;
  76. }
  77. /*
  78. 当写入数据之后,释放互斥锁 并设置相应标识位
  79. 参数:完成写入数据的缓冲区
  80. 返回值:无
  81. */
  82. void writed_pool(audio_package * read_package)
  83. {
  84.    read_package->readed=0;                      //当前区还未读出进行处理
  85.    read_package->writed=1;                      //当前区已写入新数据
  86.    pthread_mutex_unlock(&read_mx);              //退出临界区
  87. }
  88. /*
  89. 关闭缓冲区
  90. 参数:无
  91. 返回值: 无
  92. */
  93. void release_pool(void)
  94. {
  95.     int i;
  96.     for(i=0; i<MAX_POOL_SIZE; i++)
  97.     {
  98.         if(audio_package_ptr[i]!=NULL)
  99.         {
  100.             free(audio_package_ptr[i]);
  101.         }
  102.     }
  103.     pthread_mutex_destroy(&read_mx);
  104. }


以下代码为单独的一个程序,从/dev/dsp读入音频数据

#arm-linux-gcc -o read main.c -lpthread    //这样的命令编译出来的程序工作正常

#arm-linux-gcc -o read  audio_pool.o sound.c -lpthread     //这样的命令编译出来的程序就会报内存出错


复制代码
  1. /*
  2. *  * sound.c
  3. *   */
  4. #include <unistd.h>
  5. #include <fcntl.h>
  6. #include <sys/types.h>
  7. #include <sys/ioctl.h>
  8. #include <stdlib.h>
  9. #include <stdio.h>
  10. #include <linux/soundcard.h>
  11. #include <pthread.h>
  12. #define LENGTH 10    /* 存储秒数 */
  13. #define RATE 8000   /* 采样频率 */
  14. #define SIZE 16      /* 量化位数 */
  15. #define CHANNELS 1  /* 声道数目 */
  16. /* 用于保存数字音频数据的内存缓冲区 */
  17. extern void * read_audio(void* fd);
  18. const char * file = "./source.raw";
  19. unsigned char buf[LENGTH*RATE*SIZE*CHANNELS/8];
  20. void * read_audio(void * fd)
  21. {
  22.     int * xx=fd;
  23.     int tt=read(*xx, buf, LENGTH*RATE*SIZE*CHANNELS/8); /* 录音 */
  24.     return(void *) tt;
  25. }
  26. int main()
  27. {
  28.     pthread_t pid;
  29.     int fd;    /* 声音设备的文件描述符 */
  30.     int arg;    /* 用于ioctl调用的参数 */
  31.     int status;   /* 系统调用的返回值 */
  32.     FILE * fp;
  33.     /* 打开声音设备 读写方式*/
  34.     fd = open("/dev/dsp", O_RDWR);
  35.     if (fd < 0)
  36.     {
  37.         perror("open of /dev/dsp failed");
  38.         exit(1);
  39.     }
  40.     if((fp=fopen(file,"w"))==NULL)
  41.     {
  42.         perror("open dest error");
  43.         exit(1);
  44.     }
  45.     /* 设置采样时的量化位数 */
  46.     arg = SIZE;
  47.     status = ioctl(fd, SOUND_PCM_WRITE_BITS, &arg);
  48.     if (status == -1)
  49.         perror("SOUND_PCM_WRITE_BITS ioctl failed");
  50.     if (arg != SIZE)
  51.         perror("unable to set sample size");
  52.     int channels = 0; // 0=mono 1=stereo
  53.     int result = ioctl(fd, SNDCTL_DSP_STEREO, &channels);
  54.     if ( result == -1 ) {
  55.         perror("ioctl channel number");
  56.         return -1;
  57.     }
  58.     if (channels != 0) {
  59.         perror("just double");
  60.         // 只支持立体声
  61.     }
  62.     /* 设置采样时的采样频率 */
  63.     arg = RATE;
  64.     status = ioctl(fd, SOUND_PCM_WRITE_RATE, &arg);
  65.     if (status == -1)
  66.         perror("SOUND_PCM_WRITE_WRITE ioctl failed");
  67.     printf("Say something:\n");
  68.     void * test;
  69.     pthread_create(&pid,NULL,read_audio,(void *)&fd); /* 录音 */
  70.     pthread_join(pid,&test);
  71.     if ((int)test != sizeof(buf))
  72.         perror("read wrong number of bytes");
  73.     fwrite(buf,sizeof(buf),1,fp);
  74.     printf("done");
  75.     fclose(fp);
  76.     return 0;
  77. #if 0
  78.         printf("You said:\n");
  79.         status = write(fd, buf, sizeof(buf)); /* 回放 */
  80.         if (status != sizeof(buf))
  81.             perror("wrote wrong number of bytes");
  82.         /* 在继续录音前等待回放结束 */
  83.         status = ioctl(fd, SOUND_PCM_SYNC, 1);
  84.         if (status == -1)
  85.             perror("SOUND_PCM_SYNC ioctl failed");
  86. #endif
  87. }

附件: audio_pool.o.rar (7 K) 下载次数:2
级别: 新手上路
UID: 58759
精华: 0
发帖: 20
金钱: 100 两
威望: 20 点
综合积分: 40 分
注册时间: 2011-11-13
最后登录: 2012-03-18
1楼  发表于: 2011-12-18 15:35
级别: 新手上路
UID: 58759
精华: 0
发帖: 20
金钱: 100 两
威望: 20 点
综合积分: 40 分
注册时间: 2011-11-13
最后登录: 2012-03-18
2楼  发表于: 2011-12-18 17:54
原因找到了,大家不用看了,这个错误虽然很低级,但排错的过程却很漫长。
级别: 新手上路
UID: 58759
精华: 0
发帖: 20
金钱: 100 两
威望: 20 点
综合积分: 40 分
注册时间: 2011-11-13
最后登录: 2012-03-18
3楼  发表于: 2011-12-18 17:56
并且错得也很蹊跷 , 呵呵
*無鈳取玳
级别: 论坛版主
UID: 27
精华: 12
发帖: 5398
金钱: 40120 两
威望: 17929 点
综合积分: 11036 分
注册时间: 2008-01-16
最后登录: 2014-11-22
4楼  发表于: 2011-12-18 18:25

 回 3楼(安静的发狂者) 的帖子

排错的过程比错误本身更有价值,希望你能分享一下你的所得,谢谢
"If you have an apple and I have an apple and we exchange apples, then you and I will
still each have one apple. But if you have an idea and I have an idea and we exchange
these ideas, then each of us will have two ideas."
级别: 新手上路
UID: 58759
精华: 0
发帖: 20
金钱: 100 两
威望: 20 点
综合积分: 40 分
注册时间: 2011-11-13
最后登录: 2012-03-18
5楼  发表于: 2011-12-19 23:00
以上问题是全局变量名与系统函数名一致了
但却编译通过,连警告都没有,这也是我一时半会没能找到错误的原因
能编过的原因是:
我在一源码文件中定义全局亦是
int read; 然后在代码中调用了read函数
我没有包括include <unistd.h>头文件
arm-linux-gcc 编译成目标代码能过,这时候没链接
然后和项目中其他源文件一起链接,编译过了,没任何报错。