[PATCH] D14350: [FunctionAttrs] Fix an iterator wraparound bug

Duncan P. N. Exon Smith via llvm-commits llvm-commits at lists.llvm.org
Wed Nov 4 16:21:03 PST 2015


Yes, most of the iplist instantiations use a `ilist_half_node`, which
somehow magically re-attaches the cut-off head of the list, spoiling the
is-a-sentinel detection.  I'm not surprised it's hard to demonstrate
this bug.

This patch LGTM once Philip is happy.

> On 2015-Nov-04, at 15:04, David Blaikie <dblaikie at gmail.com> wrote:
> 
> +Duncan, who's been mucking about with llvm's ilist issues recently
> 
> On Wed, Nov 4, 2015 at 2:37 PM, Sanjoy Das via llvm-commits <llvm-commits at lists.llvm.org> wrote:
> sanjoy created this revision.
> sanjoy added reviewers: chandlerc, reames.
> sanjoy added a subscriber: llvm-commits.
> 
> This change fixes an iterator wraparound bug in
> `determinePointerReadAttrs`.
> 
> Ideally, ++'ing off the `end()` of an iplist should result in a failed
> assert, but currently iplist seems to silently wrap to the head of the
> list on `end()++`.  This is why the bad behavior is difficult to
> demonstrate.
> 
> http://reviews.llvm.org/D14350
> 
> Files:
>   lib/Transforms/IPO/FunctionAttrs.cpp
>   test/Transforms/FunctionAttrs/out-of-bounds-iterator-bug.ll
> 
> Index: test/Transforms/FunctionAttrs/out-of-bounds-iterator-bug.ll
> ===================================================================
> --- /dev/null
> +++ test/Transforms/FunctionAttrs/out-of-bounds-iterator-bug.ll
> @@ -0,0 +1,30 @@
> +; RUN: opt -functionattrs -S < %s | FileCheck %s
> +
> +; This checks for an iterator wraparound bug in FunctionAttrs.  The previous
> +; "incorrect" behavior was inferring readonly for the %x argument in @caller.
> +; Inferring readonly for %x *is* actually correct, since @va_func is marked
> +; readonly, but FunctionAttrs was inferring readonly for the wrong reasons (and
> +; we _need_ the readonly on @va_func to trigger the problematic code path).  It
> +; is possible that in the future FunctionAttrs becomes smart enough to infer
> +; readonly for %x for the right reasons, and at that point this test will have
> +; to be marked invalid.
> +
> +declare void @llvm.va_start(i8*)
> +declare void @llvm.va_end(i8*)
> +
> +define void @va_func(i32* readonly %b, ...) readonly nounwind {
> +; CHECK-LABEL: define void @va_func(i32* nocapture readonly %b, ...)
> + entry:
> +  %valist = alloca i8
> +  call void @llvm.va_start(i8* %valist)
> +  call void @llvm.va_end(i8* %valist)
> +  %x = call i32 @caller(i32* %b)
> +  ret void
> +}
> +
> +define i32 @caller(i32* %x) {
> +; CHECK-LABEL: define i32 @caller(i32* nocapture %x)
> + entry:
> +  call void(i32*,...) @va_func(i32* null, i32 0, i32 0, i32 0, i32* %x)
> +  ret i32 42
> +}
> Index: lib/Transforms/IPO/FunctionAttrs.cpp
> ===================================================================
> --- lib/Transforms/IPO/FunctionAttrs.cpp
> +++ lib/Transforms/IPO/FunctionAttrs.cpp
> @@ -442,9 +442,11 @@
> 
>        Function::arg_iterator AI = F->arg_begin(), AE = F->arg_end();
>        CallSite::arg_iterator B = CS.arg_begin(), E = CS.arg_end();
> -      for (CallSite::arg_iterator A = B; A != E; ++A, ++AI) {
> +      bool InVarArgSection = false;
> +      for (CallSite::arg_iterator A = B; A != E; ++A) {
> +        InVarArgSection |= (AI == AE);
>          if (A->get() == V) {
> -          if (AI == AE) {
> +          if (InVarArgSection) {
>              assert(F->isVarArg() &&
>                     "More params than args in non-varargs call.");
>              return Attribute::None;
> @@ -457,6 +459,8 @@
>            if (!CS.doesNotAccessMemory(A - B))
>              IsRead = true;
>          }
> +        if (!InVarArgSection)
> +          ++AI;
>        }
>        AddUsersToWorklistIfCapturing();
>        break;
> 
> 
> 
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
> 
> 



More information about the llvm-commits mailing list