[LLVMbugs] [Bug 18243] New: Generating unnecessary null check when casting derived pointer to virtual base class pointer

bugzilla-daemon at llvm.org bugzilla-daemon at llvm.org
Fri Dec 13 10:57:21 PST 2013


http://llvm.org/bugs/show_bug.cgi?id=18243

            Bug ID: 18243
           Summary: Generating unnecessary null check when casting derived
                    pointer to virtual base class pointer
           Product: clang
           Version: trunk
          Hardware: Macintosh
                OS: MacOS X
            Status: NEW
          Severity: enhancement
          Priority: P
         Component: LLVM Codegen
          Assignee: unassignedclangbugs at nondot.org
          Reporter: rian at alum.mit.edu
                CC: llvmbugs at cs.uiuc.edu
    Classification: Unclassified

clang version 3.5 (trunk 197014)
Target: x86_64-apple-darwin13.0.0
Thread model: posix

(clang was compiled from clean trunk)

When compiling with "clang++ -c -emit-llvm -S":

-----

class Base {
};

class Derived : public virtual Base {
};

Base *nice() {
  return new Derived();
}

-----

This generates the following LLVM bitcode for the function "nice()":

-----

; Function Attrs: ssp uwtable
define %class.Base* @_Z4nicev() #0 {
entry:
  %call = call noalias i8* @_Znwm(i64 8) #4
  %0 = bitcast i8* %call to %class.Derived*
  %1 = bitcast %class.Derived* %0 to i8*
  call void @llvm.memset.p0i8.i64(i8* %1, i8 0, i64 8, i32 8, i1 false)
  call void @_ZN7DerivedC1Ev(%class.Derived* %0) #2
  %2 = icmp eq %class.Derived* %0, null
  br i1 %2, label %cast.end, label %cast.notnull

cast.notnull:                                     ; preds = %entry
  %3 = bitcast %class.Derived* %0 to i8**
  %vtable = load i8** %3
  %vbase.offset.ptr = getelementptr i8* %vtable, i64 -24
  %4 = bitcast i8* %vbase.offset.ptr to i64*
  %vbase.offset = load i64* %4
  %5 = bitcast %class.Derived* %0 to i8*
  %add.ptr = getelementptr inbounds i8* %5, i64 %vbase.offset
  %6 = bitcast i8* %add.ptr to %class.Base*
  br label %cast.end

cast.end:                                         ; preds = %cast.notnull,
%entry
  %cast.result = phi %class.Base* [ %6, %cast.notnull ], [ null, %entry ]
  ret %class.Base* %cast.result
}

-----

This generates an unnecessary check for null against "new Derived():" "%2 =
icmp eq %class.Derived* %0, null." I can see that in general it's necessary to
check for null before casting any arbitrary derived pointer to a virtual base
class but in this case it's unnecessary since "@_Znwm" can never return null
and the constructor for "Derived" has already been called by this point.

This potential bug was caught while statically checking code for errors using
the "Stack" (http://css.csail.mit.edu/stack/) static analyzer. You can see the
corresponding bug report there: https://github.com/xiw/stack/issues/25.

When compiling on -O3 the bitcode is:

-----

; Function Attrs: ssp uwtable
define noalias %class.Base* @_Z4nicev() #0 {
entry:
  %call = tail call noalias i8* @_Znwm(i64 8) #2
  %0 = bitcast i8* %call to i32 (...)***
  store i32 (...)** bitcast (i8** getelementptr inbounds ([3 x i8*]*
@_ZTV7Derived, i64 1, i64 0) to i32 (...)**), i32 (...)*** %0, align 8, !tbaa
!1
  %vbase.offset = load i64* bitcast ([3 x i8*]* @_ZTV7Derived to i64*), align 8
  %add.ptr = getelementptr inbounds i8* %call, i64 %vbase.offset
  %1 = bitcast i8* %add.ptr to %class.Base*
  ret %class.Base* %1
}

-----

So the check is correctly optimized out here.

What exactly is the contract between Clang codegen and the LLVM optimization
passes? It seems like Clang is in the wrong here because it's generating code
that isn't assuming C++ defined behavior (checking for null pointer after
calling constructor with that pointer). There may be several other instances of
generating unnecessary code against undefined behavior in the codegen module so
that might just be how it works.

The relevant code in the codegen module lives at:
CodeGenFunction::GetAddressOfBaseClass() in lib/CodeGen/CGClass.cpp and
ShouldNullCheckClassCastValue() in lib/CodeGen/CGExprScalar.cpp.

Note: It would be nice to fix this in Clang codegen because it generates false
positives in the "Stack" static analyzer, a workaround has been committed for
this case but it seems like Clang is generating code that the user did not
write.

-- 
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20131213/60f1f63e/attachment.html>


More information about the llvm-bugs mailing list