<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 - LLD writes broken /src/headerblock in PDB if /streams is > 60kiB and >= 3 natvis files are used"
   href="https://bugs.llvm.org/show_bug.cgi?id=41626">41626</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>LLD writes broken /src/headerblock in PDB if /streams is > 60kiB and >= 3 natvis files are used
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>lld
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>unspecified
          </td>
        </tr>

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

        <tr>
          <th>OS</th>
          <td>Windows NT
          </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>COFF
          </td>
        </tr>

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

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

        <tr>
          <th>CC</th>
          <td>llvm-bugs@lists.llvm.org
          </td>
        </tr></table>
      <p>
        <div>
        <pre>If at least three /natvis: flags are passed to lld-link and the offsets to them
don't fit in a 16-bit uint (i.e. > 64kiB), then msvc's debugger fails to load
all the natvis files. It works fine with link.exe.


An easy way to get natvis offsets > 64kiB is to have enough source files that
their names add up to > 64kiB, since source names are stored in /names in front
of the natvis injected source names.


To repro:

1. Run this Python script to create and compile 320 empty cc files with long
names (it doesn't matter if cl or clang-cl are used as compiler):

C:\src\repro>type mksrc.py
# Generate enough files that the sum of their absolute paths is > 64kiB.
srcobjs = []
for n in map('{:04d}'.format, range(320)):
    srcobjs.append(('%s_%s.cc' % (200 * '0', n), '%s.obj' % n))
    open(srcobjs[-1][0], 'wb').write('void _%s() {}\n' % n)

# Compile all generated files.
from multiprocessing.dummy import Pool as ThreadPool
import subprocess
#CL = r'C:\src\chrome\src\third_party\llvm-build\Release+Asserts\bin\clang-cl'
CL = r'cl'
def cl(f): subprocess.check_call(CL + ' /nologo /c /Z7 ' + f[0] + ' /Fo' +
f[1])
pool = ThreadPool(8)
pool.map(cl, srcobjs)
pool.close()

C:\src\repro>python mksrc.py


2. Prepare a main.cc and 3 natvis files test.natvis test2.natvis test3.natvis
like so:


C:\src\repro>type test.natvis
<?xml version="1.0" encoding="utf-8" ?>
<AutoVisualizer
  xmlns="<a href="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">http://schemas.microsoft.com/vstudio/debugger/natvis/2010</a>">
  <Type Name="S">
    <DisplayString>It works.</DisplayString>
  </Type>
</AutoVisualizer>

C:\src\repro>type test2.natvis
<?xml version="1.0" encoding="utf-8" ?>
<AutoVisualizer
  xmlns="<a href="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">http://schemas.microsoft.com/vstudio/debugger/natvis/2010</a>">
</AutoVisualizer>

C:\src\repro>type test3.natvis
<?xml version="1.0" encoding="utf-8" ?>
<AutoVisualizer
  xmlns="<a href="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">http://schemas.microsoft.com/vstudio/debugger/natvis/2010</a>">
</AutoVisualizer>

C:\src\repro>type main.cc
struct S {};

int main() {
        S s;
        return 42 + (unsigned)&s;
}


Here test.natvis has a dummy visualizer for struct S, test2.natvis and
test3.natvis are just empty, and main.cc just has a struct S.



3. Compile main.cc and link main.obj and the 320 generated obj files:

C:\src\repro>cl /nologo /c main.cc /Fomain.obj /Z7
main.cc
main.cc(5): warning C4311: 'type cast': pointer truncation from 'S *' to
'unsigned int'
c:\src\repro\main.cc(5) : warning C4172: returning address of local variable or
temporary: s

C:\src\repro>C:\src\chrome\src\third_party\llvm-build\Release+Asserts\bin\lld-link.exe
main.obj 0*.obj /NATVIS:test.natvis /natvis:test2.natvis /natvis:test3.natvis
/debug



4. Run the binary under MSVC's debugger


C:\src\repro> devenv /debugexe main.exe

Then ctrl-o, open test.cc, add breakpoint on line 5 (the return), and hit F5.
The visualizer won't work. If `/natvis:test3.natvis` is removed from the link
command or link.exe is used for linking, it will work (you'll see the string
"It works." in the "Autos" window in MSVC's debugger.)


This is reduced from
<a href="https://bugs.chromium.org/p/chromium/issues/detail?id=947911#c47">https://bugs.chromium.org/p/chromium/issues/detail?id=947911#c47</a>


Almost all of the credit for finding the repro go to
<a href="mailto:thomasanderson@chromium.org">thomasanderson@chromium.org</a>, who discovered both the >64kiB requirement and the
<span class="quote">>=3 natvis files requirement. I wrote the py script and reduced the reduced</span >
repro a bit more.



thomasanderson also says that comparing to link.exe's pdb, the hash codes
produced by lld-link are differenct. Since it's fine with smaller offsets,
chances are that the offsets aren't hashed quite right.





The natvis code was added in <a href="https://reviews.llvm.org/rL328363">https://reviews.llvm.org/rL328363</a> (reviewed at
<a href="https://reviews.llvm.org/D44328">https://reviews.llvm.org/D44328</a>)</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>