Info:

twitter

Ultimi commenti: Comment feed

Tags:

Sponsor:

Archivio 2018:

Mag Feb Gen

Archivio 2017:

Dic Nov Ott Mag Apr Mar Feb Gen

Archivio 2016:

Dic Nov Ott Ago Mag Mar Feb Gen

Archivio 2015:

Nov Ott Set Mar Gen

Archivio 2014:

Dic Nov Ott Set Lug Giu Mag Apr Gen

Archivio 2013:

Dic Nov Set Ago Lug Giu Mag Apr Feb Gen

Archivio 2012:

Dic Nov Ott Set Ago Giu Mag Apr Mar Feb Gen

Archivio 2011:

Dic Nov Ott Set Ago Lug Giu Mag Apr Mar Feb Gen

Archivio 2010:

Dic Nov Ott Set Ago Lug Giu Mag Apr Mar Feb Gen

Archivio 2009:

Dic Nov Ott Set Ago Lug Giu Mag Apr Mar Feb Gen

Archivio 2008:

Dic Nov Ott Set Ago Lug Giu Mag Apr Mar Feb Gen

Archivio 2007:

Dic Nov Ott Set Ago Lug Giu Mag Apr Mar Feb Gen

Archivio 2006:

Dic Nov Ott Set Ago Lug Giu Mag Apr Mar Feb Gen

L’Heisenbug perfetto

Pochi giorni fa mi sono riscontrato nel cosidetto Heisenbug perfetto. Di solito gli Heisenbug hanno a che fare con il multi-threading circostanza per cui aggiungere qualche breakpoint al codice sfasa il timing dell’applicazione e per tanto potrebbe causare la scomparsa di un baco sotto osservazione. Nel mio caso non c’era nessun multithreading, ma bastava semplicemente “osservare” il comportamento dell’oggetto misterioso per deviarne il flusso di esecuzione. Ridotto al minimo l’Heisenbug è descritto qui sotto:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace Heisenbug

{

    class MyClass

    {

        bool here;

        public override string ToString()

        {

            string result = here.ToString();

            this.here = true;

            return result;

        }

 

        public MyClass()

        {

            this.here = false;

            // put a breakpoint on the following line

            // and add 'this' to the watch window and

            // then execute

            Console.WriteLine(this.ToString());

        }

    }

 

    class Program

    {

        static void Main(string[] args)

        {

            MyClass c = new MyClass();

            Console.WriteLine(c.ToString());

        }

    }

}

Normalmente l’applicazione scrive False-True sulla console. Se invece si aggiunge un breakpoint nella riga del costruttore indicata e si osserva appunto l’oggetto appena instanziato il risultato diventa True-True. La cosa non è stata banale da individuare perché il tutto era offuscato da qualche altro centinaio di righe di codice e parlandone con il collega pazzo con la capigliatura più caotica della mia ne è nata una questione filosofica: ma il debugger può permettersi davvero di invocare metodi mentre un oggetto è ancora in costruzione? Girerò la domanda a quelli del team di Visual Studio per sapere se il comportamento è documentato (prescritto) da qualche parte.

-quack

Update:

image

Dalla regia mi suggeriscono che questo comportamento può essere disabilitato ed il valore di default in effetti makes sense.

VS – Developer 1-0 e palla al centro

Potrebbero interessarti anche:
Commenti (20):
1. CSharpBeginner
mercoledì 16 dicembre 2009 alle 11:15 PM - chrome 3.0.195.33 Windows 7
   
   
2. Paperino
mercoledì 16 dicembre 2009 alle 11:34 PM - firefox 3.5.6 Windows 7
   

Nope, non ci siamo. Il problema non è il costruttore che invoca il metodo virtuale (si ottiene un risultato simile se si toglie il Console.WriteLine dal costruttore); il problema è che lo fa il debugger e non (?) dovrebbe.

   
3. Giuseppe
giovedì 17 dicembre 2009 alle 12:03 AM - IE 6.0 Windows CE/Mobile/Embedded
   

ma il peoblema e' la costruzione del bool... che viene kiamata all'atto dell'allocazione dell'oggetto PRIMA del costruttore vero e proprio.. in un ipotetisimil c++ qst cosa tornava <valore-a-caso> true

   
4. CSharpBeginner
giovedì 17 dicembre 2009 alle 12:05 AM - chrome 3.0.195.33 Windows 7
   

Forse il debugger invoca ToString() per dare il risultato in pasto a qualche visualizer...?

 

   
5. Paperino
giovedì 17 dicembre 2009 alle 12:08 AM - firefox 3.5.6 Windows 7
   

Yes, indeed. Nel momento in cui metti 'this' nella lista delle variabili in watch, viene invocato ToString(). Ora anche se il metodo non fosse virtuale si sarebbe di fronte al fatto che si sta invocando un metodo prima che l'oggetto sia completamente costruito e questo potrebbe falsare alcune assunzione fatte da chi ha scritto quella classe. Morale della favola: cambiare lo stato dell'oggetto durante ToString() è la via più veloce per sbattere la testa contro un muro.

   
6. CSharpBeginner
giovedì 17 dicembre 2009 alle 12:17 AM - chrome 3.0.195.33 Windows 7
   

@Giuseppe: cosa vuol dire "ipotesi simil c++"?

In C++ ritorna sempre false-true su console:

c:\tmp>type test.cpp

#include <iostream>

#include <string>

 

using namespace std;

 

 

class MyClass

{

public:

    MyClass()

      : here(false)

    {

        cout << ToString() << endl;

    }

 

    string ToString()

    {

        string result = here ? "true" : "false";

        here = true;

        return result;

    }

 

private:

    bool here;

};

 

 

int main()

{

    MyClass c;

    cout << c.ToString() << endl;

 

    return 0;

}

 

c:\tmp>cl /EHsc /nologo /W4 /MT /O2 /GL test.cpp

test.cpp

Generating code

Finished generating code

 

c:\tmp>test.exe

false

true

 

c:\tmp>

   
7. CSharpBeginner
giovedì 17 dicembre 2009 alle 12:22 AM - chrome 3.0.195.33 Windows 7
   

@Paperino:

> Morale della favola: cambiare lo stato dell'oggetto durante ToString() è la via più veloce per sbattere la testa contro un muro.

 

Altro morale della favola: thank you C# per aver rimosso la const-correctness

In C++ si sarebbe potuto definire ToString() metodo 'const' (quindi lo stato interno dell'oggetto non si sarebbe potuto modificare).

 

   
8. Paperino
giovedì 17 dicembre 2009 alle 12:48 AM - firefox 3.5.6 Windows 7
   

In C++ si sarebbe potuto definire ToString() metodo 'const'

Non so se sarebbe stata una buona idea. Alcuni oggetti potrebbero essere molto costosi da convertire in stringa e per questo da qualche parte l'oggetto convertito torna utile (come lo era nel pezzo di codice originale). Ripeto, l'origine del male sta nel fatto che il debugger si prende la libertà di invocare metodi su un oggetto durante la sua costruzione: non so se sia giusto o sbagliato.

   
9. il nonno
giovedì 17 dicembre 2009 alle 10:02 AM - IE 8.0 Windows 7
   

Appunto, e' una questione strettamente legata al debugger non una "caratteristica" del linguaggio. CSharpBeginner, mai sentito parlare de "la potenza e' niente senza controllo"?

   
10. Pinco
giovedì 17 dicembre 2009 alle 11:09 AM - firefox 3.5.6 Windows 7
   

"VS – Developer 1-0 e palla al centro"

 

   
11. 0verture
giovedì 17 dicembre 2009 alle 11:56 AM - firefox 3.5.6 Windows 7
   

Ripeto, l'origine del male sta nel fatto che il debugger si prende la libertà di invocare metodi su un oggetto durante la sua costruzione:

Se devo dare un voto alla pizza, non assaggio la farina da sola o si ?

   
12. MicioDue
giovedì 17 dicembre 2009 alle 1:36 PM - IE 8.0 Windows Vista
   

Vuoi divertirti a sperimentare un altro caso misterioso, anche se non si tratta di un Heisenbug? Guarda questo breve thread:

http://forums.asp.net/t/1503486.aspx

Una query Linq che arriva felicemente in fondo se eseguita in console ma va malamente in crash in ambiente ASP.NET, a livello talmente profondo che non solleva neanche un'eccezione trappabile! Anche per il tedesco che mi ha gentilmente risposto è difficile crederlo, eppure è perfettamente riproducibile dal codice riportato. Sono cose inquietanti...

   
13. CSharpBeginner
giovedì 17 dicembre 2009 alle 2:43 PM - chrome 3.0.195.33 Windows 7
   

@Paperino:

Alcuni oggetti potrebbero essere molto costosi da convertire in stringa e per questo da qualche parte l'oggetto convertito torna utile (come lo era nel pezzo di codice originale).

Paperino: Good point!

 

 

 

   
14. CSharpBeginner
giovedì 17 dicembre 2009 alle 2:47 PM - chrome 3.0.195.33 Windows 7
   

@il nonno

mai sentito parlare de "la potenza e' niente senza controllo"? 

 

il nonno: mai sentito parlare di "use the right tool for the job"?

Il browser che usi e l'OS che usi sono scritti in C++.

Credo che entrambi i linguaggi (C++ e C#) abbiamo pro e contro, e abbiano domini specifici di utilizzo in cui ciascuno può essere preferito all'altro.

Bye

 

   
15. il nonno
giovedì 17 dicembre 2009 alle 3:27 PM - IE 8.0 Windows 7
   

mai sentito parlare di "use the right tool for the job"?

Per la serie "cavoli a merenda"... cambiar discorso non serve a "difendere" la tua precedente infelice affermazione.

   
16. Paperino
giovedì 17 dicembre 2009 alle 7:02 PM - firefox 3.5.6 Windows 7
   

@MicioDue:

hai provato a debuggare il codice .Net stesso?

   
17. EnricoC.
giovedì 17 dicembre 2009 alle 7:30 PM - firefox 3.5.6 Windows 7
   

Papero bell'esempio per chi proviene da C++ e Java come me. Proponili piu' spesso! In questo caso il comportamento del debugger e' discutibile ma se si puo' settare su VS il discorso si spegne subito

   
18. EnricoC.
giovedì 17 dicembre 2009 alle 7:43 PM - firefox 3.5.6 Windows 7
   

LoL subito "non ci credevo" cosi' ho provato su VS 2010 ed effettivamente e' cosi'

   
19. EnricoC.
giovedì 17 dicembre 2009 alle 7:50 PM - firefox 3.5.6 Windows 7
   

E confermo che ovviamente lo fa anche con la nuova feature del "pin a watch" di VS2010, ovvero anche senza usare la watch window. EVIL DEBUGGER

   
20. MicioDue
venerdì 18 dicembre 2009 alle 12:14 AM - IE 8.0 Windows Vista
   

@Paperino:

No, principalmente per motivi di tempo. Comprenderai però la perplessità di osservare un comportamento differente del Framework (mi sembra che la cosa proprio lì si riconduca) fra l'ambiente Windows nativo e quello degli applicativi web, a parità di codice. Forse sarebbe più corretto pensare che il primo lasci correre un certo tipo di incongruenza nel parsing XML mentre l'altro vi sia fin troppo allergico!

   
Lascia un commento:
Commento: (clicca su questo link per gli smiley supportati; regole di ingaggio per i commenti)
(opzionale, per il Gravatar)