41 votes

C # ne compilera pas une longue chaîne const avec un \ 0 près du début

J'ai couru dans un cas particulier où j'obtiens l'erreur suivante lors de la création de certains types de chaîne:

Erreur inattendue lors de l'écriture des informations de débogage -- 'Erreur HRESULT E_FAIL a été renvoyé à partir d'un appel à un composant COM.'

Cette erreur n'en est pas à Débordement de Pile (voir à cette question, et cette question), mais les problèmes présentés n'ont rien à voir avec celui-ci.

Pour moi, ce qui se passe quand je crée un const string d'une certaine longueur qui comprend un null-caractère de terminaison (\0) quelque part près du début.

De reproduire, d'abord générer une chaîne de caractères de longueur appropriée, par exemple à l'aide de:

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

Saisir la chaîne résultante à l'exécution (par exemple Immédiate de la Fenêtre ou en passant la souris sur la variable et la copie de sa valeur). Ensuite, faire une const hors de lui:

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

Enfin, mettre un \0 quelque part:

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

Certaines choses que j'ai remarqué:

  • si vous mettez l' \0 près de la fin, l'erreur ne se produise pas.
  • Reproduit à l'aide .NET Framework 4.6.1 et 4.5
  • Ne se produit pas si la chaîne est courte.
  • Edit: d'autant plus précieuse d'informations disponibles dans les commentaires ci-dessous.

Une idée de pourquoi ce qui se passe? Est-ce un genre de bug?

Edit: Bug déposée, y compris des infos dans les commentaires. Merci tout le monde.

8voto

Hans Passant Points 475940

Je vais la nouille sur ce problème un peu. Ce problème se produit à la fois dans VS2015 et les versions antérieures. Donc, rien à faire directement avec le compilateur C# lui-même, ce qui va mal dans le ISymUnmanagedWriter2::DefineConstant2() méthode de mise en œuvre. ISymUnmanagedWriter2 est une interface COM, une partie de l' .NET de l'infrastructure que tous les compilateurs d'utilisation. Et utilisé à la fois par Roslyn et l'héritage compilateur C#.

Les commentaires dans le Roslyn code source (en fait, remonte à la CCI de projet) qui utilise la méthode sont l'éclairage suffisant, qu'il y a un problème avec cette méthode a été découvert avant:

// 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);
}

Avaler des exceptions, tsk, tsk. Il meurt sur la dernière clause catch dans votre cas. Ils ont fait creuser un peu plus à l'ingénierie inverse sur la longueur de la chaîne problème:

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

Ce qui est assez proche de l'endroit où le \0 commence à jeter, je l'ai eu en 2034. Rien de plus que vous ou quelqu'un d'autre peut faire ici sur ce bien sûr. Tout ce que vous pouvez raisonnablement faire est de signaler le bug à connect.microsoft.com. Mais j'espère vous voir l'écriture sur le mur, les chances qu'il se fixe sont plutôt petits. C'est du code que personne ne soutient plus, il a maintenant des 'sans papiers' état et à en juger par les autres commentaires, cela remonte bien avant .NET. Pas Ed Maurer soit :)

Solution de contournement devrait être assez facile, de la colle à cette chaîne au moment de l'exécution.

-1voto

Mark Snyder Points 21

J'ai pu reproduire le problème codé. Puis j'ai changé la déclaration en:

const string history = @ "aaa \ 0aaa ... beaucoup, beaucoup d'aa ... aaa";

Essayé à nouveau et il compile très bien.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X