2010-02-24 142 views
5

我们有一个C++/MFC应用程序,它允许用户通过配置文件自定义日期格式。不想重新发明轮子,我将格式字符串传递给CTime :: Format(“< format string>”)以执行实际的格式化。在封面下,Format调用标准C函数strftime()的变体。用不可信的格式字符串安全地调用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(); 
} 

这似乎工作,并允许我明确在我“期待”它们发生的情况下捕捉(并优雅地处理)无效参数异常。然而,我担心为了解决一个相对“本地”的问题,我在一个大型应用程序中重写全局运行时环境 - 我恨这个修复会导致其他问题。

这种方法是否合理?还是有更清晰的方法来解决这个问题?

回答

3

如果您只想在特定时间捕获此错误,则可以暂时替换无效参数处理程序,然后在调用Format后将其设回。

_invalid_parameter_handler oldHandler = _set_invalid_parameter_handler(MyInvalidParameterHandler); 

// Your try/Format/catch code here 

_set_invalid_parameter_handler(oldHandler); 

当然,我想这是可能的,如果你在你的程序有多个线程,同时它的设置另一个线程可能最终会调用您的无效参数处理程序。你将不得不确定这有多可能。

除了编写自己的验证功能,我不知道你还能怎么做。

+0

谢谢你的建议。不幸的是,我的应用程序确实是多线程的,所以我不认为我可以安全地来回切换处理程序。 (无效的参数处理程序是全局的,而不是线程特定的。) – 2010-02-24 14:19:43

+0

在这种情况下,我相信您需要创建自己的验证功能。它不应该那么难。如果您在CRT源代码中查看strftime.c,您将看到一个名为_expandtime的函数。它包含所有支持的格式说明符的case语句。你可以用它作为你的函数的基础。 – Dustin 2010-02-24 14:30:11

+0

一种可能性是添加您自己的无效参数处理程序。该文档声明,如果控制权返回到调用函数,它将返回一个错误代码。 – Dustin 2010-02-24 15:24:34

相关问题