2013-03-08 18 views

Odpowiedz

20

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.

+0

'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

+0

@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

14

Py_None to tak naprawdę kolejny obiekt Pythona, z wyjątkiem braku metod.

Python zlicza odniesienia do dowolnych PyObject*. Nie ma znaczenia, czy jest to łańcuch, liczba całkowita czy Brak.

Jeśli nie zwiększysz licznika odwołań, interpreter języka Python odrzuci obiekt po tym, jak jego licznik odniesień trafi na 0, myśląc, że nie ma żadnych wskaźników do obiektu. Oznacza to, że następnym razem, gdy spróbujesz coś zrobić z wartością zwracaną, będziesz podążał za wskaźnikiem do miejsca w pamięci, które nie ma gwarancji, że zatrzyma ono Py_None (błąd, dziwna wartość, błąd segmentacji itp.).

Istnieją alternatywy dla konieczności pamiętania używać Py_INCREF(Py_None):

return Py_BuildValue(""); 

lub

Py_RETURN_NONE;