【问题标题】:Safely calling strftime with untrusted format string使用不受信任的格式字符串安全地调用 strftime
【发布时间】:2011-01-20 13:22:01
【问题描述】:

我们有一个 C++/MFC 应用程序,它允许用户通过配置文件自定义日期格式。不想重新发明轮子,我将格式字符串传递给 CTime::Format("") 以进行实际格式化。在幕后,Format 调用标准 C 函数 strftime() 的变体。

当然,用户可能会意外输入无效的格式字符串。 (例如,“%s”而不是“%S”。)发生这种情况时,C 运行时调用Invalid Argument Handler,默认情况下,它会退出应用程序。 (没有异常可捕获——只是应用退出。)

我的问题是如何优雅地处理这种不受信任的输入。理论上,我可以为格式字符串编写自己的解析器/验证器,但这听起来像是在浪费时间。相反,我能想到的最好办法是设置我自己的(全局)无效参数处理程序,它不会退出,而是抛出一个无效参数异常:

void MyInvalidParameterHandler(
    const wchar_t* expression,
    const wchar_t* function, 
    const wchar_t* file, 
    unsigned int line, 
    uintptr_t pReserved)
{
    ::AfxThrowInvalidArgException();
}

这似乎确实有效,并且允许我在我“期望”它们发生的情况下显式捕获(并优雅地处理)无效参数异常。然而,我担心我正在覆盖大型应用程序中的全局运行时设置,以解决相对“本地”的问题——我不希望这个修复在其他地方引起额外的问题。

这种方法合理吗?或者有没有更简洁的方法来解决这个问题?

【问题讨论】:

    标签: mfc validation strftime


    【解决方案1】:

    如果您只对在特定时间捕获此错误感兴趣,您可以暂时替换无效的参数处理程序,然后在调用 Format 后将其重新设置。

    _invalid_parameter_handler oldHandler = _set_invalid_parameter_handler(MyInvalidParameterHandler);
    
    // Your try/Format/catch code here
    
    _set_invalid_parameter_handler(oldHandler);
    

    当然,我想如果你的程序中有多个线程,另一个线程可能会在设置时调用你的无效参数处理程序。您必须确定这种可能性有多大。

    除了编写您自己的验证函数之外,我不确定您还能如何做到这一点。

    【讨论】:

    • 感谢您的建议。不幸的是,我的应用程序确实是多线程的,所以我认为我不能安全地来回切换处理程序。 (无效的参数处理程序是全局的,而不是特定于线程的。)
    • 在这种情况下,我相信您将需要创建自己的验证函数。它不应该那么难。如果您查看 CRT 源代码中的 strftime.c,您将看到一个名为 _expandtime 的函数。它包含所有支持的格式说明符的 case 语句。您可以将其用作您的功能的基础。
    • 一种可能性是添加您自己的无效参数处理程序,它什么都不做。文档指出,如果控制权返回给调用函数,它将返回错误代码。
    • 我已经验证这确实有效。在 Debug 构建中,您仍然会因为断言而获得断点,但在 Release 构建中 strftime 将返回 0 并且 errno 将包含 EINVAL。
    • 谢谢,达斯汀。我认为一个不做任何事情(要求调用者检查 errno)或抛出异常(要求调用者捕获)的全局处理程序都是可接受的解决方案。
    猜你喜欢
    • 2013-02-27
    • 1970-01-01
    • 2013-04-21
    • 2015-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-20
    • 1970-01-01
    相关资源
    最近更新 更多