Com 为什么微软CRT对BSTR双自由度如此宽容

Com 为什么微软CRT对BSTR双自由度如此宽容,com,free,msvcrt,bstr,Com,Free,Msvcrt,Bstr,这是我问的一个简化问题。我使用的是VS2010(CRT v100),当我双倍释放BSTR时,它不会以任何方式抱怨 BSTR s1=SysAllocString(L"test"); SysFreeString(s1); SysFreeString(s1); 好的,这个问题是高度假设性的(事实上,答案是:) SysFreeString接受一个BSTR,它是一个指针,实际上是一个具有特定语义的数字。这意味着您可以向函数提供任何值作为参数,而不仅仅是有效的BSTR或刚才有效的BSTR。为了让SysFr

这是我问的一个简化问题。我使用的是VS2010(CRT v100),当我双倍释放BSTR时,它不会以任何方式抱怨

BSTR s1=SysAllocString(L"test");
SysFreeString(s1);
SysFreeString(s1);

好的,这个问题是高度假设性的(事实上,答案是:)

SysFreeString
接受一个BSTR,它是一个指针,实际上是一个具有特定语义的数字。这意味着您可以向函数提供任何值作为参数,而不仅仅是有效的BSTR或刚才有效的BSTR。为了让SysFreeString识别无效值,它需要知道所有有效的BSTR并对照所有BSTR进行检查。你可以想象它的价格


另外,它与其他C、C++、COM或Windows API一致:<代码>免费< /> >代码>删除< /COD>,CloseHandle,IUNONS::发布…他们都希望您知道该参数是否符合发布条件。

简而言之,您的问题是:“我正在使用无效参数调用
SysFreeString
。为什么编译器允许我这样做?”

VisualC++编译器允许调用,不发出警告,因为调用本身是有效的:匹配参数类型,API函数是好的,可以转换为二进制代码执行。编译器不知道您的参数是否有效,您有责任自己跟踪


另一方面,API函数希望您传递有效的参数。它可能会也可能不会检查其有效性。关于参数:“先前分配的字符串”。因此,对于第一次调用,该值是可以的,但之后指针值不再是第二次调用的有效参数,并且行为基本上是未定义的

与CRT无关,这是一个winapi函数。这是一种基于C语言的语言,它总是给程序员足够长的绳子,只要稍有错误就调用UB。快速、方便的移植一直与安全和可靠相矛盾

SysFreeString()没有赢得任何奖项,显然它应该有一个BOOL返回类型。但是它不能,IMalloc::Free()接口函数很久以前就被弄错了。没有什么是你自己不能解决的:

BOOL SafeSysFreeString(BSTR* str) {
    if (str == NULL) {
        SetLastError(ERROR_INVALID_ARGUMENT);
        return FALSE;
    }
    SysFreeString(*str);
    *str = NULL;
    return TRUE;
}
不要犹豫,大声叫喊吧,RaiseException()发出了一声很好的响声,很难忽视。但是,用C编写COM代码是一种残忍而不寻常的惩罚,日内瓦程序员权利公约将其定为非法。使用<代码>、BSTRYTT < /COD>或<代码> CCOMBSTR> < /Cult> C++包装器类型。 但是当你把BSTR从他们身上切下来的时候,一定要小心,当你没有或者不能一致地使用他们的时候,他们帮不了你。这就是为什么你会因为这个变种而惹上麻烦。当您必须离开包装袋时,请务必格外注意,外面有C形鲨鱼。

请参见:

自动化可以缓存为BSTR分配的空间。这加快了速度 SysAllocString/SysFreeString序列

(…)如果应用程序分配BSTR并释放它,则释放块 通过自动化(…)将内存的大小放入BSTR缓存


这可以解释为什么使用同一指针调用SysFreeString(…)两次不会产生崩溃,因为内存仍然可用(某种程度上)。

您希望编译器对系统调用的语义有深入的了解吗?我会问同样的关于系统的问题。那么为什么Windows CRT在这方面如此宽容呢?SysFreeString和其他任何函数一样都是一个函数。编译器并不明确知道这一点。欢迎使用C/C++编程,作为一名程序员,您是否需要了解许多事情才能使其工作。如果你对这个环境感到不舒服,那么有“管理”的世界是为你处理的(几乎,或者至少更多):java,.net,脚本语言等等。如果你想移动C++,那么有“智能”的东西(指针,类等等),像CComBSTR或_bstr\t:如果你没有看到抱怨,那也没关系,没有什么不好的事情发生。我同意第二个自由的未定义行为。程序员应该注意这些问题。我只是想知道为什么微软在这个严肃的问题上如此宽容。只需将
SysAllocString、SysFreeString
替换为
malloc、free
new,删除同一代码中的
,即可查看结果。顺便说一句,文档中没有任何关于未定义行为的内容。传递给第二个SysFreeString的BSTR是由SysAllocString分配的。尽管从技术上讲,该参数仍然是从SysAllocString获得的,并且对于多个SysFreeString调用来说“可以”,因为文档没有明确说明一旦释放内存,指针不再是一个有效的参数,某些事情不言而喻:提到这些场景会在每一篇MSDN文章中添加几乎无关紧要的语句。使用
new
delete
编译器会进行一些有用的检查以检测错误,但是
Sys*
函数集作为常规API使用,没有特定于上下文的帮助。我想知道Microsoft为什么会允许这样的问题。C/C++标准明确定义了此类实践的未定义行为。
new
delete
[x]alloc
free
的标准C/C++实现立即对此类程序提出了一个问题。顺便说一句,该代码是更复杂代码的简单版本。其中,双自由度是由一个C变量的重复引起的。错误可能更微妙,这就是为什么应该立即公开双重免费的原因。我不太清楚你希望微软如何处理它。他们不能阻止你做那个函数调用。如果它们引发异常,那么程序运行会变慢,因为需要进行额外的检查,10%的业务关键型软件会崩溃并停止工作。这不是一个让人们