写出完美的snprintf
平时公司的代码安全扫描会给出不安全代码的告警,其中会检查代码中间的strcpy和sprintf函数,而要求使用strncpy和snprintf。今天我们讨论一下怎样写出完美的snprintf。
snprintf是一个在C99才被加入如标准的函数,原来的各个编译器都有自己的实现,至少.NET2003编译器还要是使用_snprintf这样的函数名称。
而这些编译器间都有差异,而且Glibc库又有自己的不同的实现。
查询一下snprintf的函数的MSDN说明。如下:
Let len be the length of the formatted data string (not including the terminating null). len and count are in bytes for _snprintf, wide characters for _snwprintf.
If len < count, then len characters are stored in buffer, a null-terminator is appended, and len is returned.
If len = count, then len characters are stored in buffer, no null-terminator is appended, and len is returned.
If len > count, then count characters are stored in buffer, no null-terminator is appended, and a negative value is returned.
If buffer is a null pointer and count is nonzero, or format is a null pointer, the invalid parameter handler is invoked, as described in Parameter Validation. If execution is allowed to continue, these functions return -1 and set errno to EINVAL.
For information about these and other error codes, see _doserrno, errno, _sys_errlist, and _sys_nerr.
当buffer长度不够时,返回的是负数。
而LINUX的说明如下:
Return value
Upon successful return, these functions return the number of characters printed (not
including the trailing '\0' used to end output to strings). The functions snprintf() and
vsnprintf() do not write more than size bytes (including the trailing '\0'). If the out-
put was truncated due to this limit then the return value is the number of characters (not
including the trailing '\0') which would have been written to the final string if enough
space had been available. Thus, a return value of size or more means that the output was
truncated. (See also below under NOTES.) If an output error is encountered, a negative
value is returned.
NOTES
The glibc implementation of the functions snprintf() and vsnprintf() conforms to the C99
standard, i.e., behaves as described above, since glibc version 2.1. Until glibc 2.0.6
they would return -1 when the output was truncated.
在比较新的版本中,其遵守C99的规范,当buffer长度不够时,返回的是超过Buffer长度的正数。
你会发现,如果传递的buf的长度不够的情况下,null-terminator都没有加入。。。。。那么你使用的时候还是可能溢出。而且返回值的判断在不同的平台还可能不一样。
当然我理解使用snprintf的主要好处在于安全性,但是如果使用不对仍然可能有悲剧发生,比如你的更新SQL语句被截断了WHERE条件。所以返回值还是要判断。
那么最简单的方法还是传递的给snprintf的长度参数count应该buf长度-1,然后还要将最后一个字符改为null-terminator。然后再加入相应的判断。
发现返回值小于0或者大于(可能有等于,看你传递的长度参数和Buffer的关系)实际长度时认为出现问题。
经过测试的正确写法:
max_len = sizeof(buf)-1;
len = snprintf(buf, max_len, ...);
if ((len < 0) || (len > max_len))
{
//错误处理
}
else
{
buf[max_len]=0;
do job...
}
代码说明:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h> int main(int argc, char** argv)
{
if (argc < )
{
printf("usage:./snprintf_perfect xxxx\n");
return -;
}
char buffer[];
size_t max_len = sizeof(buffer) - ;
int len = snprintf(buffer, max_len, "%s", argv[]);
if ((len < ) || (len > max_len))
{
printf("overflow!!\n");
}
else
{
buffer[max_len] = ;
printf("%s\n", buffer);
} return ;
}
结果说明:
# 长度为buffer长度-1
[root@rocket linux_programming]# ./snprintf_perfect 012345678901234
01234567890123
# 长度为buffer长度,溢出!
[root@rocket linux_programming]# ./snprintf_perfect 0123456789012345
overflow!!
写出完美的snprintf的更多相关文章
- 在java中写出完美的单例模式
1. 前言 单例(Singleton)应该是开发者们最熟悉的设计模式了,并且好像也是最容易实现的——基本上每个开发者都能够随手写出——但是,真的是这样吗? 作为一个Java开发者,也许你觉得自己对单例 ...
- 写出完美论文的十个技巧10 Tips for Writing the Perfect Paper
10 Tips for Writing the Perfect Paper Like a gourmet meal or an old master painting, the perfect col ...
- 写出优美代码的两个方式:一步到位VS迭代优化
最近把手头这个安卓APP的所有事务性方法都写完了,有了以下体会,新手体会,老鸟轻拍 想写成优美代码的人一般都会有这样的想法: 一定要在写每一句代码,写每一个方法,构造每一个类的时候,都要记得优化: ...
- 如何写出如散文般的代码――《代码整洁之道》读书笔记(Ch1-Ch3)
不知道有多少人像我一样,程序出现问题时添加函数添加变量解决,变量名用a,b,c等"简单"的字母来表示.不知道有多少人像我一样,看完自己的代码,心里暗骂"什么玩意儿!&qu ...
- 让你用sublime写出最完美的python代码--windows环境
至少很长一段时间内,我个人用的一直是pycharm,也感觉挺好用的,也没啥大毛病 但是pycharm确实有点笨重,啥功能都有,但是有很多可能这辈子我也不会用到,并且pycharm打开的速度确实不敢恭维 ...
- (转)Python新手写出漂亮的爬虫代码1——从html获取信息
https://blog.csdn.net/weixin_36604953/article/details/78156605 Python新手写出漂亮的爬虫代码1初到大数据学习圈子的同学可能对爬虫都有 ...
- 我的Java历程_写出这个数
lzJava基础进行中,今天偶然间看到的一个题目: 读入一个自然数n,计算其各位数字之和,用汉语拼音写出和的每一位数字.如下代码: import java.util.*;public class Ma ...
- 前端一面/面试常考题1-页面布局:假设高度已知,请写出三栏布局,其中左栏、右栏宽度各为300px,中间自适应。
题目:假设高度已知,请写出三栏布局,其中左栏.右栏宽度各为300px,中间自适应. [题外话:日常宣读我的目标===想要成为一名优雅的程序媛] 一.分析 1. 题目真的像我们想得这么简单吗? 其实不然 ...
- 如何写出同事看不懂的Java代码?
原创:微信公众号 码农参上,欢迎分享,转载请保留出处. 哈喽大家好啊,我是没更新就是在家忙着带娃的Hydra. 前几天,正巧赶上组里代码review,一下午下来,感觉整个人都血压拉满了.五花八门的代码 ...
随机推荐
- UVa116 (单向TSP,多决策问题)
/*----UVa1347 单向TSP 用d(i,j)表示从格子(i,j)出发到最后一列的最小开销 则在(i,j)处有三种决策,d(i,j)转移到d(i-1,j+1),d(i,j+1),d(i+1,j ...
- vue axios跨域请求,apache服务器设置
问题所在axios请求会发送两次请求 也就是说,它会先使用options去测试,你这个接口是否能够正常通讯,如果不能就不会发送真正的请求过来,如果测试通讯正常,则开始正常请求. 思路: 跨域--> ...
- ElasticSearch高级查询
ElasticSearch高级查询 https://www.imooc.com/video/15759/0 ElasticSearch查询 1,子条件查询:特定字段查询所指特定值 1.1query c ...
- 自己动手写android图片异步载入库
尊重他人劳动成果,转载请说明出处:http://blog.csdn.net/bingospunky/article/details/44344085 接触android有半年了.关于图片异步载入.一直 ...
- 01.Hello Node.js
程序下载:https://files.cnblogs.com/files/xiandedanteng/helloNodejs.rar 关键代码: var http=require('http'); v ...
- perl学习笔记——输入与输出
读取标准输入 用<STDIN>进行标准输入:chomp($line=<STDIN>); 如果读到文件尾,行输入操作符就会返回undef.便可利用这一性质跳出循环. while( ...
- angular 中表单验证的探索
需求 之前有一段时间做一个搜索查询 但是有很多限制条件,如果校验不成功需要给用户提示错误,当然项目用的是组件库的校验 我能否自己写一个? 其实 我是不会的!!! 探索 angular 的校验功能很强大 ...
- iOS开发 最近开发了蓝牙模块,在此记录总结一下(转载)
1.基本概念 <1>中心者模式:常用的(其实99.99%)就是使用中心者模式作为开发,就是我们手机作为主机,连接蓝牙外设.由于开发只用到了中心者模式,所以我也只介绍中心者模式. <2 ...
- Linux Java开发环境
一.旧版本JDK卸载 1.卸载系统自带JDK版本 #rpm -qa|grep gcj 查看到如下信息,如图所示: 进行卸载默认安装JDK: #rpm -e --nodeps java-1.4.2- ...
- 100多道经典的JAVA面试题及答案解析
面向对象编程(OOP) Java是一个支持并发.基于类和面向对象的计算机编程语言.下面列出了面向对象软件开发的优点: 代码开发模块化,更易维护和修改. 代码复用. 增强代码的可靠性和灵活性. 增加代码 ...