程序不能使用编译选项-O3

时间:2021-06-06 02:12:26

I'm writing a C++ program that doesn't work (I get a segmentation fault) when I compile it with optimizations (options -O1, -O2, -O3, etc.), but it works just fine when I compile it without optimizations.

我正在编写一个c++程序,当我用优化(选项-O1, -O2, -O3,等等)编译时,它不工作(我得到了一个分段错误),但是当我编译它而不进行优化时,它就运行得很好了。

Is there any chance that the error is in my code? or should I assume that this is a bug in GCC?

有没有可能我的代码中有错误?还是假设这是GCC中的一个bug ?

My GCC version is 3.4.6.

我的GCC版本是3.4.6。

Is there any known workaround for this kind of problem?

有什么方法可以解决这类问题吗?

There is a big difference in speed between the optimized and unoptimized version of my program, so I really need to use optimizations.

我的程序的优化版本和未优化版本之间的速度差别很大,所以我确实需要使用优化。


This is my original functor. The one that works fine with no levels of optimizations and throws a segmentation fault with any level of optimization:

这是原来的函数。在没有优化级别的情况下运行良好,并且在任何级别的优化中抛出分割错误:

struct distanceToPointSort{
    indexedDocument* point ;
    distanceToPointSort(indexedDocument* p): point(p) {}
    bool operator() (indexedDocument* p1,indexedDocument* p2){
        return distance(point,p1) < distance(point,p2) ;
    }
} ;

And this one works flawlessly with any level of optimization:

这一项在任何层次的优化中都是完美的:

struct distanceToPointSort{
    indexedDocument* point ;
    distanceToPointSort(indexedDocument* p): point(p) {}
    bool operator() (indexedDocument* p1,indexedDocument* p2){

        float d1=distance(point,p1) ;
        float d2=distance(point,p2) ;

        std::cout << "" ;  //without this line, I get a segmentation fault anyways

        return d1 < d2 ;
    }
} ;

Unfortunately, this problem is hard to reproduce because it happens with some specific values. I get the segmentation fault upon sorting just one out of more than a thousand vectors, so it really depends on the specific combination of values each vector has.

不幸的是,这个问题很难重现,因为它发生在特定的值上。我只对一千多个向量中的一个进行了排序,这就导致了分割的错误,所以这实际上取决于每个向量的值的特定组合。

16 个解决方案

#1


8  

Now that you posted the code fragment and a working workaround was found (@Windows programmer's answer), I can say that perhaps what you are looking for is -ffloat-store.

既然您已经发布了代码片段,并且找到了一个可行的解决方案(@Windows程序员的答案),我可以说您正在寻找的可能是-ffloat-store。

-ffloat-store

-ffloat-store

Do not store floating point variables in registers, and inhibit other options that might change whether a floating point value is taken from a register or memory.

不要在寄存器中存储浮点变量,并禁止其他可能更改是否从寄存器或内存中获取浮点值的选项。

This option prevents undesirable excess precision on machines such as the 68000 where the floating registers (of the 68881) keep more precision than a double is supposed to have. Similarly for the x86 architecture. For most programs, the excess precision does only good, but a few programs rely on the precise definition of IEEE floating point. Use -ffloat-store for such programs, after modifying them to store all pertinent intermediate computations into variables.

这个选项可以防止在诸如68000这样的机器上出现不必要的过度精度,在68881中浮动寄存器的精度比双精度寄存器的精度要高。x86体系结构也是如此。对于大多数程序来说,过高的精度只会带来好处,但是有一些程序依赖于IEEE浮点的精确定义。对这些程序使用-ffloat-store,在修改后将所有相关的中间计算存储到变量中。

Source: http://gcc.gnu.org/onlinedocs/gcc-3.4.6/gcc/Optimize-Options.html

来源:http://gcc.gnu.org/onlinedocs/gcc-3.4.6/gcc/Optimize-Options.html

#2


7  

I would assume your code is wrong first.
Though it is hard to tell.

我认为您的代码首先是错误的。虽然很难说。

Does your code compile with 0 warnings?

您的代码是否使用0警告进行编译?

 g++ -Wall -Wextra -pedantic -ansi

#3


7  

Here's some code that seems to work, until you hit -O3...

这里有一些似乎可以工作的代码,直到你点击-O3…

#include <stdio.h>

int main()
{
    int i = 0, j = 1, k = 2;
    printf("%d %d %d\n", *(&j-1), *(&j), *(&j+1));
    return 0;
}

Without optimisations, I get "2 1 0"; with optimisations I get "40 1 2293680". Why? Because i and k got optimised out!

没有优化,我得到“2 1 0”;使用优化,我得到“4012293680”。为什么?因为我和k被优化了!

But I was taking the address of j and going out of the memory region allocated to j. That's not allowed by the standard. It's most likely that your problem is caused by a similar deviation from the standard.

但是我取了j的地址然后离开了分配给j的内存区域,这是标准不允许的。你的问题很可能是由类似的偏离标准引起的。

I find valgrind is often helpful at times like these.

我发现像这样的时候,valgrind很有帮助。

EDIT: Some commenters are under the impression that the standard allows arbitrary pointer arithmetic. It does not. Remember that some architectures have funny addressing schemes, alignment may be important, and you may get problems if you overflow certain registers!

编辑:一些评论者认为标准允许任意的指针算法。它不。请记住,有些架构具有有趣的寻址方案,对齐可能很重要,如果溢出某些寄存器,您可能会遇到问题!

The words of the [draft] standard, on adding/subtracting an integer to/from a pointer (emphasis added):

[草案]标准的字,关于在一个指针上加/减一个整数(重点增加):

"If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined."

“如果指针操作数和结果点都指向同一数组对象的元素,或数组对象最后一个元素后的元素,则计算不产生溢出;否则,行为就没有定义。

Seeing as &j doesn't even point to an array object, &j-1 and &j+1 can hardly point to part of the same array object. So simply evaluating &j+1 (let alone dereferencing it) is undefined behaviour.

因为&j甚至没有指向数组对象,&j-1和&j+1几乎不能指向相同数组对象的一部分。因此,简单地计算&j+1(更不用说取消它的引用)是没有定义的行为。

On x86 we can be pretty confident that adding one to a pointer is fairly safe and just takes us to the next memory location. In the code above, the problem occurs when we make assumptions about what that memory contains, which of course the standard doesn't go near.

在x86上,我们可以非常自信地认为向指针添加一个是相当安全的,只需将我们带到下一个内存位置。在上面的代码中,当我们对内存包含的内容进行假设时,问题就出现了,这当然是标准所没有的。

#4


5  

As an experiment, try to see if this will force the compiler to round everything consistently.

作为实验,尝试看看这是否会迫使编译器始终如一地遍历所有内容。

volatile float d1=distance(point,p1) ;
volatile float d2=distance(point,p2) ;
return d1 < d2 ;

#5


5  

The error is in your code. It's likely you're doing something that invokes undefined behavior according to the C standard which just happens to work with no optimizations, but when GCC makes certain assumptions for performing its optimizations, the code breaks when those assumptions aren't true. Make sure to compile with the -Wall option, and the -Wextra might also be a good idea, and see if you get any warnings. You could also try -ansi or -pedantic, but those are likely to result in false positives.

错误在代码中。很可能您正在做的事情是根据C标准调用未定义的行为,而C标准只是在没有优化的情况下工作,但是当GCC为执行它的优化做了某些假设时,当这些假设不正确时,代码就会中断。确保使用-Wall选项进行编译,并且-Wextra也可能是一个好主意,看看是否得到任何警告。你也可以尝试-ansi或-pedantic,但这些可能会导致误报。

#6


4  

You may be running into an aliasing problem (or it could be a million other things). Look up the -fstrict-aliasing option.

你可能会遇到混叠问题(也可能是其他很多问题)。查找-fstrict- alialize选项。

This kind of question is impossible to answer properly without more information.

如果没有更多的信息,这种问题是不可能正确回答的。

#7


3  

It is very seldom the compiler fault, but compiler do have bugs in them, and them often manifest themselves at different optimization levels (if there is a bug in an optimization pass, for example).

这很少是编译器的错误,但是编译器中确实有错误,并且它们经常在不同的优化级别上出现(例如,如果优化传递中有错误)。

In general when reporting programming problems: provide a minimal code sample to demonstrate the issue, such that people can just save the code to a file, compile and run it. Make it as easy as possible to reproduce your problem.

通常在报告编程问题时:提供一个最小的代码示例来演示问题,这样人们就可以将代码保存到一个文件中,编译并运行它。尽可能地让你的问题重现得更容易。

Also, try different versions of GCC (compiling your own GCC is very easy, especially on Linux). If possible, try with another compiler. Intel C has a compiler which is more or less GCC compatible (and free for non-commercial use, I think). This will help pinpointing the problem.

另外,尝试不同版本的GCC(编译您自己的GCC非常容易,特别是在Linux上)。如果可能,尝试使用另一个编译器。Intel C有一个或多或少兼容GCC的编译器(我认为对于非商业用途是免费的)。这将有助于明确问题所在。

#8


2  

It's almost (almost) never the compiler.

它几乎(几乎)不是编译器。

First, make sure you're compiling warning-free, with -Wall.

首先,确保编译时没有任何警告,使用-Wall。

If that didn't give you a "eureka" moment, attach a debugger to the least optimized version of your executable that crashes and see what it's doing and where it goes.

如果这并没有给你一个“eureka”的时刻,那就在你的可执行文件中添加一个调试器,让它崩溃,看看它在做什么,在哪里运行。

5 will get you 10 that you've fixed the problem by this point.

5将使你得到10你已经解决了这个问题。

#9


2  

Ran into the same problem a few days ago, in my case it was aliasing. And GCC does it differently, but not wrongly, when compared to other compilers. GCC has become what some might call a rules-lawyer of the C++ standard, and their implementation is correct, but you also have to be really correct in you C++, or it'll over optimize somethings, which is a pain. But you get speed, so can't complain.

几天前遇到了同样的问题,在我的例子中是混叠。与其他编译器相比,GCC的工作方式不同,但不是错误的。GCC已经成为了一些人所说的规则——c++标准的律师,它们的实现是正确的,但是你也必须在你的c++中是真正正确的,否则它会对一些事情进行过度优化,这是很痛苦的。但是你有速度,所以不要抱怨。

#10


1  

I expect to get some downvotes here after reading some of the comments, but in the console game programming world, it's rather common knowledge that the higher optimization levels can sometimes generate incorrect code in weird edge cases. It might very well be that edge cases can be fixed with subtle changes to the code, though.

在阅读了一些评论之后,我期望在这里得到一些下选,但是在控制台游戏编程世界中,通常都知道更高的优化级别有时会在奇怪的边缘情况下生成不正确的代码。不过,很有可能的是,边界情况可以通过对代码的细微更改来修复。

#11


1  

Alright... This is one of the weirdest problems I've ever had.
I dont think I have enough proof to state it's a GCC bug, but honestly... It really looks like one.

好吧……这是我遇到过的最奇怪的问题之一。我想我没有足够的证据证明它是一个GCC bug,但老实说……看起来真的很像。

This is my original functor. The one that works fine with no levels of optimizations and throws a segmentation fault with any level of optimization:

这是原来的函数。在没有优化级别的情况下运行良好,并且在任何级别的优化中抛出分割错误:

struct distanceToPointSort{
    indexedDocument* point ;
    distanceToPointSort(indexedDocument* p): point(p) {}
    bool operator() (indexedDocument* p1,indexedDocument* p2){
        return distance(point,p1) < distance(point,p2) ;
    }
} ;

And this one works flawlessly with any level of optimization:

这一项在任何层次的优化中都是完美的:

struct distanceToPointSort{
    indexedDocument* point ;
    distanceToPointSort(indexedDocument* p): point(p) {}
    bool operator() (indexedDocument* p1,indexedDocument* p2){

        float d1=distance(point,p1) ;
        float d2=distance(point,p2) ;

        std::cout << "" ;  //without this line, I get a segmentation fault anyways

        return d1 < d2 ;
    }
} ;

Unfortunately, this problem is hard to reproduce because it happens with some specific values. I get the segmentation fault upon sorting just one out of more than a thousand vectors, so it really depends on the specific combination of values each vector has.

不幸的是,这个问题很难重现,因为它发生在特定的值上。我只对一千多个向量中的一个进行了排序,这就导致了分割的错误,所以这实际上取决于每个向量的值的特定组合。

#12


1  

post the code in distance! it probably does some pointer magic, see my previous post. doing an intermediate assignment just hides the bug in your code by changing register allocation. even more telling of this is the output changing things!

把代码放在远处!它可能会做一些指针魔术,见我之前的帖子。做一个中间的任务只是通过改变寄存器的分配来隐藏代码中的错误。更能说明这一点的是输出改变的事情!

#13


0  

Wow, I didn't expect answers so quicly, and so many...

哇,我没想到答案这么快,这么多……

The error occurs upon sorting a std::vector of pointers using std::sort()

在使用std::sort()对std:::指针向量进行排序时发生错误

I provide the strict-weak-ordering functor.

我提供严格弱序函数。

But I know the functor I provide is correct because I've used it a lot and it works fine.

但我知道我提供的函子是正确的,因为我用了很多,而且效果很好。

Plus, the error cannot be some invalid pointer in the vector becasue the error occurs just when I sort the vector. If I iterate through the vector without applying std::sort first, the program works fine.

另外,错误不可能是向量中某个无效的指针,因为错误发生在我对向量排序的时候。如果我在向量中迭代而不应用std::sort first,程序就可以正常工作。

I just used GDB to try to find out what's going on. The error occurs when std::sort invoke my functor. Aparently std::sort is passing an invalid pointer to my functor. (of course this happens with the optimized version only, any level of optimization -O, -O2, -O3)

我只是用GDB试着找出发生了什么。当std::sort调用我的函数时发生错误。sort是向我的函数传递一个无效的指针。(当然这只发生在优化版本中,任何级别的优化-O, -O2, -O3)

#14


0  

as other have pointed out, probably strict aliasing. turn it of in o3 and try again. My guess is that you are doing some pointer tricks in your functor (fast float as int compare? object type in lower 2 bits?) that fail across inlining template functions. warnings do not help to catch this case. "if the compiler could detect all strict aliasing problems it could just as well avoid them" just changing an unrelated line of code may make the problem appear or go away as it changes register allocation.

正如其他人指出的,可能是严格的假混。打开o3,再试一次。我的猜测是您在您的函子中做了一些指针技巧(快速浮点数作为int比较?对象类型在较低的2位中),在内联模板函数中失败。警告无助于发现这种情况。“如果编译器能够检测到所有严格的混叠问题,它也可以避免它们”仅仅更改一个不相关的代码行可能会使问题出现或消失,因为它改变了寄存器分配。

#15


0  

As the updated question will show ;) , the problem exists with a std::vector<T*>. One common error with vectors is reserve()ing what should have been resize()d. As a result, you'd be writing outside array bounds. An optimizer may discard those writes.

更新后的问题将显示;),问题存在于std::vector 。向量的一个常见错误是reserve()调整()d的大小。结果,你会写在数组边界之外。优化器可能会丢弃这些写操作。 *>

#16


0  

The true answer is hidden somewhere inside all the comments in this thread. First of all: it is not a bug in the compiler.

真正的答案隐藏在这个线程的所有注释里面。首先:它不是编译器中的错误。

The problem has to do with floating point precision. distanceToPointSort should be a function that should never return true for both the arguments (a,b) and (b,a), but that is exactly what can happen when the compiler decides to use higher precision for some data paths. The problem is especially likely on, but by no means limited to, x86 without -mfpmath=sse. If the comparator behaves that way, the sort function can become confused, and the segmentation fault is not surprising.

这个问题与浮点精度有关。distancetoplesisort应该是一个对于参数(a、b)和(b、a)都不应该返回true的函数,但是当编译器决定对某些数据路径使用更高的精度时,这正是可能发生的事情。这个问题特别可能出现在没有-mfpmath=sse的x86上,但绝不仅限于此。如果比较器以这种方式运行,排序函数就会变得混乱,分割错误也就不足为奇了。

I consider -ffloat-store the best solution here (already suggested by CesarB).

我认为-ffloat-store是这里最好的解决方案(已经由CesarB建议)。

#1


8  

Now that you posted the code fragment and a working workaround was found (@Windows programmer's answer), I can say that perhaps what you are looking for is -ffloat-store.

既然您已经发布了代码片段,并且找到了一个可行的解决方案(@Windows程序员的答案),我可以说您正在寻找的可能是-ffloat-store。

-ffloat-store

-ffloat-store

Do not store floating point variables in registers, and inhibit other options that might change whether a floating point value is taken from a register or memory.

不要在寄存器中存储浮点变量,并禁止其他可能更改是否从寄存器或内存中获取浮点值的选项。

This option prevents undesirable excess precision on machines such as the 68000 where the floating registers (of the 68881) keep more precision than a double is supposed to have. Similarly for the x86 architecture. For most programs, the excess precision does only good, but a few programs rely on the precise definition of IEEE floating point. Use -ffloat-store for such programs, after modifying them to store all pertinent intermediate computations into variables.

这个选项可以防止在诸如68000这样的机器上出现不必要的过度精度,在68881中浮动寄存器的精度比双精度寄存器的精度要高。x86体系结构也是如此。对于大多数程序来说,过高的精度只会带来好处,但是有一些程序依赖于IEEE浮点的精确定义。对这些程序使用-ffloat-store,在修改后将所有相关的中间计算存储到变量中。

Source: http://gcc.gnu.org/onlinedocs/gcc-3.4.6/gcc/Optimize-Options.html

来源:http://gcc.gnu.org/onlinedocs/gcc-3.4.6/gcc/Optimize-Options.html

#2


7  

I would assume your code is wrong first.
Though it is hard to tell.

我认为您的代码首先是错误的。虽然很难说。

Does your code compile with 0 warnings?

您的代码是否使用0警告进行编译?

 g++ -Wall -Wextra -pedantic -ansi

#3


7  

Here's some code that seems to work, until you hit -O3...

这里有一些似乎可以工作的代码,直到你点击-O3…

#include <stdio.h>

int main()
{
    int i = 0, j = 1, k = 2;
    printf("%d %d %d\n", *(&j-1), *(&j), *(&j+1));
    return 0;
}

Without optimisations, I get "2 1 0"; with optimisations I get "40 1 2293680". Why? Because i and k got optimised out!

没有优化,我得到“2 1 0”;使用优化,我得到“4012293680”。为什么?因为我和k被优化了!

But I was taking the address of j and going out of the memory region allocated to j. That's not allowed by the standard. It's most likely that your problem is caused by a similar deviation from the standard.

但是我取了j的地址然后离开了分配给j的内存区域,这是标准不允许的。你的问题很可能是由类似的偏离标准引起的。

I find valgrind is often helpful at times like these.

我发现像这样的时候,valgrind很有帮助。

EDIT: Some commenters are under the impression that the standard allows arbitrary pointer arithmetic. It does not. Remember that some architectures have funny addressing schemes, alignment may be important, and you may get problems if you overflow certain registers!

编辑:一些评论者认为标准允许任意的指针算法。它不。请记住,有些架构具有有趣的寻址方案,对齐可能很重要,如果溢出某些寄存器,您可能会遇到问题!

The words of the [draft] standard, on adding/subtracting an integer to/from a pointer (emphasis added):

[草案]标准的字,关于在一个指针上加/减一个整数(重点增加):

"If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined."

“如果指针操作数和结果点都指向同一数组对象的元素,或数组对象最后一个元素后的元素,则计算不产生溢出;否则,行为就没有定义。

Seeing as &j doesn't even point to an array object, &j-1 and &j+1 can hardly point to part of the same array object. So simply evaluating &j+1 (let alone dereferencing it) is undefined behaviour.

因为&j甚至没有指向数组对象,&j-1和&j+1几乎不能指向相同数组对象的一部分。因此,简单地计算&j+1(更不用说取消它的引用)是没有定义的行为。

On x86 we can be pretty confident that adding one to a pointer is fairly safe and just takes us to the next memory location. In the code above, the problem occurs when we make assumptions about what that memory contains, which of course the standard doesn't go near.

在x86上,我们可以非常自信地认为向指针添加一个是相当安全的,只需将我们带到下一个内存位置。在上面的代码中,当我们对内存包含的内容进行假设时,问题就出现了,这当然是标准所没有的。

#4


5  

As an experiment, try to see if this will force the compiler to round everything consistently.

作为实验,尝试看看这是否会迫使编译器始终如一地遍历所有内容。

volatile float d1=distance(point,p1) ;
volatile float d2=distance(point,p2) ;
return d1 < d2 ;

#5


5  

The error is in your code. It's likely you're doing something that invokes undefined behavior according to the C standard which just happens to work with no optimizations, but when GCC makes certain assumptions for performing its optimizations, the code breaks when those assumptions aren't true. Make sure to compile with the -Wall option, and the -Wextra might also be a good idea, and see if you get any warnings. You could also try -ansi or -pedantic, but those are likely to result in false positives.

错误在代码中。很可能您正在做的事情是根据C标准调用未定义的行为,而C标准只是在没有优化的情况下工作,但是当GCC为执行它的优化做了某些假设时,当这些假设不正确时,代码就会中断。确保使用-Wall选项进行编译,并且-Wextra也可能是一个好主意,看看是否得到任何警告。你也可以尝试-ansi或-pedantic,但这些可能会导致误报。

#6


4  

You may be running into an aliasing problem (or it could be a million other things). Look up the -fstrict-aliasing option.

你可能会遇到混叠问题(也可能是其他很多问题)。查找-fstrict- alialize选项。

This kind of question is impossible to answer properly without more information.

如果没有更多的信息,这种问题是不可能正确回答的。

#7


3  

It is very seldom the compiler fault, but compiler do have bugs in them, and them often manifest themselves at different optimization levels (if there is a bug in an optimization pass, for example).

这很少是编译器的错误,但是编译器中确实有错误,并且它们经常在不同的优化级别上出现(例如,如果优化传递中有错误)。

In general when reporting programming problems: provide a minimal code sample to demonstrate the issue, such that people can just save the code to a file, compile and run it. Make it as easy as possible to reproduce your problem.

通常在报告编程问题时:提供一个最小的代码示例来演示问题,这样人们就可以将代码保存到一个文件中,编译并运行它。尽可能地让你的问题重现得更容易。

Also, try different versions of GCC (compiling your own GCC is very easy, especially on Linux). If possible, try with another compiler. Intel C has a compiler which is more or less GCC compatible (and free for non-commercial use, I think). This will help pinpointing the problem.

另外,尝试不同版本的GCC(编译您自己的GCC非常容易,特别是在Linux上)。如果可能,尝试使用另一个编译器。Intel C有一个或多或少兼容GCC的编译器(我认为对于非商业用途是免费的)。这将有助于明确问题所在。

#8


2  

It's almost (almost) never the compiler.

它几乎(几乎)不是编译器。

First, make sure you're compiling warning-free, with -Wall.

首先,确保编译时没有任何警告,使用-Wall。

If that didn't give you a "eureka" moment, attach a debugger to the least optimized version of your executable that crashes and see what it's doing and where it goes.

如果这并没有给你一个“eureka”的时刻,那就在你的可执行文件中添加一个调试器,让它崩溃,看看它在做什么,在哪里运行。

5 will get you 10 that you've fixed the problem by this point.

5将使你得到10你已经解决了这个问题。

#9


2  

Ran into the same problem a few days ago, in my case it was aliasing. And GCC does it differently, but not wrongly, when compared to other compilers. GCC has become what some might call a rules-lawyer of the C++ standard, and their implementation is correct, but you also have to be really correct in you C++, or it'll over optimize somethings, which is a pain. But you get speed, so can't complain.

几天前遇到了同样的问题,在我的例子中是混叠。与其他编译器相比,GCC的工作方式不同,但不是错误的。GCC已经成为了一些人所说的规则——c++标准的律师,它们的实现是正确的,但是你也必须在你的c++中是真正正确的,否则它会对一些事情进行过度优化,这是很痛苦的。但是你有速度,所以不要抱怨。

#10


1  

I expect to get some downvotes here after reading some of the comments, but in the console game programming world, it's rather common knowledge that the higher optimization levels can sometimes generate incorrect code in weird edge cases. It might very well be that edge cases can be fixed with subtle changes to the code, though.

在阅读了一些评论之后,我期望在这里得到一些下选,但是在控制台游戏编程世界中,通常都知道更高的优化级别有时会在奇怪的边缘情况下生成不正确的代码。不过,很有可能的是,边界情况可以通过对代码的细微更改来修复。

#11


1  

Alright... This is one of the weirdest problems I've ever had.
I dont think I have enough proof to state it's a GCC bug, but honestly... It really looks like one.

好吧……这是我遇到过的最奇怪的问题之一。我想我没有足够的证据证明它是一个GCC bug,但老实说……看起来真的很像。

This is my original functor. The one that works fine with no levels of optimizations and throws a segmentation fault with any level of optimization:

这是原来的函数。在没有优化级别的情况下运行良好,并且在任何级别的优化中抛出分割错误:

struct distanceToPointSort{
    indexedDocument* point ;
    distanceToPointSort(indexedDocument* p): point(p) {}
    bool operator() (indexedDocument* p1,indexedDocument* p2){
        return distance(point,p1) < distance(point,p2) ;
    }
} ;

And this one works flawlessly with any level of optimization:

这一项在任何层次的优化中都是完美的:

struct distanceToPointSort{
    indexedDocument* point ;
    distanceToPointSort(indexedDocument* p): point(p) {}
    bool operator() (indexedDocument* p1,indexedDocument* p2){

        float d1=distance(point,p1) ;
        float d2=distance(point,p2) ;

        std::cout << "" ;  //without this line, I get a segmentation fault anyways

        return d1 < d2 ;
    }
} ;

Unfortunately, this problem is hard to reproduce because it happens with some specific values. I get the segmentation fault upon sorting just one out of more than a thousand vectors, so it really depends on the specific combination of values each vector has.

不幸的是,这个问题很难重现,因为它发生在特定的值上。我只对一千多个向量中的一个进行了排序,这就导致了分割的错误,所以这实际上取决于每个向量的值的特定组合。

#12


1  

post the code in distance! it probably does some pointer magic, see my previous post. doing an intermediate assignment just hides the bug in your code by changing register allocation. even more telling of this is the output changing things!

把代码放在远处!它可能会做一些指针魔术,见我之前的帖子。做一个中间的任务只是通过改变寄存器的分配来隐藏代码中的错误。更能说明这一点的是输出改变的事情!

#13


0  

Wow, I didn't expect answers so quicly, and so many...

哇,我没想到答案这么快,这么多……

The error occurs upon sorting a std::vector of pointers using std::sort()

在使用std::sort()对std:::指针向量进行排序时发生错误

I provide the strict-weak-ordering functor.

我提供严格弱序函数。

But I know the functor I provide is correct because I've used it a lot and it works fine.

但我知道我提供的函子是正确的,因为我用了很多,而且效果很好。

Plus, the error cannot be some invalid pointer in the vector becasue the error occurs just when I sort the vector. If I iterate through the vector without applying std::sort first, the program works fine.

另外,错误不可能是向量中某个无效的指针,因为错误发生在我对向量排序的时候。如果我在向量中迭代而不应用std::sort first,程序就可以正常工作。

I just used GDB to try to find out what's going on. The error occurs when std::sort invoke my functor. Aparently std::sort is passing an invalid pointer to my functor. (of course this happens with the optimized version only, any level of optimization -O, -O2, -O3)

我只是用GDB试着找出发生了什么。当std::sort调用我的函数时发生错误。sort是向我的函数传递一个无效的指针。(当然这只发生在优化版本中,任何级别的优化-O, -O2, -O3)

#14


0  

as other have pointed out, probably strict aliasing. turn it of in o3 and try again. My guess is that you are doing some pointer tricks in your functor (fast float as int compare? object type in lower 2 bits?) that fail across inlining template functions. warnings do not help to catch this case. "if the compiler could detect all strict aliasing problems it could just as well avoid them" just changing an unrelated line of code may make the problem appear or go away as it changes register allocation.

正如其他人指出的,可能是严格的假混。打开o3,再试一次。我的猜测是您在您的函子中做了一些指针技巧(快速浮点数作为int比较?对象类型在较低的2位中),在内联模板函数中失败。警告无助于发现这种情况。“如果编译器能够检测到所有严格的混叠问题,它也可以避免它们”仅仅更改一个不相关的代码行可能会使问题出现或消失,因为它改变了寄存器分配。

#15


0  

As the updated question will show ;) , the problem exists with a std::vector<T*>. One common error with vectors is reserve()ing what should have been resize()d. As a result, you'd be writing outside array bounds. An optimizer may discard those writes.

更新后的问题将显示;),问题存在于std::vector 。向量的一个常见错误是reserve()调整()d的大小。结果,你会写在数组边界之外。优化器可能会丢弃这些写操作。 *>

#16


0  

The true answer is hidden somewhere inside all the comments in this thread. First of all: it is not a bug in the compiler.

真正的答案隐藏在这个线程的所有注释里面。首先:它不是编译器中的错误。

The problem has to do with floating point precision. distanceToPointSort should be a function that should never return true for both the arguments (a,b) and (b,a), but that is exactly what can happen when the compiler decides to use higher precision for some data paths. The problem is especially likely on, but by no means limited to, x86 without -mfpmath=sse. If the comparator behaves that way, the sort function can become confused, and the segmentation fault is not surprising.

这个问题与浮点精度有关。distancetoplesisort应该是一个对于参数(a、b)和(b、a)都不应该返回true的函数,但是当编译器决定对某些数据路径使用更高的精度时,这正是可能发生的事情。这个问题特别可能出现在没有-mfpmath=sse的x86上,但绝不仅限于此。如果比较器以这种方式运行,排序函数就会变得混乱,分割错误也就不足为奇了。

I consider -ffloat-store the best solution here (already suggested by CesarB).

我认为-ffloat-store是这里最好的解决方案(已经由CesarB建议)。