Chinaunix首页 | 论坛 | 博客
  • 博客访问: 573642
  • 博文数量: 493
  • 博客积分: 2891
  • 博客等级: 少校
  • 技术积分: 4960
  • 用 户 组: 普通用户
  • 注册时间: 2010-03-17 17:11
文章分类

全部博文(493)

文章存档

2010年(493)

分类:

2010-05-12 19:54:46

1 现象:问题描述
一个CBufferStream类封装了流的读写处理,负责往一个buffer中写入和读取多个变长数据.
写入时会预先判断buffer的剩余空间,当不够时,会realloc双倍的空间.每次realloc之后就会出现越界写的情况,并导致coredump.
2 关键过程:根本原因分析
  TInt4 CBufferedStream::write(const TChar* buff, TUInt4 len)
{
    //begin add by xiechuan
    TUInt4 written = 0;
    TChar* pTemp = NULL;
    if (m_currLen+ len> m_currBufferSize)//如果即将写满
    {
        //重新分配buffer大小
        m_currBufferSize = (m_currLen+ len> m_currBufferSize*2) ?(m_currLen+ len):(m_currBufferSize*2);
        pTemp = (TChar*)realloc(*m_pBufferStart,m_currBufferSize);
        if(!pTemp)//如果为空则返回-1
        {
            return -1; 
        }
        *m_pBufferStart = pTemp;//将改变后的首地址保存
     
        m_pBuffer = pTemp + m_offSet;//重新计算当前的buffer
    }
    memcpy(m_pBuffer+m_currWritePos,buff,len);
    m_currWritePos+=len;
    m_currLen += len;
    return 0;
}
   Buffer的布局:
                            M 
m_pBufferStart     m_pBuffer   
由于buffer前面一部分是有消息头数据的,所以变长数据的写入只能从m_pBufferStart+offset开始.当buffer不够时将m_currBufferSize的长度翻倍后,然后realloc.
m_currBufferSize = (m_currLen+ len> m_currBufferSize*2) ?(m_currLen+ len):(m_currBufferSize*2);
pTemp = (TChar*)realloc(*m_pBufferStart,m_currBufferSize);
由于重新分配内存是从m_pBufferStart开始的,而没有加上消息头的长度(offset).所以导致realloc之后,真正增加的buffer长度并不是先前预计的2倍.导致后续继续写时.越界.
3 结论:解决方案及效果
pTemp = (TChar*)realloc(*m_pBufferStart,m_currBufferSize+m_offset);
重新分配内存时应该加上前面消息头的长度.修改之后无越界和coredump.
4 经验总结:预防措施和规范建议
1.内存操作要注意长度越界的问题.最好画出内存布局,把边界考虑清楚再编码.
5 备注
6 考核点
对c内存分配函数的了解和内存操作的越界错误的反应
7 试题
1.有一段连续内存buff,前面存放的是固定消息头,长度为head_length,后面存放的是可变数据长度为data_length.往内存可变数据区写入数据,长度不够时(算法是:即将写入的长度 + 已经写入的长度 > data_length)下列处理最合理的是:
A. data_length*=2;
buff  =  (char*)malloc(data_length);
B. data_length*=2;
Char* tmp  =  (char*)realloc(buff,data_length+head_length);
  buff  =  tmp; 
C. data_length*=2;
buff  =  (char*)malloc(data_length+head_length);
D. data_length*=2;
Char* tmp  =  (char*)realloc(buff ,data_length);
buff  =  tmp; 
答案:B
A,C错误原因是,重新分配内存,造成原来的数据丢失和内存泄漏
D.错误原因是,realloc时没有加上消息头长度,重新分配的内存一部分用来存放消息头,导致可变数据区的真实大小 < data_length.而上面指定的判断长度的算法就可能产生越界.
阅读(815) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~