[llvm-bugs] [Bug 42501] New: clang-cl /clang: pass-through causes read-after-free with aliased options

via llvm-bugs llvm-bugs at lists.llvm.org
Wed Jul 3 11:39:27 PDT 2019


https://bugs.llvm.org/show_bug.cgi?id=42501

            Bug ID: 42501
           Summary: clang-cl /clang: pass-through causes read-after-free
                    with aliased options
           Product: clang
           Version: trunk
          Hardware: PC
                OS: All
            Status: NEW
          Severity: enhancement
          Priority: P
         Component: Frontend
          Assignee: unassignedclangbugs at nondot.org
          Reporter: nicolasweber at gmx.de
                CC: llvm-bugs at lists.llvm.org, neeilans at live.com,
                    richard-llvm at metafoo.co.uk

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.

-- 
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/20190703/44418ec5/attachment-0001.html>


More information about the llvm-bugs mailing list