[cfe-dev] LTO "bug" and Clang warnings

Renato Golin renato.golin at linaro.org
Tue Jan 8 08:29:37 PST 2013


Hi Duncan,

Ok, I found that even if main() does reference foo, setup() still gets
chopped off and the results is the unexpected:

Foo: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Bar: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Baz: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

So, while there is the issue in LTO, I still think Clang could give a
warning. This is a source of buffer overflow attacks...

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:

  PM.add(createGlobalOptimizerPass());
  PM.add(createConstantMergePass());
  PM.add(createDeadArgEliminationPass());
  PM.add(createInstructionCombiningPass());

  // Inline small functions
  if (RunInliner)
    PM.add(createFunctionInliningPass());

  PM.add(createPruneEHPass());   // Remove dead EH info.
  if (RunInliner)
    PM.add(createGlobalOptimizerPass());
  PM.add(createGlobalDCEPass()); // Remove dead functions.

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.

I'll create a bugzilla for this, and the Clang warning. If Clang folks
think it's worth, they can start from there.

--renato


On 8 January 2013 16:20, Duncan Sands <baldrick at free.fr> wrote:

> Hi Renato,
>
>
> On 08/01/13 17:16, Renato Golin wrote:
>
>> After looking at the Livermore for a while, we found the issue that was
>> causing
>> LTO to produce a different result.
>>
>> Consider the code below [1]. setup() doesn't touch bar/baz, main() doesn't
>> reference foo. LTO finds, correctly,
>>
>
> I don't think this is correct.  At the LLVM IR level it is valid to write
> into
> bar and baz by accessing off the end of foo.  GlobalOpt is wrong to think
> that
> an inbounds GEP into foo cannot be referencing bar/baz; the inbounds rules
> only
> say it can't access memory outside of S.  So I think this is an optimizer
> bug.
>
> Ciao, Duncan.
>
>
>  that it can remove the setup(), but the
>
>> result is different.
>>
>> The code is clearly wrong, but the compiler has no right to fix user's
>> stupidity, even at that level. The only think I can think that would
>> mitigate
>> the problem would be to have a warning or out-of-bounds access when it's
>> that
>> obvious.
>>
>> Clang folks,
>>
>> Correct me it I'm wrong, but I humbly think this should be done in the
>> front-end, so it's easy to print out line information without requiring
>> debug
>> symbols to be present. How easy would be to do that in Clang's AST?
>>
>> I assume it's only a matter of checking the stride against the bounds of
>> the
>> array, if all is knowns at compile time. That would also help against
>> segmentation fault.
>>
>> It wouldn't, however, work with variable length arrays, but VLA tend to
>> segfault
>> more often than silently overwrite other global variables.
>>
>> cheers,
>> --renato
>>
>> [1]
>> #include <stdio.h>
>>
>> struct {
>>    int foo[20];
>>    int bar[20];
>>    int baz[20];
>> } S;
>>
>> void setup() {
>>    int i;
>>    // OVERWRITES ALL THREE ARRAYS
>>    for (i=0; i<60; i++)
>>      S.foo[i] = i; // ONLY REFERENCES FOO
>> }
>>
>> // DOESN'T USE FOO
>> int main() {
>>    int i;
>>    setup();
>>    printf("Bar: ");
>>    for (i=0; i<20; i++)
>>      printf("%d ", S.bar[i]);
>>    printf("\nBaz: ");
>>    for (i=0; i<20; i++)
>>      printf("%d ", S.baz[i]);
>>    puts("");
>>
>>    return 0;
>> }
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20130108/1da75407/attachment.html>


More information about the cfe-dev mailing list