41

I've run into a peculiar case where I get the following error when creating certain types of string:

Unexpected error writing debug information -- 'Error HRESULT E_FAIL has been returned from a call to a COM component.'

This error is not new to Stack Overflow (see this question and this question), but the problems presented have nothing to do with this one.

For me, this is happening when I create a const string of a certain length that includes a null-terminating character (\0) somewhere near the beginning.

To reproduce, first generate a string of appropriate length, e.g. using:

var s = new string('a', 3000);

Grab the resulting string at runtime (e.g. Immediate Window or by hovering over the variable and copying its value). Then, make a const out of it:

const string history = "aaaaaa...aaaaa";

Finally, put a \0 in there somewhere:

const string history = "aaaaaaaaaaaa\0aa...aaaaa";

Some things I noticed:

  • if you put the \0 near the end, the error doesn't happen.
  • Reproduced using .NET Framework 4.6.1 and 4.5
  • Doesn't happen if the string is short.
  • Edit: even more precious info available in the comments below.

Any idea why this is happening? Is it some kind of bug?

Edit: Bug filed, including info from comments. Thanks everybody.

Community
  • 1
  • 1
Gigi
  • 28,163
  • 29
  • 106
  • 188
  • Is this only under Visual Studio? I haven't managed to reproduce it when compiling from the command line. – Jon Skeet Jan 10 '16 at 14:19
  • I got this to occur in a console application using the example provided, however, prefacing the const string with the string literal '@' => `const string history = @"aaaaaaaaaaaa\0...."; compiled without issue. – Tommy Jan 10 '16 at 14:23
  • 1
    Using Notepad++ and some trial and error, it appears that the 2033rd index of the string is the magic compile vs not compile spot for this issue. This is using VS 2015 community, win10 build 11092, .net 4.5.2 or .net 4.6.1 – Tommy Jan 10 '16 at 14:33
  • sounds like a problem with visual studio since its listing debug information. – Daniel A. White Jan 10 '16 at 14:33
  • 17
    Oh it is *certainly* some sort of bug! The other hints in the error message suggest where it is -- in unmanaged code in the PDB writer. Someone probably mixed up a null-terminated string with a length-prefixed string. It's an easy mistake to make. – Eric Lippert Jan 10 '16 at 14:35
  • Report bugs at connect.microsoft.com – Hans Passant Jan 10 '16 at 14:37
  • 22
    I don't see how that makes it off-topic. It's a practical programming problem that's been encountered. The fact that it's a bug with a tool doesn't make it off-topic. Other people can still run into the same problem and come here looking for an answer. Gigi, since you've filed a bug report, consider posting an answer to that effect along with a link to your bug report. If and when you get a response, you could edit your answer to include that information as well. (Answering your own question is totally fine, and makes a good deal of sense in this case.) – Cody Gray - on strike Jan 11 '16 at 04:30
  • 1
    \0 means that the string is terminated (from c and c++ days this one is called the null terminated string to identify the end of the string). I think putting the \0 at the middle of the string confused the debugger somehow and cause the error. But i don't understand why you want to use \0 at the middle of the string or even for C#! – Hesham Jan 14 '16 at 07:56
  • 3
    @Hesham It's a rare use case but I'm doing something particular with binary strings, which include the NUL character. – Gigi Jan 14 '16 at 16:57
  • I cannot reproduce this in framework 4.5 and VS 2013 Pro. I even tried a really huge string with multiple nulls - all worked fine. –  Feb 12 '16 at 10:58
  • Going to **Project/Properties/Build/Advanced/Debug Info** and setting it to **none** makes the application compile and execute with no problem. – jsanalytics Feb 12 '16 at 15:07
  • @Gigi can you post a copy of the complete source code to Github? – Black Frog Feb 14 '16 at 18:29

2 Answers2

8

I'll noodle about this issue a little bit. This issue occurs both in VS2015 and earlier versions. So nothing directly to do with the C# compiler itself, this goes wrong in the ISymUnmanagedWriter2::DefineConstant2() implementation method. ISymUnmanagedWriter2 is a COM interface, part of the .NET infrastructure that all compilers use. And used both by Roslyn and the legacy C# compiler.

The comments in the Roslyn source code (actually dates back to the CCI project) that uses the method are illuminating enough, that there is trouble with this method was discovered before:

// EDMAURER If defining a string constant and it is too long (length limit is undocumented), this method throws
// an ArgumentException.
// (see EMITTER::EmitDebugLocalConst)

try
{
    this.symWriter.DefineConstant2(name, value, constantSignatureToken);
}
catch (ArgumentException)
{
    // writing the constant value into the PDB failed because the string value was most probably too long.
    // We will report a warning for this issue and continue writing the PDB.
    // The effect on the debug experience is that the symbol for the constant will not be shown in the local
    // window of the debugger. Nor will the user be able to bind to it in expressions in the EE.

    //The triage team has deemed this new warning undesirable. The effects are not significant. The warning
    //is showing up in the DevDiv build more often than expected. We never warned on it before and nobody cared.
    //The proposed warning is not actionable with no source location.
}
catch (Exception ex)
{
    throw new PdbWritingException(ex);
}

Swallowing exceptions, tsk, tsk. It dies on the last catch clause in your case. They did dig a little deeper to reverse-engineer the string length problem:

internal const int PdbLengthLimit = 2046; // Empirical, based on when ISymUnmanagedWriter2 methods start throwing.

Which is fairly close to where the \0 starts throwing, I got 2034. Nothing much that you or anybody else here can do about this of course. All you can reasonably do is report the bug at connect.microsoft.com. But hopefully you see the writing on the wall, the odds that it will get fixed are rather small. This is code that nobody maintains anymore, it now has 'undocumented' status and judging from other comments this goes back long before .NET. Not Ed Maurer either :)

Workaround ought to be easy enough, glue this string together at runtime.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
-1

I was able to repro the issue as coded. Then I changed the declaration to:

const string history = @"aaa\0aaa...lots and lots of aaa...aaa";

Tried again and it compiles just fine.