2013-10-31 8 views
6

Okay, zuerst einmal, faire Warnung, das ist ein Projekt für eine Klasse. Ich suche keine andere Hilfe als mein Speicherleck zu reparieren. Ich stelle mir vor, dass ich einige schreckliche Kodierungspraktiken über den Raum dieses C-Codes verfolgt habe. Egal, wenn ich Valgrind nach der Ursache der Speicherlecks suche, ist mir überhaupt nicht klar, welche Speicherlecks mir fehlen. Ich weiß, dass es mindestens zwei Strings gibt, die ich nicht freigebe, sondern dass ich malloc() ed, basierend auf der Größe der valgrind-Ausgabe. Da ich einen Teil des überflüssigen Codes aus dem Projekt herausgenommen habe, sind die Valgrind-Zeilennummern möglicherweise sehr schlecht, deshalb habe ich sie mit Kommentaren versehen, um Ihnen das zu erleichtern.Hausaufgaben: Ich habe irgendwo ein Speicherleck, aber ich kann es nicht finden. Irgendwelche Tipps, wie man Valgrind effektiver nutzen kann?

Ein wenig Hintergrund, ich bin die grundlegenden Funktionen eines Shell zu schreiben. Es unterstützt derzeit die folgenden:

1.Take Benutzereingabe

2.Parse der Eingabe in ein CmdIn struct

3.Execute der Befehl, vorausgesetzt, es ist nicht ein Rohr in ihr hat.

4.free den Raum von dem CmdIn ich erstellt, und von vorn beginnt bei Schritt 1 Dies ist, wo das Problem auftritt.

#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <sys/wait.h> 
#define MAX_SIZE 1024 
#define MAX_CLEN 2097152 
#define READ_END 0 
#define WRITE_END 1 
#define CHILD_STATUS 0 
struct cmdin 
{ 
    char *cmd; 
    char **args; 
    int nargs; 
    int pipeflag; 
}; 

//check if the last argument of the command passed to it is a pipe. 
//if so, return the position of the pipe, otherwise, return 0 
//if it has already found a pipe, it will return the position of that pipe 
int conpipe(struct cmdin * cmd) 
{ 
    if(!cmd->pipeflag) 
    { 
     if(!strcmp(cmd->args[cmd->nargs], "|")) 
     { 
      return cmd->nargs; 
     } 
     else 
     { 
      return 0; 
      /* PROBLEM LINE BELOW */ 
     } // line 46, where valgrind claims one of the problems exists 
    } 
    else 
    { 
     //printf("pipeflag: %d\n", cmd->pipeflag); 
     return (cmd->pipeflag); 
    } 
} 

//free the command after each runthrough 
int freeze(struct cmdin cmd) 
{ 
    int i; 
    for(i=0; i <= (cmd.nargs); i++) 
    { 
     //printf("cmd.args[%d]: %s\n",i, cmd.args[i]); 
     /* PROBLEM LINE BELOW*/ 
     free(cmd.args[i]); //this is line 62, as noted by valgrind 
    } 
    free(cmd.args); 
    free(cmd.cmd); 
    return 0; 
} 

//parse input, and add a null to the end 
struct cmdin * parse(char *cmd) 
{ 
    //allocate space for the command 
    struct cmdin *ped = malloc(sizeof(struct cmdin)); 
    //declare pipeflag, and nargs as 0 
    ped->pipeflag = 0; 
    ped->nargs = 0; 
    //allocate space for the array of strings, and for the string cmd. 
    ped->args = malloc(sizeof(char*) * MAX_SIZE); 
    ped->cmd = malloc(sizeof(char) * MAX_SIZE); 
    //scan the input, and put the first argument into the cmd string 
    sscanf(cmd, "%s %[^\n]", ped->cmd, cmd); 
    //allocate space for the next string, and then copy cmd to it. 
    ped->args[ped->nargs] = malloc(sizeof(char) * MAX_SIZE); 
    strcpy(ped->args[ped->nargs], ped->cmd); 
    ped->pipeflag = conpipe(ped); 

    /* PROBLEM LINE BELOW*/ 
    ped->nargs++;  // line 86, where valgrind claims the second leak is called? 
    ped->args[ped->nargs] = malloc(sizeof(char) * MAX_SIZE); 
    //loop that allocates space for a command, and then assigns 
    //the next arg to it. 
    while(sscanf(cmd, " %s %[^\n]", ped->args[ped->nargs], cmd) == 2) 
    { 
     ped->pipeflag = conpipe(ped); 
     ped->nargs++; 
     ped->args[ped->nargs] = malloc(sizeof(char) * MAX_SIZE); 
    } 

    strncpy(ped->args[ped->nargs], cmd, strlen(cmd)-1); 
    ped->nargs++; 
    //ped->args[ped->nargs] = malloc(sizeof(char) * MAX_SIZE); 
    ped->args[ped->nargs] = NULL; 

    return ped; 

} 

int main() 
{ 
    char cwd[MAX_CLEN]; 
    getcwd(cwd, sizeof(cwd)); 
    char input[MAX_CLEN]; 
    char *exit = "exit\n"; 
    char *cd = "cd"; 

    //Command to take input 
    printf("tosh$ "); 
    fgets(input, sizeof input, stdin);  

    while(strcmp(input, exit)) 
    { 
     //Command to parse input 
     struct cmdin *cmd; 
     cmd = parse(input); 
     //if there is not a pipeflag 
     if(!cmd->pipeflag) 
     { 
      //Change directories 
      if(!strcmp(cd, cmd->args[0])) 
      { 
       chdir(cmd->args[1]); 
       getcwd(cwd, sizeof(cwd)); 
      } 
      else if(strcmp(input, exit)) 
      { 
       //command to run input 
       int child_pid; 
       child_pid = fork(); 
       if(child_pid == 0) 
       { 
        if(strcmp(cmd->args[1],cmd->args[0])) 
        { 
         execvp(cmd->cmd, cmd->args); 
        } 
        else 
        { 
         free(cmd->args[1]); 
         cmd->args[1] = NULL; 
         cmd->nargs--; 
         execvp(cmd->cmd, cmd->args); 

        } 
       } 
       else 
       { 
        wait(&child_pid); 
       } 
      } 
      freeze(*cmd); 
      free(cmd); 
     }  
     //Command to take input 
     printf("tosh$ "); 
     fgets(input, sizeof input, stdin); 
    } 
    return 0; 
} 

Hinweis: Die Eingabe für diesen valgrind, sah wie folgt aus:

tosh$ ls -al 
tosh$ exit 

Die valgrind Heap und Leak Zusammenfassungen, sind wie folgt:

HEAP SUMMARY: 
==4901==  in use at exit: 4,096 bytes in 2 blocks 
==4901== total heap usage: 6 allocs, 4 frees, 24,600 bytes allocated 
==4901== 
==4901== 2,048 bytes in 1 blocks are definitely lost in loss record 1 of 2 
==4901== at 0x4C2B3F8: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==4901== by 0x400A48: parse (tosh.c:46) 
==4901== by 0x400C97: main (tosh.c:86) 
==4901== 
==4901== 2,048 bytes in 1 blocks are definitely lost in loss record 2 of 2 
==4901== at 0x4C2B3F8: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==4901== by 0x400BDE: parse (tosh.c:62) 
==4901== by 0x400C97: main (tosh.c:86) 
==4901== 
==4901== LEAK SUMMARY: 
==4901== definitely lost: 4,096 bytes in 2 blocks 
==4901== indirectly lost: 0 bytes in 0 blocks 
==4901==  possibly lost: 0 bytes in 0 blocks 
==4901== still reachable: 0 bytes in 0 blocks 
==4901==   suppressed: 0 bytes in 0 blocks 

UPDATE: Wie pro Antrag . Mein Makefile:

CC=gcc 
CFLAGS=-g -Wall 
TARGET=tosh 

$(TARGET): $(TARGET).c 
    $(CC) $(CFLAGS) -o $(TARGET) $(TARGET).c 

Valgrind Version: valgrind-3.7.0

gcc Version: gcc (Ubuntu/Linaro 4.7.2-2ubuntu1) 4.7.2

echo $ LD_PRELOAD:

(Diese gedruckte nichts)

+0

'Alle Haufen Blöcke befreit wurden - keine Lecks sind möglich'. Sie haben jedoch Ihren Speicher nur freigegeben, wenn '! Cmd-> pipeflag' ist und Sie eine Menge falscher Lese-/Schreibvorgänge im Speicher haben (valgrind memcheck listet sie alle auf) – keltar

+0

@keltar Ist nicht der 'LECK SUMMARY: definitiv verloren: 4096 Bytes in 2 Blöcken' Sagen, dass ich Gedächtnis verloren habe? –

+1

Ja. Aber mit dem von Ihnen bereitgestellten Code meldet er keine Lecks. Sind Sie 100% sicher, dass Sie dieselbe Version ausführen? – keltar

Antwort

4

Es ist nicht gelungen, zu reproduzieren. Aber ein paar Notizen.

  1. Verwenden Sie die verfügbaren Fehler und Warnungen.

    gcc -Wall -Wextra -pedantic … 
    
  2. Überprüfen Sie die Rückgabewerte und den Erfolg der Operationen. Dies ist zwingend erforderlich, um Bugs zu reduzieren, vor allem solche, die nur ein User Case eine Meile weiter unten aufdeckt.


if (!(foo = malloc(size))) { 
    perror("mem"); 
} 

... 


/* This line is no good: */ 
sscanf(cmd, "%s %[^\n]", ped->cmd, cmd); 
/*  |       | 
*  +----------+----------------+ 
*     | 
*     +--- Not good. UB. (Input/Output same.) 
*/ 

Sie könnte eine Routine hinzufügen zählen und Größen zu bekommen ...

i = sscanf(cmd, "%s%n %[^\n]%n", ped->cmd, &n1, cmd, &n2); 

if (i < 2) { 
    /* Debug print. */ 
    fprintf(stderr, 
      "%s:%-3d; " 
      "sscanf => %d items and %d bytes str[%d]<%s>\n", 
      __FILE__, __LINENO_, 
      i, n2, n1, ped->cmd 
    ); 
} 

usw.

3

okay, ich dachte nur, was das Problem ist. Die meisten Kommentatoren hatten Recht. Es war, dass ich valgrind auf unterschiedlichem Quellcode laufen ließ. Ich habe eine Kopie von Tosh in meinem ~/usr/bin aufbewahrt (was in meinem $ PATH ist). Ich habe vergessen, diesen Teil des Codes mit den letzten Änderungen zu aktualisieren (einschließlich derjenigen, die meine Speicherverlustprobleme behoben haben).

Als ich lief valgrind verwendete ich den folgenden Befehl aus dem Verzeichnis tosh.c tosh enthält:

$ valgrind tosh

Was ich habe laufen sollte:

$ valgrind ./tosh

Als ich gemacht Das Update für meinen Befehl, der Code lief gut ohne Speicherverluste. Danke für all deine Hilfe! Entschuldigung, es hat so lange gedauert, das herauszufinden.