Brakujące Py_INCREF
spowoduje niepoprawne zliczanie referencji dla Py_None
, co może spowodować, że tłumacz zwolni Py_None
. Od Py_None
jest alokowany statycznie w pliku Objects/object.c
:
PyObject _Py_NoneStruct = {
_PyObject_EXTRA_INIT
1, &PyNone_Type
};
aw Include/object.h
tam jest określenie:
#define Py_None (&_Py_NoneStruct)
Więc co się stanie, jest to, że interpreter padnie z fatalnym błędem:
Fatal Python error: deallocating None
Która jest generowana przez funkcję none_dealloc
w Objects/object.c
:
/* ARGUSED */
static void
none_dealloc(PyObject* ignore)
{
/* This should never get called, but we also don't want to SEGV if
* we accidentally decref None out of existence.
*/
Py_FatalError("deallocating None");
}
Jak stwierdził tego komentarza, jeśli NoneType
nie miał swoją funkcję dealokując, by uzyskać segmentacji winy, ponieważ free
wezwanie byłyby wykonywane na stosie.
Możesz przetestować to kopiowanie przykładu w tutorial, dodając wywołanie do Py_DECREF(Py_None)
do funkcji Noddy_name
, zbuduj rozszerzenie i wykonaj pętlę wywołując tę metodę.
W ogólnym przypadku zliczania odniesienia 0
może spowodować, że program nie na wiele różnych sposobów.
W szczególności Python może ponownie wykorzystać pamięć używaną przez obiekty, które zostały zwolnione, co oznacza, że nagle każde odniesienie do obiektu może stać się odniesieniem do losowego obiektu (lub do pustej komórki pamięci), a ty widział takie rzeczy jak:
>>> None #or whatever object that was deallocated
<ARandomObjectYouNeverSawBefore object at ...>
(. To rzeczywiście happened do mnie czasem, podczas pisania rozszerzeń C Niektóre obiekty gdzie tokarskie do zapoznania buforuje tylko losowo razy z powodu braku połączeń do Py_INCREF
).
W innych sytuacjach może powstać inny rodzaj błędów lub interpreter może ulec awarii lub uszkodzeniu.
'PyNone' jest prawdopodobnie przydzielone statycznie (brak źródła Pythona na mnie spojrzeć go), więc spróbuje uwolnić statycznie przydzieloną pamięć, co byłoby szczególnie interesujące. W każdym razie nic dobrego z tego nie wynika. – Voo
@Voo też tak pomyślałem i okazuje się, że jest przydzielany statycznie (w 'object.c'), a to prowadzi do błędu krytycznego. W każdym razie moje rozumowanie było słuszne, z wyjątkiem tego, że odnosi się do bardziej ogólnego przypadku zapomnienia o wzroście ogólnego obiektu. – Bakuriu