[PATCH] D75542: [Sema] Prevent UB for uninitialized `IsSurrogate`

Brian Gesiak via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Tue Mar 3 10:16:54 PST 2020


modocache created this revision.
modocache added reviewers: rsmith, RKSimon, aaron.ballman, wenlei.
Herald added a project: clang.

A closed-source C++ codebase I help maintain began hitting a Clang ICE
with a stack trace that referenced
`clang::OverloadCandidate::getNumParams`:
https://gist.github.com/modocache/84eac9c519796644139471dd06ef4628

Specifically, Clang was querying `getNumParams`, the implementation of
which checks the `IsSurrogate` member:

  unsigned getNumParams() const {
    if (IsSurrogate) {
      QualType STy = Surrogate->getConversionType();
      // ...
    }
    // ...
  }

However, the `OverloadCandidate` instance had not initialized that member
with a value, triggering UB. In the case of the stack trace, `IsSurrogate`
was evaluated as if it were `true`, and the access into uninitialized
`Surrogate` caused the crash.

Every other use of `clang::OverloadCandidate` initializes `IsSurrogate`
with a value, so I do so in this patch in order to avoid triggering UB
in the case of my closed-source codebase. I believe the potential for UB
was introduced in this commit from January 9:
https://github.com/llvm/llvm-project/commit/25195541349b1d6dfc03bf7511483110bda69b29

Alternatively, I considered modifying the `clang::OverloadCandidate`
constructor to initialize `IsSurrogate` with a `false` value. I feel doing
so would be safer, but I stuck with what appears to be the convention:
initializing `OverloadCandidate` members are the site of use.

Unfortunately I don't have a small example I can share of how
`getNumParams` can be called in an invalid state. The closed-source C++
code that triggers the UB looks something like this and only occurs when
using GCC's libc++:

  class MyClass {
    std::pair<std::string, int> myPair;
    // ...
    void myMemberFunctionoFoo(std::pair<std::string, int> p) {}
    void myMemberFunctionBar() {
      std::bind(&MyClass::myMemberFunctionFoo, this, myPair);
    }
  };

I tried reverse-engineering a test for this patch by commenting out the
if statements added in the commit that I think introduced the UB,
https://github.com/llvm/llvm-project/commit/25195541349b1d6dfc03bf7511483110bda69b29.
But in fact I found that removing these if statements entirely did not
cause any tests in check-clang to fail, so I'm concerned the code may be
untested at the moment.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D75542

Files:
  clang/lib/Sema/SemaOverload.cpp


Index: clang/lib/Sema/SemaOverload.cpp
===================================================================
--- clang/lib/Sema/SemaOverload.cpp
+++ clang/lib/Sema/SemaOverload.cpp
@@ -6978,6 +6978,7 @@
     OverloadCandidate &Candidate = CandidateSet.addCandidate();
     Candidate.FoundDecl = FoundDecl;
     Candidate.Function = FunctionTemplate->getTemplatedDecl();
+    Candidate.IsSurrogate = false;
     Candidate.Viable = false;
     Candidate.FailureKind = ovl_fail_explicit;
     return;
@@ -7363,6 +7364,7 @@
     OverloadCandidate &Candidate = CandidateSet.addCandidate();
     Candidate.FoundDecl = FoundDecl;
     Candidate.Function = FunctionTemplate->getTemplatedDecl();
+    Candidate.IsSurrogate = false;
     Candidate.Viable = false;
     Candidate.FailureKind = ovl_fail_explicit;
     return;


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D75542.247949.patch
Type: text/x-patch
Size: 813 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20200303/c2191703/attachment.bin>


More information about the cfe-commits mailing list