【问题标题】:VS2010 C code - String poolingVS2010 C 代码 - 字符串池
【发布时间】:2011-03-18 06:13:16
【问题描述】:

当您使用以下标志编译并且添加 /GF- 或删除优化标志时,VS 2010 中的以下代码崩溃,它们不会崩溃。崩溃发生在翻译'if(path [i] =='/')'的汇编代码中。我想了解编译器在这里所​​做的优化并导致崩溃。期待一些指点。

-卡提克

cl.exe /MD /O2 test.c

//Test.c

#include <stdio.h>

#include  <string.h>

void testpath(char* path, int bufsiz)  
{  

    int i;  

    printf("%p\n", path);  
    for( i=0; i < strlen(path); i++ ) {  
      if( path[i] == '/' ) {  
         path[i] = '\\';  
     }  
  }  
}

int main()  
{  

    const char* path = "testexport.prj";  
    char *path1 = "testexport.prj";  
    printf("%p\n", path);  
    printf("%p\n", path1);  
    testpath(path, 1024);  
}  

【问题讨论】:

  • 你说这崩溃了。是否有任何其他信息说明它为什么崩溃?您显示的代码应该没有任何问题。正如您所说,条件应该阻止分配执行,因为您传递给函数的path 中没有'/' 字符。您确定您在此处显示的代码是您正在运行的代码的精确副本吗?

标签: c++ c visual-studio visual-studio-2010 winapi


【解决方案1】:

您尝试修改字符串文字,这是未定义的行为。

 const char* path = "testexport.prj";
 testpath(path, 1024);
 // then later:
 void testpath(char* path, int bufsiz)
 {
     int i;  
     for( i=0; i`<`strlen(path); i++ ) {  
     if( path[i] == '/' ) {  
         path[i] = '\\';// <<<<<< UB here
     }  
 }  

字符串文字通常存储在只读内存中,因此在您的实现中尝试修改字符串文字会导致访问冲突,从而导致程序崩溃。

【讨论】:

  • 感谢您的回复。我了解修改“字符串”文字会导致未指定的行为。但是我的观点是,由于代码中的条件检查 'path[i] == '/'' 而导致字符串文字没有被修改时,优化的构建会导致崩溃。你能评论一下吗?
  • @Kartlee:启用优化时,您无法确定调试时在哪一行,因此最可能的解释是您误解了调试会话的结果。一定要修改 if 语句:`if( path[i] == '/' ) { printf( "gonna modify\n" );路径[i] = '\\';以便在修改尝试之前有一个调试打印。我很确定程序会在修改尝试后崩溃。
  • 但是在他显示的代码中,他传递给函数的path 中没有'/' 字符。所以要么编译器中有一个非常奇怪的错误,要么他没有告诉我们。
【解决方案2】:

尝试修改 string literal 的内容会调用未定义行为。

来自 ISO C99 (Section 6.4.5/6)

如果它们的元素具有适当的值,则未指定这些数组是否不同。 如果程序尝试修改这样的数组,则行为未定义

来自 ISO C++-98 (Section 2.13.4/2)

是否所有字符串文字都是不同的(即存储在非重叠对象中)是实现定义的。 尝试修改字符串文字的效果是不确定的。

在大多数实现(包括 MSVC)上,这会导致您的应用程序崩溃。

【讨论】:

  • 感谢您的回复。我了解修改“字符串”文字会导致未指定的行为。但是我的观点是,由于代码中的条件检查 'path[i] == '/'' 而导致字符串文字没有被修改时,优化的构建会导致崩溃。你能评论一下吗?
  • @Kartlee: path[i] = '\\';尝试修改字符串文字的内容,这会导致您的应用程序崩溃,是的,行为未定义。(未指定)。 :) 条件检查很好恕我直言。
  • 当字符串文字由于条件检查而没有进入修改它的代码时会导致崩溃,这是一个真正的惊喜。你有机会看到这里到底发生了什么的汇编代码吗?如果您关闭字符串池,它们不会导致崩溃。我怀疑编译器是否在打开字符串池时提前检查字符串文字是否被修改。
【解决方案3】:

我们有一个应用程序,在 VC6.0 中似乎存在字符串池中的错误。两个不同的字符串似乎“汇集”到一个字符串,导致崩溃。在 VS2010 中不会发生这种崩溃。或者,如果在 VS6.0 中使用 /Zi 而不是 /ZI。只是想知道VS6.0中的默认值是否是使用字符串池而不是VS2010中的默认值。在这种情况下,字符串池错误可能仍然存在。如果有许多字符串几乎相同,那么我的工作理论(尚未经过审查)是在字符串池中未检测到哈希冲突,从而消除了两个字符串之一。当查看两个几乎相似的字符串的指针时,这将在生成的 ASM 代码中可见。 在我们的例子中,我们没有修改 VC6.0 中的字符串,只是引用它们。

【讨论】:

  • 如果您有新问题,请点击 按钮提出问题。如果有助于提供上下文,请包含指向此问题的链接。 - From Review
  • 我需要分享一个案例我们有一个庞大的客户群,并且使用 VS6.0 C++ 超过 12 年,我见过两个对字符串池敏感的应用程序实例。我们使用 ->name 值创建对象。我们提供了一个“find_object("String")” API 来按名称搜索对象。通过字符串池,观察到两种情况,其中对象“StringA”和“StringB”都被创建并存在,但无法通过搜索找到对象“StringB”,因为它的字符串对象已经过优化,因此它与原始字符串不匹配。生成的 *.asm 显示优化后的字符串。待定消毒,以便我可以分享。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-11
  • 2016-04-27
  • 2018-09-20
  • 1970-01-01
相关资源
最近更新 更多