<div dir="ltr">Hi Duncan,<div><br></div><div>Ok, I found that even if main() does reference foo, setup() still gets chopped off and the results is the unexpected:</div><div><br></div><div><div>Foo: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 </div>
<div>Bar: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 </div><div>Baz: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 </div></div><div><br></div><div style>So, while there is the issue in LTO, I still think Clang could give a warning. This is a source of buffer overflow attacks...</div>
<div style><br></div><div style>While trying to define which pass was doing this, I commented out pass by pass in LTO and found that commenting some of them would produce a seg-fault in LLVM (haven't checked further, though), but I know that is one of:</div>
<div style><br></div><div style><div> PM.add(createGlobalOptimizerPass());<br></div><div> PM.add(createConstantMergePass());<br></div><div> PM.add(createDeadArgEliminationPass());<br></div><div> PM.add(createInstructionCombiningPass());<br>
</div><div><br></div><div> // Inline small functions</div><div> if (RunInliner)</div><div> PM.add(createFunctionInliningPass());</div><div><br></div><div> PM.add(createPruneEHPass()); // Remove dead EH info.</div>
<div> if (RunInliner)<br></div><div> PM.add(createGlobalOptimizerPass());</div><div> PM.add(createGlobalDCEPass()); // Remove dead functions.</div><div><br></div><div style>Then I looped over all LTO passes in the populateLTOPassManager() but adding them manually (incrementally, until I passed them all) didn't allow me to reproduce the error.</div>
<div style><br></div><div style>I'll create a bugzilla for this, and the Clang warning. If Clang folks think it's worth, they can start from there.</div><div style><br></div><div style>--renato</div></div></div><div class="gmail_extra">
<br><br><div class="gmail_quote">On 8 January 2013 16:20, Duncan Sands <span dir="ltr"><<a href="mailto:baldrick@free.fr" target="_blank">baldrick@free.fr</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Hi Renato,<div class="im"><br>
<br>
On 08/01/13 17:16, Renato Golin wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
After looking at the Livermore for a while, we found the issue that was causing<br>
LTO to produce a different result.<br>
<br>
Consider the code below [1]. setup() doesn't touch bar/baz, main() doesn't<br>
reference foo. LTO finds, correctly,<br>
</blockquote>
<br></div>
I don't think this is correct. At the LLVM IR level it is valid to write into<br>
bar and baz by accessing off the end of foo. GlobalOpt is wrong to think that<br>
an inbounds GEP into foo cannot be referencing bar/baz; the inbounds rules only<br>
say it can't access memory outside of S. So I think this is an optimizer bug.<br>
<br>
Ciao, Duncan.<div class="HOEnZb"><div class="h5"><br>
<br>
that it can remove the setup(), but the<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
result is different.<br>
<br>
The code is clearly wrong, but the compiler has no right to fix user's<br>
stupidity, even at that level. The only think I can think that would mitigate<br>
the problem would be to have a warning or out-of-bounds access when it's that<br>
obvious.<br>
<br>
Clang folks,<br>
<br>
Correct me it I'm wrong, but I humbly think this should be done in the<br>
front-end, so it's easy to print out line information without requiring debug<br>
symbols to be present. How easy would be to do that in Clang's AST?<br>
<br>
I assume it's only a matter of checking the stride against the bounds of the<br>
array, if all is knowns at compile time. That would also help against<br>
segmentation fault.<br>
<br>
It wouldn't, however, work with variable length arrays, but VLA tend to segfault<br>
more often than silently overwrite other global variables.<br>
<br>
cheers,<br>
--renato<br>
<br>
[1]<br>
#include <stdio.h><br>
<br>
struct {<br>
int foo[20];<br>
int bar[20];<br>
int baz[20];<br>
} S;<br>
<br>
void setup() {<br>
int i;<br>
// OVERWRITES ALL THREE ARRAYS<br>
for (i=0; i<60; i++)<br>
S.foo[i] = i; // ONLY REFERENCES FOO<br>
}<br>
<br>
// DOESN'T USE FOO<br>
int main() {<br>
int i;<br>
setup();<br>
printf("Bar: ");<br>
for (i=0; i<20; i++)<br>
printf("%d ", S.bar[i]);<br>
printf("\nBaz: ");<br>
for (i=0; i<20; i++)<br>
printf("%d ", S.baz[i]);<br>
puts("");<br>
<br>
return 0;<br>
}<br>
<br>
</blockquote>
<br>
</div></div></blockquote></div><br></div>