2016-05-26 20 views
10

Po aktualizacji środowiska kompilacji, jeden z naszych testów dymu zepsuł się w TeamCity. Dochodzenia okazało się, że z tego samego kodu źródłowego,MSBuild v14 kompiluje semantycznie niepoprawny montaż w rzadkich okolicznościach.

  • C: \ Windows \ Microsoft.NET \ Framework \ v4.0.30319 \ MSBuild.exe wytwarza prawidłowe binarny
  • C: \ Program Files (x86) \ MSBuild \ 14.0 \ bin \ MSBuild.exe produkuje nieprawidłowe binarny

Kiedy to się dzieje

  • „params Object []” jest używane
  • tylko jedna wartość jest przekazywana, bez wyraźnie owinięty w tablicy
  • wymienione parametry są używane
  • w innej kolejności, niż w podpis metody kod

próbki do reprodukcji

static void Main(string[] args) 
{ 
    var customerId = Guid.NewGuid(); 

    // Produces buggy code when compiled with MSBuild v14 
    TestMethodWithParams(args: customerId, whatever: "foo"); 

    //All the calls below result correct behavior, regardless of the version of MSBuild, order and naming of parameters 
    TestMethodWithParams("foo", customerId); 
    TestMethodWithParams(whatever: "foo", args: customerId); 

    TestMethodWithParams(args: new object[] { customerId }, whatever: "foo"); 
    TestMethodWithParams("foo", new object[] { customerId }); 
    TestMethodWithParams(whatever: "foo", args: new object[] {customerId}); 
} 

private static void TestMethodWithParams(string whatever, params object[] args) 
{ 
    Console.WriteLine("args: '{0}'", args); 
} 

Co dokładnie dzieje

Niepoprawna wersja tylko przełyka pojedynczy parametr, wartość null jest przekazywana. Kod dekompilowana pokazuje różnicę:

w poprawnym formacie binarnym:

Guid guid = Guid.NewGuid(); 
Program.TestMethodWithParams("foo", new object[] 
{ 
    guid 
}); 

nieprawidłowym formacie binarnym:

Guid guid = Guid.NewGuid(); 
object obj; 
Program.TestMethodWithParams("foo", new object[] 
{ 
    obj // <- this is and will always be null 
}); 

Jak naprawić

Kiedy zawinęła jeden parametr w produkt tablica obiektów, problem zniknął. Inną opcją byłoby nie używanie nazwanych argumentów i/lub upewnienie się, że kolejność występowania parametrów jest taka sama w wywołaniu i podpisie.

ALE: Głównym problemem jest to, że nie możemy powrócić do starszego MSBuild (...), a sprawdzenie całego kodu (i przechodzenie przez każdy plik binarny w tłumie naszych pakietów NuGet) nie jest łatwe i skuteczne rozwiązanie. Co więcej, ten rodzaj błędu może zostać ponownie wprowadzony do kodu źródłowego w dowolnym momencie później. Najlepszym rozwiązaniem byłoby prawdopodobnie naprawienie MSBuild.

Czy ktoś doświadczył czegoś takiego? Czy to może być błąd w MSBuild? Pomysły?

+3

Prawdopodobnie chcesz zgłosić problem tutaj: https://github.com/dotnet/roslyn – jessehouwing

+0

Wygląda na to, że mogę to również zaimportować. Zgadzam się z @jessehouwing, powinieneś zgłosić problem na GitHub. – DavidG

+0

Prawdopodobnie nie jest trudno napisać analizator Roslyn, który sygnalizuje te połączenia, ponieważ konwencja wywoływania jest dość specyficzna. W ten sposób można łatwo wygenerować błąd kompilatora w swoich rozwiązaniach, aby zapobiec ich przekradnięciu się. – jessehouwing

Odpowiedz

4

Jak już wspomniałem w wydaniu GitHub, uważam, że jest to błąd, który pierwotnie został zgłoszony jako #4197 i został naprawiony w Roslyn 1.1.

2

dziękuję za wszystkie informacje i sugestie. Udostępniłeś szczegóły, które pomogły nam znaleźć ten problem. Okazało się, że instalacja "Microsoft Build Tools 2015 z Update 2" rozwiązała nasz problem.

Jeszcze raz dziękuję wszystkim. /David