为什么 yacc 在退出时有内存泄漏?
Why yacc have memory leak at exit?
当我用 valgrind 执行我的 lex/yacc 程序时,它发现内存泄漏。但我想知道是否有可能删除此内存泄漏。 valgrind 的输出是:
==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)
还有我的 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;
}
%%
还有我的 yacc 文件:
%{
#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", );
add_arg();
};
list_args: OPTION list_args{
printdebug ("yacc list arg plusieurs: %s\n", );
add_arg();
}|OPTION{
printdebug ("yacc list arg seul : %s\n", );
add_arg();
}|;
params: WORD params{
printdebug ("yacc param plusieurs : %s\n", );
add_arg();
}
|WORD {
printdebug ("yacc param seul: %s\n", );
add_arg();
}|;
background: AMPERSAND{
set_background();
}
|;
io_list: GREAT WORD{
set_io(GREAT,);
}|GREAT_GREAT WORD{
set_io(GREAT_GREAT,);
} LESS WORD{
set_io(LESS,);
}| ERR_GREAT WORD{
set_io(ERR_GREAT,);
}| ERR_GREAT_GREAT WORD{
set_io(ERR_GREAT_GREAT,);
}| GREAT_AMP WORD{
set_io(GREAT_AMP,);
}| GREAT_GREAT_AMP WORD{
set_io(GREAT_GREAT_AMP,);
}|;
%%
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;
}
感谢您的帮助。
==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
对于大多数程序来说,不释放仍然可用的内存是很正常的。因为在exit处还有指向它的指针,所以不是真的泄漏。
添加到@Oneill 评论中,生成的 lex 代码提供全局函数,您可以声明(使用 extern)和调用来处理这种情况。在您的特定情况下,您正在寻找函数 int yylex_destroy ( void );
。当您在代码中调用该函数时,它将清除词法分析器分配的所有剩余内存。
函数列表如下:
int yylex_destroy ( void );
int yyget_debug ( void );
void yyset_debug ( int debug_flag );
YY_EXTRA_TYPE yyget_extra ( void );
void yyset_extra ( YY_EXTRA_TYPE user_defined );
FILE *yyget_in ( void );
void yyset_in ( FILE * _in_str );
FILE *yyget_out ( void );
void yyset_out ( FILE * _out_str );
int yyget_leng ( void );
char *yyget_text ( void );
int yyget_lineno ( void );
void yyset_lineno ( int _line_number );
当我用 valgrind 执行我的 lex/yacc 程序时,它发现内存泄漏。但我想知道是否有可能删除此内存泄漏。 valgrind 的输出是:
==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)
还有我的 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;
}
%%
还有我的 yacc 文件:
%{
#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", );
add_arg();
};
list_args: OPTION list_args{
printdebug ("yacc list arg plusieurs: %s\n", );
add_arg();
}|OPTION{
printdebug ("yacc list arg seul : %s\n", );
add_arg();
}|;
params: WORD params{
printdebug ("yacc param plusieurs : %s\n", );
add_arg();
}
|WORD {
printdebug ("yacc param seul: %s\n", );
add_arg();
}|;
background: AMPERSAND{
set_background();
}
|;
io_list: GREAT WORD{
set_io(GREAT,);
}|GREAT_GREAT WORD{
set_io(GREAT_GREAT,);
} LESS WORD{
set_io(LESS,);
}| ERR_GREAT WORD{
set_io(ERR_GREAT,);
}| ERR_GREAT_GREAT WORD{
set_io(ERR_GREAT_GREAT,);
}| GREAT_AMP WORD{
set_io(GREAT_AMP,);
}| GREAT_GREAT_AMP WORD{
set_io(GREAT_GREAT_AMP,);
}|;
%%
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;
}
感谢您的帮助。
==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
对于大多数程序来说,不释放仍然可用的内存是很正常的。因为在exit处还有指向它的指针,所以不是真的泄漏。
添加到@Oneill 评论中,生成的 lex 代码提供全局函数,您可以声明(使用 extern)和调用来处理这种情况。在您的特定情况下,您正在寻找函数 int yylex_destroy ( void );
。当您在代码中调用该函数时,它将清除词法分析器分配的所有剩余内存。
函数列表如下:
int yylex_destroy ( void );
int yyget_debug ( void );
void yyset_debug ( int debug_flag );
YY_EXTRA_TYPE yyget_extra ( void );
void yyset_extra ( YY_EXTRA_TYPE user_defined );
FILE *yyget_in ( void );
void yyset_in ( FILE * _in_str );
FILE *yyget_out ( void );
void yyset_out ( FILE * _out_str );
int yyget_leng ( void );
char *yyget_text ( void );
int yyget_lineno ( void );
void yyset_lineno ( int _line_number );