<html>
    <head>
      <base href="https://bugs.llvm.org/">
    </head>
    <body><table border="1" cellspacing="0" cellpadding="8">
        <tr>
          <th>Bug ID</th>
          <td><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - clang-cl /clang: pass-through causes read-after-free with aliased options"
   href="https://bugs.llvm.org/show_bug.cgi?id=42501">42501</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>clang-cl /clang: pass-through causes read-after-free with aliased options
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>clang
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>trunk
          </td>
        </tr>

        <tr>
          <th>Hardware</th>
          <td>PC
          </td>
        </tr>

        <tr>
          <th>OS</th>
          <td>All
          </td>
        </tr>

        <tr>
          <th>Status</th>
          <td>NEW
          </td>
        </tr>

        <tr>
          <th>Severity</th>
          <td>enhancement
          </td>
        </tr>

        <tr>
          <th>Priority</th>
          <td>P
          </td>
        </tr>

        <tr>
          <th>Component</th>
          <td>Frontend
          </td>
        </tr>

        <tr>
          <th>Assignee</th>
          <td>unassignedclangbugs@nondot.org
          </td>
        </tr>

        <tr>
          <th>Reporter</th>
          <td>nicolasweber@gmx.de
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>llvm-bugs@lists.llvm.org, neeilans@live.com, richard-llvm@metafoo.co.uk
          </td>
        </tr></table>
      <p>
        <div>
        <pre>Repro:

1. Build clang with asan

2. Run `bin/clang-cl /clang:-fprofile-remapping-file /clang:adsf -c test.cc /c`
(test.cc is just an empty file)


This results in:


=================================================================
==64401==ERROR: AddressSanitizer: heap-use-after-free on address 0x603000002f50
at pc 0x000114337c03 bp 0x7ffeec1aaee0 sp 0x7ffeec1aa6a8
READ of size 25 at 0x603000002f50 thread T0
    #0 0x114337c02 in __asan_memcpy
(libclang_rt.asan_osx_dynamic.dylib:x86_64+0x40c02)
    #1 0x106eb33b1 in llvm::raw_svector_ostream::write_impl(char const*,
unsigned long) (clang-cl:x86_64+0x1034683b1)
    #2 0x106eaaafa in llvm::raw_ostream::write(char const*, unsigned long)
(clang-cl:x86_64+0x10345fafa)
    #3 0x106e5c8a0 in llvm::Twine::printOneChild(llvm::raw_ostream&,
llvm::Twine::Child, llvm::Twine::NodeKind) const (clang-cl:x86_64+0x1034118a0)
    #4 0x106e5bc12 in llvm::Twine::toVector(llvm::SmallVectorImpl<char>&) const
(clang-cl:x86_64+0x103410c12)
    #5 0x106c028dd in llvm::opt::ArgList::MakeArgString(llvm::Twine const&)
const (clang-cl:x86_64+0x1031b78dd)
    #6 0x106c0352c in llvm::opt::ArgList::GetOrMakeJoinedArgString(unsigned
int, llvm::StringRef, llvm::StringRef) const (clang-cl:x86_64+0x1031b852c)
    #7 0x106bfc77c in llvm::opt::Arg::render(llvm::opt::ArgList const&,
llvm::SmallVector<char const*, 16u>&) const (clang-cl:x86_64+0x1031b177c)
    #8 0x104996f49 in
clang::driver::tools::Clang::ConstructJob(clang::driver::Compilation&,
clang::driver::JobAction const&, clang::driver::InputInfo const&,
llvm::SmallVector<clang::driver::InputInfo, 4u> const&, llvm::opt::ArgList
const&, char const*) const (clang-cl:x86_64+0x100f4bf49)
    #9 0x104869534 in
clang::driver::Driver::BuildJobsForActionNoCache(clang::driver::Compilation&,
clang::driver::Action const*, clang::driver::ToolChain const*, llvm::StringRef,
bool, bool, char const*, std::__1::map<std::__1::pair<clang::driver::Action
const*, std::__1::basic_string<char, std::__1::char_traits<char>,
std::__1::allocator<char> > >, clang::driver::InputInfo,
std::__1::less<std::__1::pair<clang::driver::Action const*,
std::__1::basic_string<char, std::__1::char_traits<char>,
std::__1::allocator<char> > > >,
std::__1::allocator<std::__1::pair<std::__1::pair<clang::driver::Action const*,
std::__1::basic_string<char, std::__1::char_traits<char>,
std::__1::allocator<char> > > const, clang::driver::InputInfo> > >&,
clang::driver::Action::OffloadKind) const (clang-cl:x86_64+0x100e1e534)
    #10 0x10483d8a7 in
clang::driver::Driver::BuildJobs(clang::driver::Compilation&) const
(clang-cl:x86_64+0x100df28a7)
    #11 0x10481f339 in
clang::driver::Driver::BuildCompilation(llvm::ArrayRef<char const*>)
(clang-cl:x86_64+0x100dd4339)
    #12 0x103a7ad2e in main (clang-cl:x86_64+0x10002fd2e)
    #13 0x7fff7928b3d4 in start (libdyld.dylib:x86_64+0x163d4)

0x603000002f50 is located 0 bytes inside of 32-byte region
[0x603000002f50,0x603000002f70)
freed by thread T0 here:
    #0 0x114346a4d  (libclang_rt.asan_osx_dynamic.dylib:x86_64+0x4fa4d)
    #1 0x103a66323 in llvm::opt::InputArgList::~InputArgList()
(clang-cl:x86_64+0x10001b323)
    #2 0x10481beb0 in
clang::driver::Driver::BuildCompilation(llvm::ArrayRef<char const*>)
(clang-cl:x86_64+0x100dd0eb0)
    #3 0x103a7ad2e in main (clang-cl:x86_64+0x10002fd2e)
    #4 0x7fff7928b3d4 in start (libdyld.dylib:x86_64+0x163d4)

previously allocated by thread T0 here:
    #0 0x11434662d  (libclang_rt.asan_osx_dynamic.dylib:x86_64+0x4f62d)
    #1 0x106c045ac in llvm::opt::InputArgList::MakeIndex(llvm::StringRef) const
(clang-cl:x86_64+0x1031b95ac)
    #2 0x106c04b18 in
llvm::opt::InputArgList::MakeArgStringRef(llvm::StringRef) const
(clang-cl:x86_64+0x1031b9b18)
    #3 0x106c161e7 in llvm::opt::Option::accept(llvm::opt::ArgList const&,
unsigned int&, unsigned int) const (clang-cl:x86_64+0x1031cb1e7)
    #4 0x106c0f7d0 in llvm::opt::OptTable::ParseOneArg(llvm::opt::ArgList
const&, unsigned int&, unsigned int, unsigned int) const
(clang-cl:x86_64+0x1031c47d0)
    #5 0x106c1012b in llvm::opt::OptTable::ParseArgs(llvm::ArrayRef<char
const*>, unsigned int&, unsigned int&, unsigned int, unsigned int) const
(clang-cl:x86_64+0x1031c512b)
    #6 0x1047fdbde in
clang::driver::Driver::ParseArgStrings(llvm::ArrayRef<char const*>, bool,
bool&) (clang-cl:x86_64+0x100db2bde)
    #7 0x10481bb2a in
clang::driver::Driver::BuildCompilation(llvm::ArrayRef<char const*>)
(clang-cl:x86_64+0x100dd0b2a)
    #8 0x103a7ad2e in main (clang-cl:x86_64+0x10002fd2e)
    #9 0x7fff7928b3d4 in start (libdyld.dylib:x86_64+0x163d4)



This is because Option.cpp does this for aliases:

  const Option &UnaliasedOption = getUnaliasedOption();
  StringRef Spelling;
  // If the option was an alias, get the spelling from the unaliased one.
  if (getID() == UnaliasedOption.getID()) {
    /// ... unimportant ...
  } else {
    Spelling = Args.MakeArgString(Twine(UnaliasedOption.getPrefix()) +
                                  Twine(UnaliasedOption.getName()));
  }


Then, Driver.cpp does

      // Parse any pass through args using default clang processing rather
      // than clang-cl processing.
      auto CLModePassThroughOptions = llvm::make_unique<InputArgList>(
          ParseArgStrings(CLModePassThroughArgList, false, ContainsError));

      if (!ContainsError)
        for (auto *Opt : *CLModePassThroughOptions) {
          appendOneArg(Opt, nullptr);
        }


Here, the Spelling in the alias args are owned by CLModePassThroughOptions,
which soon goes out of scope -- and the ad-hoc copying logic in

  auto appendOneArg = [&Args](const Arg *Opt, const Arg *BaseArg) {
      unsigned Index = Args.MakeIndex(Opt->getSpelling());
      Arg *Copy = new llvm::opt::Arg(Opt->getOption(), Opt->getSpelling(),
                                     Index, BaseArg);
      Copy->getValues() = Opt->getValues();
      if (Opt->isClaimed())
        Copy->claim();
      Args.append(Copy);
  };


doesn't copy the Spelling storage from one ArgList to the other.</pre>
        </div>
      </p>


      <hr>
      <span>You are receiving this mail because:</span>

      <ul>
          <li>You are on the CC list for the bug.</li>
      </ul>
    </body>
</html>