2012-11-17 11 views
6

sono abbastanza disperata su un errore non riesco a superare.Perché malloc restituisce NULL con molta memoria e sempre nello stesso punto?

Per la mia classe di programmazione C all'università, ho dovuto implementare un parser per flussi di input GML (Graph Modeling Language).

In caso di successo, il parser restituisce un tipo di dati astratto al chiamante, che è una matrice di adiacenza come rappresentazione del grafico.

Ok, il parser funziona in modo impeccabile, non ci sarebbe alcun problema a ridurmi alla disperazione negli ultimi giorni. Nel parser, c'è una chiamata di funzione che a sua volta chiama malloc. malloc viene chiamato abbastanza spesso durante lo scanner che fornisce il simbolo per simbolo al parser. Ma i blocchi di malloc'd mem vengono SEMPRE liberati chiamando free() prima di lasciare la routine dello scanner.

Ma c'è una chiamata di funzione fatale piuttosto profonda all'interno del parser, che, a sua volta, chiama una funzione che usa malloc per riservare 12 byte di memoria (tre proprietà integer) per il salvataggio di una struttura. La struttura è necessaria per memorizzare le informazioni su un singolo bordo all'interno del grafico (nodo di origine, nodo di destinazione, peso).

Questa chiamata viene effettuata due volte. la prima volta, tutto va bene. Quindi, poiché possono verificarsi da 1 a n fronti in base alla sintassi gml, il codice entra in un ciclo while, in cui lo stesso puntatore viene assegnato con un puntatore a una nuova Edge Struct, a condizione che nel flusso di input siano presenti bordi. Il primo richiamo della routine di riconoscimento Edge all'interno del ciclo, che è il secondo in totale (il primo avviene prima di entrare nel ciclo, vedi m.a.), fallisce costantemente con Malloc che restituisce NULL.

Semplicemente non ho idea del perché.

Non si tratta di un problema di mancanza di memoria, perché quando io malloc 1000 byte nella funzione main() di quel programma, solo per divertimento, funziona correttamente.

Uso Code :: Blocks e DevCPP come IDE. In entrambi, il programma incontra lo stesso problema.

Here's mio principale routine di analisi:

DirectedGraph Graph(char* sourceString, int*currentPosition){ 

int sym; 
int restartPosition = 0; 
int* backupPosition; 
char* backupString; 
int nodeCount = 0; 

int currentSrc = -1; 
int currentTgt = -1; 
int currentWgt = -1; 
EdgeDescription e; 
DirectedGraph correctMatrix; 
MatrixStruct* errorMatrix = NULL; 

/*begin parsing*/ 
bool isGraphHeader = GraphHdr(sourceString, currentPosition); 

if(isGraphHeader == true){ 

    bool isNode = Node(sourceString, currentPosition); 

    if(isNode == true){ 

    while(isNode == true){ 

     nodeCount++; 
     restartPosition = *currentPosition; 
     isNode = Node(sourceString, currentPosition); 

    } 

    *currentPosition = restartPosition; 

    /*now get edge information (from-to-weight)*/ 
    /*as we have already read the next symbol, we have to reset*/ 
    /*our read position by one symbol backwards*/ 
    e = Edge(sourceString, &restartPosition); /*<======== HERE I CALL THE FATAL ROUTINE FOR THE FIRST TIME - EVERYTHING´s JUST FINE, PROGRAM PROCEEDS*/ 
    restartPosition = 0; 

    /*just for clearer coding in if statement*/ 
    currentSrc = e->source; 
    currentTgt = e->target; 
    currentWgt = e->weight; 
    destroyEdge(e); 

    if(currentSrc != -1 && currentTgt != -1 && currentWgt != -1){ 

     /*initialize matrix with counted number of nodes*/ 
     correctMatrix = CreateNewGraph(nodeCount); 

     /*the edge is inserted only when it lies within the boundaries*/ 
     /*of our graph. but we do not interrupt the whole processing, we just skip it.*/ 
     while(currentSrc != -1 && currentTgt != -1 && currentWgt != -1){ 

      if(currentSrc <= nodeCount && currentTgt <= nodeCount){ 

       InsertEdge(correctMatrix, currentSrc, currentTgt, currentWgt); 
       restartPosition = *currentPosition; 
      } 

      e = Edge(sourceString, currentPosition); /* <============== THIS IS THE CALL THAT FAILS*/ 
      currentSrc = e->source; 
      currentTgt = e->target; 
      currentWgt = e->weight; 

     } 

     /*as we have read over the next symbol in the loop, reset the position to read*/ 
     *currentPosition = *currentPosition - 1; 
     sym = GetNextSymbol(sourceString,currentPosition); 

     if(sym == rightBrace){ 

      sym = GetNextSymbol(sourceString, currentPosition); 

      if(sym == eot){ 

       return correctMatrix; 
      } 
      else{ 
       return errorMatrix; 
      } 
     } 
     else{ 
      return errorMatrix; 
     } 
    } 
    else{ 
     return errorMatrix; 
    } 
    } 
    else{ 
    return errorMatrix; 
    } 
} 
else{ 
    return errorMatrix; 
} 

}

Qui il GetNextSymbol (scanner, che fornisce i simboli al parser):

/** 
* DOCUMENTATION 
* ============================ 
* This is the main scanning function 
* which is used by the parser to recognize 
* terminal symbols and valid literals. 
* 
* RETURNS: the enum code for the recognized symbol. 
* or an error code, when invalid symbol encountered. 
*/ 

int GetNextSymbol(char* sourceString, int* currentPosition){ 


    int symbolCode; 
    int loopCounter = 0; 
    char* currentIdentifier = (char*)malloc(10); 
    char* currentNumber = (char*)malloc(10); 
    int identifierPosition = 0; 
    int numberPos = 0; 
    int numericVal = 0; 
    char currentChar; 

    currentChar = getNextChar(sourceString, currentPosition); 

    /*skip all blanks, empty chars, 
    linefeeds, carriage returns*/ 
    while(currentChar == ' ' 
     || currentChar == 11 
     || currentChar == 10 
     || currentChar == 13 
     || currentChar == '\t') 
    { 
     currentChar = getNextChar(sourceString, currentPosition); 
    } 

    /*=====================================*/ 
    /*Section 1: scan for terminal symbols */ 
    /*====================================*/ 

    if(currentChar == '['){ 
     symbolCode = leftBrace; 
    } 
    else if(currentChar == ']'){ 
     symbolCode = rightBrace; 
    } 

    /*=====================================*/ 
    /*Section 2: scan for valid literals */ 
    /*====================================*/ 

    else if(isdigit(currentChar)){ 

     /*here we calculate the numeric value of a number expression*/ 
     /*when calculated, we assign the numeric value to the symCode variable*/ 
     /*this works out because the values for a real symbol are always negative*/ 
     symbolCode = digit; 
     while(isdigit(currentChar)){ 

     currentNumber[numberPos] = currentChar; 
     currentChar = getNextChar(sourceString, currentPosition); 
     loopCounter++; 
     numberPos++; 
     } 

     currentNumber[numberPos] = '\0'; 
     numericVal = atoi(currentNumber); 
     symbolCode = numericVal; 

     /*when identifier or braces follow number without space: reset currentPos*/ 
     /*to the position of the previous char*/ 
     if(isalpha(currentChar)){ 
     *currentPosition = *currentPosition - loopCounter; 
     } 
     else if(currentChar == ']'){ 
     *currentPosition = *currentPosition - loopCounter; 
     } 
     else if(currentChar == '['){ 
     *currentPosition = *currentPosition - loopCounter; 
     } 

    } 
    else if(isalpha(currentChar)){ 

     while(isalpha(currentChar)){ 

     currentIdentifier[identifierPosition] = currentChar; 
     currentChar = getNextChar(sourceString, currentPosition); 
     loopCounter++; 
     identifierPosition++; 
     } 

     /*check wether we have found a valid identifying label*/ 
     /*and deallocate the reserved mem space*/ 
     currentIdentifier[identifierPosition] = '\0'; 
     symbolCode = recognizeIdentifier(currentIdentifier); 

     /*when number or braces follow identifier without space: reset currentPos*/ 
     /*to the position of the previous char*/ 
     if(isdigit(currentChar)){ 
     *currentPosition = *currentPosition - 1; 
     } 
     else if(currentChar == ']'){ 
     *currentPosition = *currentPosition - 1; 
     } 
     else if(currentChar == '['){ 
     *currentPosition = *currentPosition - 1; 
     } 

    } 
    else if(currentChar=='\0'){ 

     symbolCode = eot; 
    } 
    /*neither terminal symbol nor end of text found on current position --> illegal symbol*/ 
    else{ 
     symbolCode = error; 
    } 

    free(currentIdentifier); 
    free(currentNumber); 
    return symbolCode; 

} 

e ora il chiamata fatale nella routine di riconoscimento "Bordo". In primo luogo, l'intestazione per la struct

#ifndef GML_EDGE_STRUCT_H_INCLUDED 
#define GML_EDGE_STRUCT_H_INCLUDED 


typedef struct EdgeStruct* EdgeObj; 

typedef struct EdgeStruct { 

    int source; 
    int target; 
    int weight; 

} EdgeStruct; 

typedef EdgeObj EdgeDescription; 

EdgeDescription createNewEdge(int src, int tgt, int wgt); 
void destroyEdge(EdgeObj); 

#endif // GML_EDGE_STRUCT_H_INCLUDED 

L'implementazione

#include "GML_EDGE_STRUCT.h" 
#include <stdio.h> 
#include <stdlib.h> 
EdgeDescription createNewEdge(int source, int target, int weight){ 

    EdgeDescription e; 
    int bytesRequested = sizeof(EdgeStruct); 

    e = malloc(bytesRequested); 
    e->source = source; 
    e->target = target; 
    e->weight = weight; 
    return e; 
} 

Lo so, thats praticamente codice;) solo per mostrare, che tutto ciò che può essere liberato, ho liberato.

Ho cercato su Google il mio problema negli ultimi due giorni, ovviamente anche qui allo stack overflow, e ci sono centinaia di siti, postings et cetera riguardanti malloc che restituiscono null. Dicono tutti fondamentalmente la stessa cosa: non abbastanza memoria (che è, lascia chiamarla improbabile), o heap frammentato, quindi non ci sono mem chunk di dimensioni sufficienti disponibili.

ma: tutto quello che richiedo sono 12 (in parole: dodici) byte per memorizzare tre proprietà int. che sembra essere troppo.

Ho superato alcuni limiti interni di cui non sono a conoscenza?

L'aiuto sarebbe molto apprezzato.

Grazie in anticipo Roland

EDIT 2012/11/24:

grazie per le vostre risposte. ma. il problema deve essere di natura più basilare.

perché: quando ho testato le altre parti del mio programma (file I/O) ecc. Che sono molto meno complesse del parser e fanno una sola chiamata in profondità rispetto al main(), non posso neanche malloc. Il file che ho letto ha all'incirca 140 byte. Anche quando provo la parte I/O isolata da tutte le altre parti, anche quando li esternalizzo in un progetto diverso, non ottengo memoria dal sistema. senza significato. Ho riavviato il computer, tutto. assolutamente. no. modificare.

qualche idea? nel frattempo ho messo troppe ore in questo progetto, la maggior parte delle quali sta rintracciando quegli errori di memoria fottuti ...: - (((

+7

Sei sicuro che il problema riguardi il malloc che restituisce NULL? Questo è molto raro, invece potrebbe accadere che raddoppi un puntatore. Prova ad affermare che malloc non restituisce mai NULL. –

+7

Hai provato Valgrind? –

risposta

1

Non posso dire molto, solo un'osservazione. in GetNextSymbol(), non vedo alcuna restrizione sul numero di cifre leggere, quindi non c'è la possibilità di un buffer overflow. lo stesso vale per la lettura di un identificatore.

un altro in Graph(), la mancanza di Edge(sourceString, currentPosition) chiamata è in una while loop e il risultato non viene mai liberato, AFAICS

3

Se si sospetta che l'applicazione utilizzi troppa memoria o frammenta tutta la memoria disponibile, allora è possibile controllare l'utilizzo della memoria dall'applicazione durante l'esecuzione. Se mangia tutta la memoria di sistema, malloc restituisce NULL a causa di ciò.

Se quanto sopra non è il tuo caso, vorrei controllare la tua applicazione per il danneggiamento dell'heap. Di solito quando si sovrascrivono strutture di heap accadono cose molto brutte. In modalità debug il compilatore aggiunge alcuni controlli extra e zone rosse per il rilevamento della corruzione dell'heap. Nelle modalità di rilascio, le strutture di heap di solito portano ad una violazione di accesso. Posso immaginare che in casi molto rari le strutture dell'heap possano essere danneggiate e il danno possa essere interpretato come fuori dallo spazio in modo che NULL venga restituito da malloc.

In un modo o nell'altro utilizzerei il debugger di memoria. Valgrind mi ha salvato molte volte, ma potrebbe non essere disponibile nel tuo ambiente. Ci sono molti argomenti qui su StackOverflow sui debugger di memoria.

Problemi correlati