<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 - [llvm-profdata] Race condition in mergeInstrProfile() with NumThreads >1 causing corruption/crash"
   href="https://bugs.llvm.org/show_bug.cgi?id=43618">43618</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>[llvm-profdata] Race condition in mergeInstrProfile() with NumThreads >1 causing corruption/crash
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>new-bugs
          </td>
        </tr>

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

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

        <tr>
          <th>OS</th>
          <td>Linux
          </td>
        </tr>

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

        <tr>
          <th>Severity</th>
          <td>release blocker
          </td>
        </tr>

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

        <tr>
          <th>Component</th>
          <td>new bugs
          </td>
        </tr>

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

        <tr>
          <th>Reporter</th>
          <td>ua_llvm-bugs@binary-island.eu
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>htmldeveloper@gmail.com, llvm-bugs@lists.llvm.org
          </td>
        </tr></table>
      <p>
        <div>
        <pre>llvm-profdata.cpp - mergeInstrProfile():

  SmallVector<std::unique_ptr<WriterContext>, 4> Contexts;
  for (unsigned I = 0; I < NumThreads; ++I)
    Contexts.emplace_back(std::make_unique<WriterContext>(
        OutputSparse, ErrorLock, WriterErrorCodes));

  ....

    unsigned Ctx = 0;
    for (const auto &Input : Inputs) {
      Pool.async(loadInput, Input, Remapper, Contexts[Ctx].get());
      Ctx = (Ctx + 1) % NumThreads;
    }
    Pool.wait()


There is an error in reasoning here causing a nasty race condition: Only
NumThreads many Contexts are being created and re-used for _all_ files being
processed (which are most likely way more than NumThreads for bigger projects).
Since all Tasks are queued with a preassigned Context, Tasks with the same
assigned Context, are racing with each other.

If Task A and Task D both have the same Context, while B and C do have
different ones, and if Task A takes longer to complete than B and C, then Task
D will execute even though Task A is still using the very same Context. This
will cause corruption and crashes.

I see this while compiling Firefox where llvm-profdata crashes consistently
(as-in: almost 100% of the time on my machine).

This bug goes back when threading was introducing to llvm-profdata in July
2016, so it is present in all current major versions (trunk, 9.x, 8.x, ...).

A probable fix would be to assign each Task its own unique Context, which would
in return increase the memory usage linearly with the amount of files that need
to be processed. This would be the easiest fix to apply since it requires the
fewest changes overall.

Alternatively, schedule Tasks in batches and wait for those to finish before
scheduling new Tasks, with memory usage now being O(threads). But this would
probably be measurably slower.

I haven't provided a patch for this, since I wasn't sure what the desired fix
was because each comes with a cost.</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>