При попытке использовать getopt
несколько раз я получаю ошибку в valgrind Invalid read of size 1
, Ошибка возникает только при выполнении чего-то вроде этого:
ls -a -b
ls -a -b
Поэтому я предполагаю, что проблема заключается в повторном использовании getopt
функции.
command.h
class Command {
protected:
// for use in getopt
int c = 0;
// name of command
char* name;
public:
Command(const char* nname) : name((char*)nname) { }
virtual ~Command() { };
virtual void process_args(int argc, char* argv[]) = 0;
virtual char* get_name() const {
return name;
}
};
ls.h это просто этот завернутый в класс:
class ls : public Command {
public:
ls() : Command("ls") { }
~ls() { }
void process_args(int input_argc, char* input_argv[]) {
int verbose_flag = 0;
struct option long_options[] =
{
/* These options set a flag. */
{"verbose", no_argument, &verbose_flag, 1},
{"brief", no_argument, &verbose_flag, 0},
/* These options don't set a flag.
We distinguish them by their indices. */
{"add", no_argument, 0, 'a'},
{"append", no_argument, 0, 'b'},
{"delete", required_argument, 0, 'd'},
{"create", required_argument, 0, 'c'},
{"file", required_argument, 0, 'f'},
{0, 0, 0, 0}
};
while (1) {
// removed static and moved struct outside
// everything else is the same
}
}
};
main.cpp
std::vector<std::unique_ptr<Command>> commands;
commands.push_back(std::unique_ptr<Command>(new ls()));
commands.push_back(std::unique_ptr<Command>(new shibe()));
while (true) {
std::string input;
std::getline(std::cin, input);
if (input == "quit")
break;
std::istringstream iss(input);
std::vector<std::string> args;
std::copy(std::istream_iterator<std::string>(iss), std::istream_iterator<std::string>(), std::back_inserter(args));
int input_argc = args.size();
char* input_argv[input_argc];
for (int i = 0; i < args.size(); i++) {
input_argv[i] = (char*)args[i].c_str();
}
for (int i = 0; i < commands.size(); i++) {
if (strcmp(input_argv[0], commands[i]->get_name()) == 0) {
commands[i]->process_args(input_argc, input_argv);
break;
}
}
}
Вывод Valgrind:
ls -a -b
--30624-- REDIR: 0x375e8812d0 (strlen) redirected to 0x480155c (_vgnU_ifunc_wrap per)
--30624-- REDIR: 0x375e87f810 (__GI_strchr) redirected to 0x4a07b30 (__GI_strchr )
option -a
option -b
ls -a -b
==30624== Invalid read of size 1
==30624== at 0x375E8CDFDC: _getopt_internal_r (in /lib64/libc-2.12.so)
==30624== by 0x375E8CF1EA: _getopt_internal (in /lib64/libc-2.12.so)
==30624== by 0x375E8CF2D2: getopt_long (in /lib64/libc-2.12.so)
==30624== by 0x401E1C: ls::process_args(int, char**) (ls.h:31)
==30624== by 0x4019CB: main (main.cpp:36)
==30624== Address 0x513e5da is 26 bytes inside a block of size 27 free'd
==30624== at 0x4A05FD6: operator delete(void*) (vg_replace_malloc.c:480)
==30624== by 0x4CCADFE: std::basic_string<char, std::char_traits<char>, std:: allocator<char> >::~basic_string() (basic_string.h:538)
==30624== by 0x403AA5: void std::_Destroy<std::string>(std::string*) (stl_con struct.h:93)
==30624== by 0x403855: void std::_Destroy_aux<false>::__destroy<std::string*> (std::string*, std::string*) (stl_construct.h:103)
==30624== by 0x403466: void std::_Destroy<std::string*>(std::string*, std::st ring*) (stl_construct.h:126)
==30624== by 0x402DE6: void std::_Destroy<std::string*, std::string>(std::str ing*, std::string*, std::allocator<std::string>&) (stl_construct.h:151)
==30624== by 0x402878: std::vector<std::string, std::allocator<std::string> > ::~vector() (stl_vector.h:415)
==30624== by 0x401A03: main (main.cpp:26)
==30624==
--30624-- REDIR: 0x375e8846b0 (mempcpy) redirected to 0x4a09f80 (mempcpy)
non-option input_argv-elements: s b
quit
--30624-- REDIR: 0x375e87b6d0 (free) redirected to 0x4a06369 (free)
==30624==
==30624== HEAP SUMMARY:
==30624== in use at exit: 0 bytes in 0 blocks
==30624== total heap usage: 36 allocs, 36 frees, 916 bytes allocated
==30624==
==30624== All heap blocks were freed -- no leaks are possible
==30624==
==30624== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 6 from 6)
==30624==
Справочная страница Linux на getopt()
дает понять, как сбросить getopt()
(который, к сожалению, использует ряд глобальных переменных для связи с вызывающей стороной и поддержания состояния):
Переменная optind — это индекс следующего элемента, который будет обработан в argv. Система инициализирует это значение равным 1. Вызывающий может сбросить его на 1, чтобы возобновить сканирование того же самого argv или при сканировании нового вектора аргумента.
Других решений пока нет …