Attention: Here be dragons

This is the latest (unstable) version of this documentation, which may document features not available in or compatible with released stable versions of Godot.

Utilizzare i sanitizer

Cosa sono i sanitizer?

I sanitizer sono strumenti di strumentazione statica che aiutano a trovare bug che i debugger tradizionali di solito non riescono a rilevare. Sono particolarmente utili se combinati con Test unitari nell'integrazione continua.

I sanitizer si possono utilizzare su Windows, macOS e Linux tramite i compilatori Clang (LLVM), GCC o Visual Studio. Alcune piattaforme potrebbero inoltre disporre dei propri sanitizer. Nei casi in cui un singolo sanitizer sia fornito da tanti diversi compilatori, è importante ricordare che il loro risultato e comportamento potrebbero differire leggermente.

Utilizzare i sanitizer su Godot

I sanitizer richiedono di ricompilare il binario. Ciò significa che non è possibile utilizzare i binari ufficiali di Godot per eseguire i sanitizer.

Quando si compila con uno qualsiasi dei sanitizer abilitati, al nome del file binario risultante sarà aggiunto il suffisso .san per distinguerlo da un file binario senza sanitizer.

Hanno un impatto sulle prestazioni poiché è necessario effettuare molte verifiche in più in fase di esecuzione. Anche l'utilizzo della memoria aumenterà. È possibile abilitare determinate combinazioni di più sanitizer in una singola build. Attenzione però all'impatto sulle prestazioni quando si utilizzano più sanitizer alla volta, poiché il file binario risultante potrebbe essere eccessivamente lento.

È possibile passare alcune opzioni ai sanitizer senza dover ricompilare il file binario attraverso variabili d'ambiente.

Sanitizer di indirizzi (ASAN)

Il sanitizer di indirizzi è generalmente il sanitizer più utilizzato. Può diagnosticare problemi come sovraccarico di buffer e accessi fuori dai limiti. Se il motore si arresta in modo anomalo con un messaggio come free(): invalid pointer, ciò è in genere dovuto a un sovraccarico di buffer. (Questo messaggio viene stampato dal runtime C, non da Godot.)

In certe situazioni (come rilevare letture di memoria non inizializzate), il sanitizer di indirizzi non è sufficiente. Bisognerebbe utilizzare invece il Sanitizer di memoria (MSAN).

È anche possibile rilevare situazioni di utilizzo dopo la restituzione specificando la variabile d'ambiente ASAN_OPTIONS=detect_stack_use_after_return=1 prima di eseguire Godot (non durante la compilazione). Ciò aumenta il sovraccarico sul runtime del sanitizer di indirizzi, quindi abilita questa funzionalità solo quando è effettivamente necessaria.

Per abilitare il sanitizer di indirizzi in una build di Godot, bisogna passare l'opzione SCons use_asan=yes durante la compilazione. L'abilitazione di ASAN generalmente rende il binario risultante circa 2× più lento.

Avvertimento

A causa di una decisione di progettazione, i sanitizer di indirizzo, memoria e thread si escludono a vicenda. Significa che è possibile utilizzare soltanto uno di questi sanitizer in un determinato binario.

Sanitizer di perdite (LSAN)

Il sanitizer di perdite può rilevare le perdite di memoria, ovvero situazioni in cui la memoria non più in uso non viene mai liberata dal programma in esecuzione. Questo può potenzialmente portare a esaurire la memoria se il programma rimane in esecuzione per abbastanza a lungo. Poiché è possibile eseguire Godot su server dedicati per mesi o addirittura anni senza essere riavviato, è importante correggere le perdite di memoria non appena avvengono.

Per abilitare il sanitizer di perdite in una build di Godot, bisogna passare l'opzione SCons use_lsan=yes durante la compilazione. L'abilitazione di LSAN comporta solo un piccolo sovraccarico sullo prestazioni, ma il programma richiederà molto più tempo per terminare, poiché il rilevamento delle perdite di memoria avviene alla chiusura del programma.

Sanitizer di memoria (MSAN)

Il sanitizer di memoria accompagna il Sanitizer di indirizzi (ASAN). A differenza del sanitizer di indirizzi, il sanitizer di memoria è in grado di rilevare letture di memoria non inizializzate.

Per abilitare il sanitizer di memoria in una build di Godot, bisogna passare l'opzione use_msan=yes a SCons durante la compilazione. L'abilitazione di MSAN generalmente rende il binario risultante circa 3× più lento.

Avvertimento

A causa di una decisione di progettazione, i sanitizer di indirizzo, memoria e thread si escludono a vicenda. Significa che è possibile utilizzare soltanto uno di questi sanitizer in un determinato binario.

Sanitizer di thread (TSAN)

Il thread sanitizer serve per individuare gli accessi concorrenti riguardo il multithreading. Un accesso concorrente avviene quando più thread tentano di modificare gli stessi dati allo stesso tempo. Poiché la pianificazione dei thread può essere ordinata in qualsiasi modo dal sistema operativo, ciò porta a comportamenti errati che avvengono solo occasionalmente (e che pertanto possono essere difficili da ritracciare). Per prevenire un accesso concorrente, è necessario aggiungere un blocco per garantire che solo un thread alla volta possa accedere ai dati condivisi.

Per abilitare il sanitizer di thread in una build di Godot, bisogna passare l'opzione use_tsan=yes a SCons durante la compilazione. L'abilitazione di TSAN generalmente rende il binario risultante 10× più lento, moltiplicando inoltre l'utilizzo della memoria per un fattore di circa 8×.

Avvertimento

A causa di una decisione di progettazione, i sanitizer di indirizzo, memoria e thread si escludono a vicenda. Significa che è possibile utilizzare soltanto uno di questi sanitizer in un determinato binario.

Nota

Su Linux, se ci si imbatte nel seguente errore:

FATAL: ThreadSanitizer: unexpected memory mapping

Potrebbe essere necessario ridurre temporaneamente l'entropia ASLR (Address Space Layout Randomization) nel sistema con:

sudo sysctl vm.mmap_rnd_bits=28

Oppure preferibilmente disabilitarla completamente con:

sudo sysctl kernel.randomize_va_space=0

E non appena finito di usare il sanitizer di thread, aumentare l'entropia ASLR con:

sudo sysctl vm.mmap_rnd_bits=32

O riabilitare l'ASLR con:

sudo sysctl kernel.randomize_va_space=2

Anche riavviando il computer lo stato dell'ASLR sarà ripristinato ai valori predefiniti.

È importante ripristinale le modifiche il prima possibile, poiché ridurre l'entropia ASLR o disabilitare completamente l'ASLR può essere un rischio di sicurezza.

Sanitizer per comportamenti indefiniti (UBSAN)

Il sanitizer per comportamenti indefiniti serve per individuare situazioni in cui il programma presenta un comportamento casuale e imprevedibile. Ciò è dovuto a codice C/C++ che è accettato dal compilatore, ma non è corretto. Anche compilare con una diversa serie di ottimizzazioni può alterare i risultati osservati del comportamento indefinito.

Per abilitare il sanitizer per comportamenti indefiniti (UBSAN) in una build di Godot, bisogna passare l'opzione use_ubsan=yes a SCons durante la compilazione. L'abilitazione di UBSAN comporta solo un piccolo sovraccarico sulle prestazioni.

Sanitizer specifici per piattaforma

Web

Quando si compila per il Web, sono disponibili 2 opzioni SCons in più per il sanitizer:

  • use_assertions=yes abilita le asserzioni di Emscripten durante l'esecuzione, che possono individuare diversi problemi.

  • use_safe_heap=yes abilita il sanitizer SAFE_HEAP di Emscripten. Offre funzionalità simili ad ASAN, ma si concentra su problematiche specifiche di WebAssembly. Non è garantita la compatibilità di SAFE_HEAP con ASAN e UBSAN nello stesso binario, quindi potrebbe essere necessario compilarlo separatamente.