<div dir="ltr"><div>The bugs:<br></div><div><br></div><div><a href="http://llvm.org/bugs/show_bug.cgi?id=14851">http://llvm.org/bugs/show_bug.cgi?id=14851</a><br></div><div><br></div><div><a href="http://llvm.org/bugs/show_bug.cgi?id=14852">http://llvm.org/bugs/show_bug.cgi?id=14852</a><br>
</div><div><br></div><div><br></div><div>cheers,</div><div>--renato</div><div><br></div></div><div class="gmail_extra"><br><br><div class="gmail_quote">On 8 January 2013 16:29, Renato Golin <span dir="ltr"><<a href="mailto:renato.golin@linaro.org" target="_blank">renato.golin@linaro.org</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><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>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><br></div><div>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><br></div><div><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>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><br></div><div>I'll create a bugzilla for this, and the Clang warning. If Clang folks think it's worth, they can start from there.</div><span class="HOEnZb"><font color="#888888"><div><br></div><div>--renato</div>
</font></span></div></div><div class="HOEnZb"><div class="h5"><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><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><div><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>
</div></div></blockquote></div><br></div>