Seite 2 von 2
Re: Frage zu konvertierung von ctype in Python Typ
Verfasst: Montag 11. November 2013, 15:16
von snow
Ich habe das gerade mal geändert, dass ich nach dem auslesen, den Speicherplatz mit der Methode frei mache:
Code: Alles auswählen
pointer = self.lib.tokenize(c_char_p(text))
....
self.lib.dArrayFree(pointer)
und bekomme dann folgenden Fehler:
Code: Alles auswählen
*** Error in `/usr/bin/python': double free or corruption (out): 0x0000000002e84440 ***
Dann habe ich mal das in C probiert und habe den selben Fehler bekommen:
Code: Alles auswählen
DArray *result = tokenize("$hallo wer @ist da");
.....
dArrayFree(result);
dArrayFree(result);
Bei einem AUfruf an der Funktion im C Code wird das DArray ganz normal gecleared, aber beim zweiten mal crasht es dann wie im Python Code. Weiß jemand den Grund dafür?
Re: Frage zu konvertierung von ctype in Python Typ
Verfasst: Montag 11. November 2013, 15:53
von snafu
Naja, `free()` sollte üblicherweise auch nur exakt einmal pro Zeiger aufgerufen werden. Danach kann man nicht mehr davon ausgehen, dass der Zeiger noch gültig ist und somit kracht es beim zweiten Aufruf dann entsprechend.
Du sprichst hier von "gecleared". Ich würde bei "free" im Namen einer Funktion aber erwarten, dass da mehr gemacht wird, als nur den Inhalt zu leeren. Wie gesagt: "free" meint eher, dass das gebundene Objekt komplett abgeräumt werden soll, weil man es nicht mehr benutzen muss und somit der vom Objekt genutzte Speicher wieder freigegeben weden kann.
Re: Frage zu konvertierung von ctype in Python Typ
Verfasst: Montag 11. November 2013, 17:40
von snow
Ja aber im obigen Python Code rufe ich die free Methode ja nur einmal auf und es crasht genauso wie wenn ich es 2 mal im C Code aufrufen würde. Aber ich hab im Python Code wirklich nur einmal versucht den Speicher dafür zu leeren. Deswegen die Frage : Wieso crasht der Python Code als wenn ich 2 mal free aufgerufen hätte?
Re: Frage zu konvertierung von ctype in Python Typ
Verfasst: Montag 11. November 2013, 17:46
von BlackJack
@snow: Kannst Du eingrenzen *wo* der Crash auftritt? Also vor oder nach dem Aufruf Deiner `dArrayFree()`-Funktion?
Ansonsten wäre ein minimales aber lauffähiges Beispiel praktisch, an dem man das nachvollziehen kann.
Re: Frage zu konvertierung von ctype in Python Typ
Verfasst: Montag 11. November 2013, 23:57
von snow
Der Crash tritt direkt beim Aufruf der dArrayFree Funktion auf.
Der gesamte Code ist dieser hier:
Code: Alles auswählen
class DArray(Structure):
_fields_ = [("length", c_uint),
("capacity", c_uint),
("elems", POINTER(c_char_p))]
class RaschLexer():
def __init__(self):
self.lib = CDLL(./libSnowEdit.so")
self.lib.tokenize.argtypes = [c_char_p]
self.lib.tokenize.restype = POINTER(DArray)
self.lib.dArrayFree.argtypes = [POINTER(DArray)]
def getVariables(self, text):
variables = set([])
pointer = self.lib.tokenize(c_char_p(text))
ret = pointer.contents
for i in range(ret.length):
variables.update([ret.elems[i]])
self.lib.dArrayFree(pointer)
return variables
Was vielleicht noch interessant ist, ist die C Funktion für den Free, aber ich glaube nicht dass es daran liegt, weil im C Code funktioniert sie:
Code: Alles auswählen
void dArrayFree(DArray *arr) {
if (arr != NULL) {
if (arr->elems != NULL){
uint i;
for (i = 0; i < arr->length; i++) {
free(arr->elems[i]);
}
free(arr->elems);
}
free(arr);
}
}
Re: Frage zu konvertierung von ctype in Python Typ
Verfasst: Dienstag 12. November 2013, 00:42
von BlackJack
@snow: So auf Anhieb fällt mir eigentlich nur auf, dass der Rückgabetyp von der Funktion nicht auf `None` gesetzt wird. Damit ist nicht 100%ig ausgeschlossen, dass nach der Funktion nicht ein C-``int`` vom Aufrufstapel als Rückgabewert entfernt wird, der dann dort fehlt und zu Folgefehlern führt.
Die Klasse macht übrigens keinen Sinn. Der gemeinsame Zustand sind einfach nur ein paar Funktionen die man genauso gut auf Modulebene hätte definieren können und dann halt eine Lexer-/Parsefunktion. Ich hätte das so geschrieben (natürlich ungetestet):
Code: Alles auswählen
from itertools import islice
class DArray(Structure):
_fields_ = [
('length', c_uint),
('capacity', c_uint),
('elems', POINTER(c_char_p))
]
D_ARRAY_P = POINTER(DArray)
lib_snow_edit = CDLL('./libSnowEdit.so')
_tokenize = lib_snow_edit.tokenize
_tokenize.argtypes = [c_char_p]
_tokenize.restype = D_ARRAY_P
_d_array_free = lib_snow_edit.dArrayFree
_d_array_free.argtypes = [D_ARRAY_P]
_d_array_free.restype = None
def rasch_parse(text):
d_array_p = _tokenize(text)
try:
d_array = d_array_p.contents
return set(islice(d_array, d_array.length))
finally:
_d_array_free(d_array_p)
Re: Frage zu konvertierung von ctype in Python Typ
Verfasst: Dienstag 12. November 2013, 20:45
von snow
Habs mal geändert.Aber leider hat das Hinzufügen von None als restype keinen Einfluss gehabt und es taucht immer noch der selbe Fehler auf
Re: Frage zu konvertierung von ctype in Python Typ
Verfasst: Dienstag 12. November 2013, 20:56
von jerch
@snow:
Lass Dir mal die Pointer des Structs und von elems in C, in Python und in C beim free ausgeben.
Re: Frage zu konvertierung von ctype in Python Typ
Verfasst: Dienstag 12. November 2013, 21:00
von Sirius3
@snow: erstens ist die c-Calling-Konvention dass der Aufrufer sich um die Parameter auf dem Stack kümmert und zweitens wird bei der üblichen 64-bit-Calling-Konvention gar keine Parameter mehr auf den Stack gelegt.
Memory-Leaks können sehr schwer zu finden sein. Ohne vollständigen Code kann man da kaum Tipps geben.
Daher sind Programmiersprachen, die sich darum kümmern auch so bequem
Re: Frage zu konvertierung von ctype in Python Typ
Verfasst: Dienstag 12. November 2013, 21:22
von snow
@jerch: In meinem C-Testprogramm für die C Lib :
Darray wurde erzeugt. Adresse: 0x865090
Darray elems wurde erzeugt. Adresse: 0x8650b0
Darray wurde erzeugt. Adresse: 0x865140
Darray elems wurde erzeugt. Adresse: 0x865160
Darray elems freed. Adresse: 0x8650b0
Darray freed. Adresse: 0x865090
Darray elems freed. Adresse: 0x865160
Darray freed. Adresse: 0x865140
Und im Python Code nach eingabe der ersten Variablen:
Darray wurde erzeugt. Adresse: 0x1a9a6d0
Darray elems wurde erzeugt. Adresse: 0x1d0e3b0
Darray wurde erzeugt. Adresse: 0x1d083e0
Darray elems wurde erzeugt. Adresse: 0x1d0e4a0
Darray elems freed. Adresse: 0x1d0e3b0
Darray freed. Adresse: 0x1a9a6d0
@Sirius3 aber immerhin gibt es in C/C++ ja Programme wie valgrind die einem dabei helfen diese Memeory-Leaks zu finden. Aber wär schon was, wenn es eine Sprache gibt die so bequem wie Python ist und gleichzeitig so performant wie C. \dreamoff ^^
Re: Frage zu konvertierung von ctype in Python Typ
Verfasst: Dienstag 12. November 2013, 21:29
von BlackJack
@snow: Ich würde sagen mit raten kommt man hier nicht weiter. Man bräuchte ein minimales Beispiel was jeder nachvollziehen kann, also bei sich selber auf dem Rechner kompilieren und laufen lassen kann, was das Problem aufzeigt.
Re: Frage zu konvertierung von ctype in Python Typ
Verfasst: Dienstag 12. November 2013, 21:33
von jerch
@snow:
Im Python Bsp fehlt ja was - wenn er da abgebrochen hast, wäre der "korrupte" Pointer ausm Stacktrace noch ganz hilfreich
Re: Frage zu konvertierung von ctype in Python Typ
Verfasst: Dienstag 12. November 2013, 21:35
von snow
edit: Ok Fehler ist gelöst xD Habe gerade noch eine Bedingung in die Python Methode gesetzt, dass wenn der Text leer ist, die Methode gar nicht ausgeführt werden soll und einfach ein leeres set zurück gegeben werden soll, mit dem Ziel weniger printouts zu haben. Nachdem ich gerade einfach aus Spaß den free Aufruf nochmal in die Methode gepackt habe ist das Programm auf einmal nicht mehr abgestürzt.
edit2: Nun ist auch der Grund gefunden warum es bei einem leeren String abgestürzt ist.
Code: Alles auswählen
DArray *newDArray() {
DArray *arr = (DArray*) malloc(sizeof(DArray));
arr->elems = NULL;
arr->length = 0;
arr->capacity = 0;
return arr;
}
void dArrayFree(DArray *arr) {
if (arr != NULL) {
if (arr->elems != NULL){
uint i;
for (i = 0; i < arr->length; i++) {
free(arr->elems[i]);
}
free(arr->elems);
}
free(arr);
}
}
Da ich vorher nicht in der Methode newDArray den Pointer auf NULL gesetzt habe, wurde natürlich die Adresse auf irgendwas gesetzt. Die Prüfung in der Free Methode konnte natürlich nicht greifen und wollte irgendwo im Nirvana Speicher frei machen. Ich weiß, böser Patzer
Trotzdem danke für eure Hilfe