平时公司的代码安全扫描会给出不安全代码的告警,其中会检查代码中间的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的更多相关文章

  1. 在java中写出完美的单例模式

    1. 前言 单例(Singleton)应该是开发者们最熟悉的设计模式了,并且好像也是最容易实现的——基本上每个开发者都能够随手写出——但是,真的是这样吗? 作为一个Java开发者,也许你觉得自己对单例 ...

  2. 写出完美论文的十个技巧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 ...

  3. 写出优美代码的两个方式:一步到位VS迭代优化

    最近把手头这个安卓APP的所有事务性方法都写完了,有了以下体会,新手体会,老鸟轻拍   想写成优美代码的人一般都会有这样的想法: 一定要在写每一句代码,写每一个方法,构造每一个类的时候,都要记得优化: ...

  4. 如何写出如散文般的代码――《代码整洁之道》读书笔记(Ch1-Ch3)

    不知道有多少人像我一样,程序出现问题时添加函数添加变量解决,变量名用a,b,c等"简单"的字母来表示.不知道有多少人像我一样,看完自己的代码,心里暗骂"什么玩意儿!&qu ...

  5. 让你用sublime写出最完美的python代码--windows环境

    至少很长一段时间内,我个人用的一直是pycharm,也感觉挺好用的,也没啥大毛病 但是pycharm确实有点笨重,啥功能都有,但是有很多可能这辈子我也不会用到,并且pycharm打开的速度确实不敢恭维 ...

  6. (转)Python新手写出漂亮的爬虫代码1——从html获取信息

    https://blog.csdn.net/weixin_36604953/article/details/78156605 Python新手写出漂亮的爬虫代码1初到大数据学习圈子的同学可能对爬虫都有 ...

  7. 我的Java历程_写出这个数

    lzJava基础进行中,今天偶然间看到的一个题目: 读入一个自然数n,计算其各位数字之和,用汉语拼音写出和的每一位数字.如下代码: import java.util.*;public class Ma ...

  8. 前端一面/面试常考题1-页面布局:假设高度已知,请写出三栏布局,其中左栏、右栏宽度各为300px,中间自适应。

    题目:假设高度已知,请写出三栏布局,其中左栏.右栏宽度各为300px,中间自适应. [题外话:日常宣读我的目标===想要成为一名优雅的程序媛] 一.分析 1. 题目真的像我们想得这么简单吗? 其实不然 ...

  9. 如何写出同事看不懂的Java代码?

    原创:微信公众号 码农参上,欢迎分享,转载请保留出处. 哈喽大家好啊,我是没更新就是在家忙着带娃的Hydra. 前几天,正巧赶上组里代码review,一下午下来,感觉整个人都血压拉满了.五花八门的代码 ...

随机推荐

  1. TDD的iOS开发初步以及Kiwi使用入门

    测试驱动开发(Test Driven Development,以下简称TDD)是保证代码质量的不二法则,也是先进程序开发的共识.Apple一直致力于在iOS开发中集成更加方便和可用的测试,在Xcode ...

  2. Ubuntu16.04 -- 后台进程Nohup

    nohup用于使程序在用户退出登陆.关闭终端之后仍能继续运行 用法: nohup your_command & #(符号&使程序在后台运行) exit #(退出nohup模式) 启动后 ...

  3. python2 to3

    http://blog.csdn.net/zhzh213/article/details/53842790 有个内部工具叫做2to3.py位置在Python3/tool/script文件夹. 首先CD ...

  4. mysql二进制安装及基础操作

    mysql二进制安装及基础操作 环境说明: 系统版本    CentOS 6.9 x86_64 软件版本    mysql-5.6.36-linux-glibc2.5-x86_64 1.安装 采用二进 ...

  5. 初识Nginx及编译安装Nginx

    初识Nginx及编译安装Nginx 环境说明: 系统版本    CentOS 6.9 x86_64 软件版本    nginx-1.12.2 1.什么是Nginx? 如果你听说或使用过Apache软件 ...

  6. nginx资源争夺问题

    nginx资源争夺问题 多个配置之间存在资源争夺的情况,需要进行整理: 学习了:https://blog.csdn.net/veryisjava/article/details/72917894 ng ...

  7. Linux——Virtualenv和pip小探

    转载自:http://mengzhuo.org/blog/virtualenv%E5%92%8Cpip%E5%B0%8F%E6%8E%A2.html 本文献给那些看着参差不齐的中文文档/教程,但还在坚 ...

  8. 【BIEE】04_当维度表中的维不存在事实表中,需要展示所有维度并且数据类展示为0

    有时候,我们往往会存在这样的需求 例如:事实表的数据如下 EMP_FACT表示事实表,DIM_LEVEL是维度表 预期效果:(根据员工信息,分析各等级员工工资与员工个数) 我们在BIEE报表中新建报表 ...

  9. 【VBA】快速填充单元格

    在Excle中,需要填充单元格,直接下拉,然后即可填充,但是使用VBA代码又该如何实现这个呢? 代码区域 Public Sub 快速填充() Dim myRange As range Cells.Cl ...

  10. AOP切面编程在android上的应用

    代码地址如下:http://www.demodashi.com/demo/12563.html 前言 切面编程一直是一个热点的话题,这篇文章讲讲一个第三方aop库在android上的应用.第三方AOP ...