Oneill Oneill - 1 month ago 17
C Question

Why yacc have memory leak at exit?

when I execute my lex/yacc program with valgrind, it find memory leak. But I would know if it's possible to delete this memory leak. The output of valgrind is:

==10006==
==10006== HEAP SUMMARY:
==10006== in use at exit: 16,458 bytes in 3 blocks
==10006== total heap usage: 13 allocs, 10 frees, 16,684 bytes allocated
==10006==
==10006== 8 bytes in 1 blocks are still reachable in loss record 1 of 3
==10006== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10006== by 0x4028FA: yyalloc (lex.yy.c:1852)
==10006== by 0x402411: yyensure_buffer_stack (lex.yy.c:1552)
==10006== by 0x400DA9: yylex (lex.yy.c:686)
==10006== by 0x40312D: yyparse (parser.tab.c:1183)
==10006== by 0x40462F: parse (Parser.c:10)
==10006== by 0x4045EB: main (main.c:21)
==10006==
==10006== 64 bytes in 1 blocks are still reachable in loss record 2 of 3
==10006== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10006== by 0x4028FA: yyalloc (lex.yy.c:1852)
==10006== by 0x401FA5: yy_create_buffer (lex.yy.c:1387)
==10006== by 0x400DD3: yylex (lex.yy.c:688)
==10006== by 0x40312D: yyparse (parser.tab.c:1183)
==10006== by 0x40462F: parse (Parser.c:10)
==10006== by 0x4045EB: main (main.c:21)
==10006==
==10006== 16,386 bytes in 1 blocks are still reachable in loss record 3 of 3
==10006== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10006== by 0x4028FA: yyalloc (lex.yy.c:1852)
==10006== by 0x401FDC: yy_create_buffer (lex.yy.c:1396)
==10006== by 0x400DD3: yylex (lex.yy.c:688)
==10006== by 0x40312D: yyparse (parser.tab.c:1183)
==10006== by 0x40462F: parse (Parser.c:10)
==10006== by 0x4045EB: main (main.c:21)
==10006==
==10006== LEAK SUMMARY:
==10006== definitely lost: 0 bytes in 0 blocks
==10006== indirectly lost: 0 bytes in 0 blocks
==10006== possibly lost: 0 bytes in 0 blocks
==10006== still reachable: 16,458 bytes in 3 blocks
==10006== suppressed: 0 bytes in 0 blocks
==10006==
==10006== For counts of detected and suppressed errors, rerun with: -v
==10006== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)


And my lex:

Chiffre [0-9]
Lettre [a-zA-Z]
Alphanum ({Chiffre}{Lettre})+

%{

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "parser.tab.h"

%}
%%
-[a-zA-Z]+ {
yylval.
string = strdup(yytext);
return OPTION;
}

[a-zA-Z0-9_\-./]+ {
yylval.string = strdup(yytext);
return WORD;
}
"||" {
return OR;
}
"|" {
return PIPE;
}
"&&" {
return AND;
}
"&" {
return AMPERSAND;
}
";" {
return SEMICOLON;
}
"2>" {
return
ERR_GREAT;
}

">&" {
return
GREAT_AMP;
}

"2>>" {
return
ERR_GREAT_GREAT;
}
">>&" {
return
GREAT_GREAT_AMP;
}
">>" {
return
GREAT_GREAT;
}

">" {
return
GREAT;
}

"<" {
return
LESS;
}

[ \t]+ {
}

"\n" {
return 0;
}

%%


And my yacc file:

%{
#include <stdio.h>
#include "executor/CmdArg.h"
#include "executor/Command.h"
#include "print.h"
int yyerror(const char *msg) {
return fprintf(stderr, "YACC: %s\n", msg);
}
%}

%union {
int number;
char *string;
};
%token<string> WORD
%token<string> OPTION
%destructor {
free($$);
} <string>
%token<void> SEMICOLON
%token OR AND PIPE AMPERSAND GREAT GREAT_GREAT LESS ERR_GREAT ERR_GREAT_GREAT GREAT_AMP GREAT_GREAT_AMP
%error-verbose
%%

pipeline: cmd_args
background SEMICOLON
pipeline{
end_cmd(SEQUENCING_SEQUENCING);
}
|
cmd_args background
PIPE pipeline{
end_cmd(SEQUENCING_PIPE);
}
|
cmd_args background
OR pipeline{
end_cmd(SEQUENCING_OR);
}
|
cmd_args background
AND pipeline{
end_cmd(SEQUENCING_AND);
}
|
cmd_args background{
end_cmd(SEQUENCING_NOTHING);
}
|;
cmd_args: WORD list_args params io_list{
printdebug("YACC COMMMAND : %s\n", $1);
add_arg($1);
};

list_args: OPTION list_args{
printdebug ("yacc list arg plusieurs: %s\n", $1);
add_arg($1);
}|OPTION{
printdebug ("yacc list arg seul : %s\n", $1);
add_arg($1);
}|;

params: WORD params{
printdebug ("yacc param plusieurs : %s\n", $1);
add_arg($1);
}
|WORD {
printdebug ("yacc param seul: %s\n", $1);
add_arg($1);
}|;
background: AMPERSAND{
set_background();
}
|;

io_list: GREAT WORD{
set_io(GREAT,$2);
}|GREAT_GREAT WORD{
set_io(GREAT_GREAT,$2);
} LESS WORD{
set_io(LESS,$2);
}| ERR_GREAT WORD{
set_io(ERR_GREAT,$2);
}| ERR_GREAT_GREAT WORD{
set_io(ERR_GREAT_GREAT,$2);
}| GREAT_AMP WORD{
set_io(GREAT_AMP,$2);
}| GREAT_GREAT_AMP WORD{
set_io(GREAT_GREAT_AMP,$2);
}|;


%%

struct CmdArg *temp;
void set_io(enum yytokentype tokentype, char* file){

}
void set_background() {
temp->_background = 1;
}
void add_arg(char* s){
if (!temp)temp = new_cmdArg();
cmdarg_add_argument(temp,s);
free(s);
}
void end_cmd(Sequencing seq){
temp->_seq=seq;
command_add_cmdArg(temp, seq);
free_cmdArg(temp);
temp = NULL;
}


Thank you for your help.

Answer

==10006== LEAK SUMMARY:

==10006== definitely lost: 0 bytes in 0 blocks

==10006== indirectly lost: 0 bytes in 0 blocks

==10006== possibly lost: 0 bytes in 0 blocks

==10006== still reachable: 16,458 bytes in 3 blocks

==10006== suppressed: 0 bytes in 0 blocks

Not freeing still reachable memory is quite normal for most programs. Since there is still a pointer to it at exit, it's not really a leak.