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 ...
随机推荐
- Python的time(时间戳与时间字符串互相转化)
strptime("string format")字符串如"20130512000000"格式的 输入处理函数 localtime(float a)时间戳的输入 ...
- 【算法导论】八皇后问题的算法实现(C、MATLAB、Python版)
八皇后问题是一道经典的回溯问题.问题描述如下:皇后可以在横.竖.斜线上不限步数地吃掉其他棋子.如何将8个皇后放在棋盘上(有8*8个方格),使它们谁也不能被吃掉? 看到这个问题,最容易想 ...
- 网站开发进阶(二十一)Angular项目信息错位显示问题解决
Angular项目信息错位显示问题解决 绪 最近在项目开发过程中遇到这样一个棘手的问题:查询出所有订单信息后,点击选择某一个订单,查询出的结果是上一次查询所得的结果.而且会出现点击两次才可以显示订单详 ...
- 报表软件公司高价悬赏BUG,100块1个我真是醉了
一直在用帆软的报表软件FineReport来做项目,也一直关注着这个公司的发展. 看到<提BUG,拿奖金>的这个活动,有些疑问和思考. 一般FineReport新版本在正式发布前,都会经过 ...
- TCP的核心系列 — ACK的处理(二)
本文主要内容:tcp_ack()中的一些细节,如发送窗口的更新.持续定时器等. 内核版本:3.2.12 Author:zhangskd @ csdn 发送窗口的更新 什么时候需要更新发送窗口呢? (1 ...
- ubuntu 的挂起与休眠
待机 计算机将目前的运行状态等数据存放在内存,关闭硬盘.外设等设备,进入等待状态.此时内存仍然需要电力维持其数据,但整机耗电很少.恢复时计算机从内存读 出数据,回到挂起前的状态,恢复速度较快.一般笔记 ...
- PS 图像调整算法——色调分离
色调分离的原理就是将R, G, B每个通道 0-255 的色调区间进行强制划分到给定的区间里去,所以色调会合并,最终的图像看起来颜色就是一块一块的. clc; clear all; close all ...
- SQLite数据库中多线程使用问题
由于项目是接手之前的烂尾项目,经常被吐槽说界面卡半天,后来发现项目里的网络请求,数据库操作都是在主线程.将一些长时间的操作换到多线程或者异步之后后,用户交互是变的顺畅多了,可是经常出现莫名其妙的闪退, ...
- 高通Android display架构分析
目录(?)[-] Kernel Space Display架构介绍 函数和数据结构介绍 函数和数据结构介绍 函数和数据结构介绍 数据流分析 初始化过程分析 User Space display接口 K ...
- Redis客户端ServiceStack.Redis的简单使用
在nuget中下载ServiceStack.Redis,但是运行之后会出现一个问题: Exception: "Com.JinYiWei.Cache.RedisHelper"的类型初 ...