C ++
我在代码中使用了很多像strncpy,strncat,sprintf等字符串函数。 我知道有更好的替代方案,但是我交出了一个旧项目,在这些项目中使用了这些功能,所以为了兼容性和一致性,我必须坚持使用这些功能。 我的主管对错误检查和健壮性非常挑剔,并坚持每次使用这些函数时检查缓冲区溢出违规。 这在我的代码中创建了很多if-else语句,看起来不太漂亮。 我的问题是,每次我调用其中一个函数时,是否真的有必要检查溢出? 即使我知道缓冲区溢出不可能发生,例如使用sprintf函数在字符串中存储整数时
sprintf(buf,"%d",someInteger);
我知道64位系统上无符号整数的最大长度可以是20位数。 另一方面,buf远远超过20个字符。 在这种情况下,我还应该检查缓冲区溢出吗?
我认为要走的路是使用例外 。 当你必须解耦程序的正常控制流程和错误检查时,异常是非常有用的。
你可以做的是为每个字符串函数创建一个包装器,在其中执行错误检查并在发生缓冲区溢出时抛出异常。
然后,在您的客户端代码中,您可以简单地在try
块内调用您的包装,然后检查catch
块中的异常并返回错误代码。
示例代码(未经测试):
int sprintf_wrapper( char *buffer, int buffer_size, const char *format, ... )
{
if( /* check for buffer overflow */ )
throw my_buffer_exception;
va_list arg_ptr;
va_start( arg_ptr, format );
int ret = sprintf( buffer, , format, arg_ptr );
va_end(arg_ptr);
return ret;
}
Error foo()
{
//...
try{
sprintf_wrapper(buf1, 100, "%d", i1);
sprintf_wrapper(buf2, 100, "%d", i2);
sprintf_wrapper(buf3, 100, "%d", i3);
}
catch( my_buffer_exception& )
{
return err_code;
}
}
也许编写一个可以调用的测试用例来简单地测试缓冲区以减少代码重复和丑陋。
您可以将if / else语句抽象为另一个类的方法,然后传递缓冲区和期望的长度。
就本质而言,这些缓冲区非常容易被覆盖,所以要小心从用户/外部源输入的任何时间。 您也可以尝试获取字符串长度(使用strlen),或者自己检查/ 0结束字符串字符,并将其与缓冲区大小进行比较。 如果你为/ 0字符循环,而它不在那里,如果你没有通过期望的缓冲区大小限制你的循环的最大大小,你将进入一个无限循环,所以检查它也是如此。
另一种选择是重构代码,以便每次使用这些方法时,都将它们替换为您编写的一个长度安全的版本,并在那里调用已有适当检查的方法(但必须将缓冲区大小传递给它) 。 对于某些项目来说这可能是不可能的,因为复杂性可能很难进行单元测试。
让我首先解释你的最后一段:你写一次代码,而不是它将被维护和使用多久。 猜猜你认为你的代码会被使用多长时间,然后乘以10-20来确定它实际使用的时间。 在那个窗口的末尾,一个整数可能会大得多,并且溢出缓冲区,所以你必须做缓冲区检查。
鉴于你有几个选择:
使用“n”系列函数(如snprintf
来防止缓冲区溢出,并告诉用户它未定义如果缓冲区溢出会发生什么情况。
考虑它是致命的,要么是abort()
,要么是在发生长度违例时抛出未捕获的异常。
尝试通知用户存在问题,并中止操作或尝试让用户修改输入并重试。
前两种方法肯定会更容易实施和维护,因为您不必担心以合理的方式将正确的信息返回给用户。 在任何情况下,您都可能将其作为其他答案中建议的函数考虑进去。
最后,让我说,因为你已经标记了C ++而不是C这个问题,所以想想慢慢地将你的代码库迁移到C ++(因为你的代码库现在是C)并且利用C ++工具,然后完全消除这些缓冲区检查,因为它会自动为你发生。
链接地址: http://www.djcxy.com/p/29439.html上一篇: c++