zlib 压缩输出缓冲区 overflow 问题
问题
后台服务传包太大时,我们框架可以使用 zlib 库对响应进行压缩;在这次服务调试过程中,使用 zlib compress2 以 Z_BEST_COMPRESSION 模式进行压缩时,报 Z_BUF_ERROR(-5) 错误
分析
bool Codec::ZlibCompress(const std::string& src , std::string& compr_str)
{
int max_size = src.size();
if(max_size == 0)
{
return false;
}
DataBuffer<char> compr(max_size);
memset(compr, 0, max_size);
uLongf compr_len = max_size;
int res = compress2((Bytef*)compr.Get(),&compr_len,(const Bytef*)(src.c_str()),src.size(),9);
if(res != Z_OK)
{
return false;
}
compr_str = Base64Encode((const void*)compr,compr_len);
return true;
}
这里 compress2 的输出缓冲区大小设置成为待压缩原串的长度了,在压缩数据太小或随机性很大等情况下,压缩得到的数据可能会比原来的大,导致 Z_BUF_ERROR;
下面的数据是对随机字符的压缩情况,src_size 为原串大小,compr size 为压缩后长度,说明在字符很随机的情况下,压缩完再使用 Base64Encode(Base64 编码数据会增大 1/3),长度一般都会变大。


解决
int compressBound(uLong sourceLen);
zlib 提供了一个 compressBound 方法,用于估算调用一次 compress2()/compress(),用于压缩 sourceLen 长度数据所需输出缓冲区的最大大小。
但是框架压缩后,对压缩串进行 Base64 编码(Base64 编码数据会增大 1/3),最终的输出缓冲区大小应该至少设置为 compressBound(sourceLen) * 4 / 3,因此改后的代码为:
bool Codec::ZlibCompress(const std::string& src , std::string& compr_str)
{
int src_size = src.size();
// 原串则不进行压缩,且压缩输出串置空
if(0 == src_size)
{
compr_str = "";
return true;
}
/*
经过测试,在 best_compress(9) 的模式下,由随机字符构成的原串,压缩输出串有可能比原串长度大
由随机字符构成的原串,长度在 0-40k 情况下,output_buffer_size / compressBound() * 100 最大为 133.33(best_compress 和 best_speed 下此值一样)
为保证输出缓冲区足够大,缓冲区大小设置为 compressBound() * 2
*/
int max_size = compressBound(src_size) * 2;
// 如果得到的输出缓冲区大小不大于 0,则返回压缩失败
if(max_size <= 0)
{
return false;
}
DataBuffer<char> compr(max_size);
uLongf compr_len = max_size;
int res = compress2((Bytef*)compr.Get(),&compr_len,(const Bytef*)(src.c_str()),src_size,9);
if(res != Z_OK)
{
return false;
}
compr_str = Base64Encode((const void*)compr,compr_len);
return true;
}
bool Codec::ZlibDecompress(const std::string& base64_src , std::string& decmpr_str)
{
int size = base64_src.size();
if(0 == size)
{
decmpr_str = "";
return true;
}
DataBuffer<char> src(base64_src.size());
int base64_res = Base64Decode((const char*)(base64_src.c_str()),base64_src.size(),(void*)src,&size);
if(base64_res != 0)
{
return false;
}
int max_size = size*30;
DataBuffer<char> decompr(max_size);
uLongf decompr_len = max_size;
uLong src_size = size;
int res = uncompress2((Bytef*)decompr.Get(),&decompr_len,(const Bytef*)src.Get(),&src_size);
if(res != Z_OK)
{
return false;
}
decmpr_str = std::string(decompr , decompr_len);
return true;
}
参考
compressBound
http://refspecs.linuxbase.org/LSB_3.0.0/LSB-PDA/LSB-PDA/zlib-compressbound-1.html
In what situation would compressed data be larger than input?
https://stackoverflow.com/questions/16992754/in-what-situation-would-compressed-data-be-larger-than-input
zlib详细基础教程
https://www.0xaa55.com/thread-442-1-1.html
zlib 压缩输出缓冲区 overflow 问题的更多相关文章
- PHP基础之输出缓冲区基本概念、原理分析
一.概念 在PHP运行的过程中,可以将会产生输出的函数或操作结果暂时保存在PHP的缓冲区,只有当缓冲区满了.或者PHP运行完毕.或者在必要时候进行输出,才会将数据输出到浏览器,此缓冲数据的区域称为PH ...
- 深入理解php的输出缓冲区(output buffer)
这篇文章是翻译自Julien Pauli的博客文章PHP output buffer in deep,Julien是PHP源码的资深开发和维护人员.这篇文章从多个方面讲解了PHP中的输出缓冲区以及怎么 ...
- PHP中zlib扩展实现GZIP压缩输出各种方法总结
一般情况下我们出现大量数据传输理希望减少服务器的带宽压力,会采取一种方式来压缩文件传输,php中用zlib也可以实现gzip压缩输出,下面我们来看GZIP压缩输出各种方法总结. GZIP(GNU-ZI ...
- 饼干是这样压缩的——PHP使用zlib扩展实现页面GZIP压缩输出
饼干是这样压缩的——PHP使用zlib扩展实现页面GZIP压缩输出 GZIP(GNU-ZIP)是一种压缩技术.经过GZIP压缩后页面大小可以变为原来的30%甚至更小.这样用户浏览的时候就会感觉很爽很愉 ...
- PHP的输出缓冲区(转)
什么是缓冲区?简单而言,缓冲区的作用就是,把输入或者输出的内容先放进内存,而不显示或者读取.至于为什么要有缓冲区,这是一个很广泛的问题,如果有兴趣,可以在网山找下资料.其实缓冲区最本质的作用就是,协调 ...
- PHP的输出缓冲区
什么是缓冲区?简单而言,缓冲区的作用就是,把输入或者输出的内容先放进内存,而不显示或者读取.至于为什么要有缓冲区,这是一个很广泛的问题,如果有兴趣,可以在网山找下资料.其实缓冲区最本质的作用就是,协调 ...
- zlib打印bit length overflow
bit length overflow code bits -> code bits -> zlib库输出此log,此log不代表压缩出现错误,没有什么危害,而且zlib非常稳定,完全可以 ...
- Nginx_地址重写(rewrite)_日志管理(log_format)_压缩输出_Nginx设定限速_Nginx设置反向代理及反向代理缓存
Nginx地址重写 Nginx rewrite rewrite语法规则1).变量名可以使用 "=" 或 "!=" 运算符~ 区分大小写~* 不区分大小写^~ 禁 ...
- Delphi Base64编码/解码及ZLib压缩/解压
最近在写的程序与SOAP相关,所以用到了一些Base64编码/解码及数据压缩/解压方面的知识. 在这里来作一些总结: 一.Base64编码/解码 一般用到的是Delphi自带的单元EncdDe ...
随机推荐
- H5学习之旅-H5的元素属性(3)
1.标签可以拥有属性,为标签提供更多的信息 2.属性以键值对的形式呈现例如:href = "www.baidu.com" 3.常用标签属性 :align对其方式 ,对齐方式,包括上 ...
- Win8 HTML5与JS编程学习笔记(一)
微软的Visual Studio提供了多种构成win8应用的方式,其中最让我感到激动的是基于网页设计语言的开发模式,它提供了结合HTML5与Javascript来开发应用的方法,通过这种方法进行开发, ...
- LeetCode之“链表”:Sort List
题目链接 题目要求: Sort a linked list in O(n log n) time using constant space complexity. 满足O(n log n)时间复杂度的 ...
- SpriteBuilder代码中弱引用(weak)需要注意的地方
比如在GameScene类中有一个弹出菜单层实例的引用,我们有: @implementation GameScene{ //other ivars __weak GameMenuLayer *_pop ...
- C++语言之动态内存分配
在C语言中,我们熟悉的内存分配与释放的最常用的接口分别是malloc , free .在C++中: 存在着更加方便的动态存储分配: 1.new 和delete 机制,new 它能更可靠控制存储区的分配 ...
- 近期ubuntu 14.04 cpu占用高排障
近期linux使用总是cpu达到满值, 双核cpu其中一个核总是100%,另一个核正常.top之发现输入法框架fcitx满载,直接kill之,发现搜狗输入法不能用了,随即输入如下命令: fcitx f ...
- rails将类常量重构到数据库对应的表中之三
经过博文之一和之二的重构,貌似代码表现的还不错,正常运行和test都通过鸟,但是,感觉告诉我们还是有什么地方不对劲啊!究竟是哪里不对劲呢?我们再来好好看一下. 我们把数据库表中的支付方式集合直接放在实 ...
- C# 将PDF转为SVG的3种情况
PDF格式的文档广泛用于各种办公场所,在工作中难免会有将PDF文档转换为其他文档格式的需要.在本篇文档中,将介绍PDF转为SVG的方法.根据不同的转换需求,这里分三种情况进行讲述,即转PDF所有页为S ...
- 细说Web页面与本地电脑通讯
话说在很久很久以前.Web页面与客户的本地电脑Localhost通讯,有两种方式: 1.Flash 2.ActiveX控件 由于Flash本人不是很了解,也给出不了什么示例代码, 对于ActiveX控 ...
- miniUI input设置默认值,js获取年月注意事项,数据库nvl函数使用
2017-6-5周一,今天碰到的一个需求是:两税附征模块进入页面筛选时间默认值为当前月的上一个月,并根据筛选结果显示数据,我们用的框架为miniUI. 坑1: 默认值设置,刚刚接触miniUI,对里面 ...