Why am I getting a segmentation fault when I use switch-case statement with hash-strings? [closed] - c++

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed last month.
Improve this question
I am trying to create a CLI (Command Line Interface). I currently don't have a good idea of what I want from it.
Note: The faults started appearing when I used a switch-case statement with hash-strings to run the commands. Also, there are no errors when compiled. The faults may start anywhere, because I have used printf to print a message representing argc and argv when the cli is run.
Below is the code I used:
codeycat.cpp
#include <map>
#include <iostream>
using namespace std;
static enum Functions {
undef,
comm_test,
comm_commands
} functions;
static map<string, Functions> mapStringValues;
static void Initialize();
bool samestr(const char *svar, const char *str)
{
if (strcmp(svar, str) == 0)
{
return true;
}
else
{
return false;
}
}
string construct_version(int major, int minor, int patch)
{
string strmajor = to_string(major);
string strminor = to_string(minor);
string strpatch = to_string(patch);
string version = strmajor + "." + strminor + "." + strpatch;
return version;
}
int test(string command)
{
int code = system(command.c_str());
return code;
}
void commands()
{
printf("(test, commands)\n");
}
int main(int argc, char *argv[])
{
string doc = "Usage: codeycat [options...] [function] [args...]\n"
"Options:\n"
"\t--help -h: Show this message and exit\n"
"\t--version -v: Show version and exit\n";
string version = construct_version(1, 0, 0);
printf("arg count: %d, args: %s %s %s", argc, argv[0], argv[1], argv[2]);
if (argc < 2)
{
printf("%s", doc.c_str());
return 1;
}
const char command[PATH_MAX] = {*argv[2]};
switch (mapStringValues[command])
{
case undef:
printf("Command not found: %s", command);
case comm_test:
test(argv[3]);
case comm_commands:
cout << "Hello" << endl;
// commands();
}
return 0;
}
void Initialize()
{
mapStringValues["undef"] = undef;
mapStringValues["test"] = comm_test;
mapStringValues["commands"] = comm_commands;
}
Running % ./codeycat of course returns a return code 1 (error), but running % ./codeycat with options --help, --version, -h, -v or running its functions don't work.
Here are the outputs:
./codeycat
arg count: 1, args: ./codeycat (null) COLORTERM=truecolorUsage: codeycat [options...] [function] [args...]
Options:
--help -h: Show this message and exit
--version -v: Show version and exit
./codeycat --help
[1] 12372 segmentation fault ./codeycat --help
./codeycat -h
[1] 12416 segmentation fault ./codeycat -h
./codeycat --version
[1] 12459 segmentation fault ./codeycat --version
./codeycat -v
[1] 12501 segmentation fault ./codeycat -v
./codeycat test 'echo Hello'
[1] 12544 segmentation fault ./codeycat test 'echo Hello'
./codeycat commands
[1] 12587 segmentation fault ./codeycat commands

You can't read from argv without first checking argc. argv is an array of length argc, so any index greater than or equal to argc is out of bounds. This line
printf("arg count: %d, args: %s %s %s", argc, argv[0], argv[1], argv[2]);
Doesn't crash because some printf implementations print "(null)" if you pass a null pointer to the %s specifier.
When you don't pass any arguments, you return early because argc is 1 and you print the doc and return 1.
However, when you do pass an argument, you don't return early, which means you reach this line
const char command[PATH_MAX] = {*argv[2]};
This crashes because you are reading from argv[2] when argc is less than 2. If you pass 2 CLI arguments, this line won't crash. Additionally, this doesn't create a string, it creates an array of size PATH_MAX with element 0 being the first character of argv[2]. If you want to index mapStringValues with argv[2], you need to create an std::string. Also, argv[2] is the second argument, so if you want the first argument to be the command(which is usually the case), then you should read from argv[1].
string command = argv[1];
Switch statement cases don't break automatically, which means that at the end of "case undef:", you will enter "case comm_test".
switch (mapStringValues[command])
{
case undef:
printf("Command not found: %s", command);
// this will fall through to case comm_test,
case comm_test:
test(argv[3]);
case comm_commands:
cout << "Hello" << endl;
// commands();
}
test(argv[3]) will be called even if the initial case is undef.
You need to add break statements to prevent the cases from falling through
switch (mapStringValues[command])
{
case undef:
printf("Command not found: %s", command);
// add break to prevent fallthrough
break;
case comm_test:
test(argv[3]);
break;
case comm_commands:
cout << "Hello" << endl;
break;
// commands();
}
Lastly, you never called Initialize(), so the map is always empty, meaning that every command will result in not being found. You need to call the Initialize() function to initialize the map

Related

Using the Argo Command line parser: Unknown option is not returned when option is behind a exsiting option

Using this very nice Commandline parser Argo (Header only C++ library) I've encountered a small issue.
See : https://github.com/phforest/Argo
Argo returns : 'Error: Unknown option' when a option in not found, but not when the argument is behind a know argument.
Compiling the code below: (inc is location of the argo header)
c++ test.cpp -I inc --std=c++11
#include <iostream>
int main(int argc, char **argv)
{
argo::Configuration pcnfg;
std::vector<std::string> input_texts;
pcnfg.program.name = { "wow", "EyeOnText WoWoolConsole" };
pcnfg.program.version = { 1, 1, 1 };
argo::Arguments args(pcnfg);
args.add(argo::handler::Option("input-text", "i", input_texts).help("Input text to process."));
const auto result = args.parse(argc, argv);
switch (result.status)
{
case argo::ReturnCode::Error: std::cerr << "Error: " << result.message << std::endl; return 1;
case argo::ReturnCode::SuccessAndAbort: return 0;
default: break;
}
for ( auto const & input : input_texts )
{
std::cout << "- " << input << std::endl;
}
return 0;
}
run:
./a.out --other -i "test"
Error: Unknown option '--other'
Which is ok
run:
./a.out -i "test" --other
- test
- --other
--other should not be in the input list.
(Disclaimer: I'm the developer of the library)
I think this is solved in more recent versions. At least, using the provided code, I get the expected output (twice an 'Unknown option' error). If it's not solved, we can take it up using the bug tracker at https://gitlab.com/dgrine/Argo/issues

Bash autocomplete an option without running the application

I have found this code as a bash autocomplete. But, it looks strange to me. What if I do not like to run the code at all. If I would like to type ./a.out then space (without entering) and then by pressing tab, I would like to see only two options apple and cherry and if I type a and press tab, then it autocomplete the option apple and similarly for c. Let's say only one of the two options are acceptable:
./a.out apple
./a.out cherry
where apple and cherry are options and not the name of the files in the directory. In the first case, I would like the program types that your option is apple and in the second case your option is cherry. In any other case, the program should print an error that the option is not valid.
All examples that I find on the internet such as what follows look like that you should run the program first, then it reacts. The while loop inside the main function collides with the normal functionality of the program. Have I misunderstood the readline library? Is the above-described application possible to implement by editing the following code?
// sudo apt-get install libreadline-dev
// g++ -std=c++11 main.cpp -lreadline
#include <iostream>
#include "readline/readline.h"
#include "readline/history.h"
using namespace std;
int main(int argc, char** argv)
{
const char *line;
while ((line = readline("? ")) != nullptr) {
cout << "[" << line << "]" << endl;
if (*line) add_history(line);
free(line);
}
// if(argc!=2)
// {
// cout<<"<exe> one_parameter"<<endl;
// return 1;
// }
// string option=argv[1];
// if(option=="apple" || option=="cherry")
// cout<<"Your option is "<<option<<endl;
// else
// {
// cout<<"Error: invalid option "<<option<<endl;
// return 1;
// }
return 0;
}
// partial answer - why you may want to invoke the app while doing the autocompletion
One way of implementing the autocomplete for an application is to have the application binary configure it (by having a flag that prints the instructions for autocomplete configuration or by just parsing the --help output of the application).
Schemataically:
complete -F $(./a.out --generate-autocomplete-config) ./a.out
This is why you might see the binary actually invoked as a part of autocomplete implementation.
This has nothing to do with your executable. You need to put this in a file and source (source autocomplete_file or . autocomplete_file) it in the bash.
_a_complete_()
{
local word=${COMP_WORDS[COMP_CWORD]}
local files='apple cherry'
COMPREPLY=( $( compgen -W "${files}" -- ${word} ) )
}
complete -F _a_complete_ ./a.out
Here a nice documentation can be found.

Send some arguments (like Ctrl-C, 3, some_string), to program, from bash script

I have a program that written in c++, and i have parameter that i want to re change. when the program is running.
So i have function that "catch" the signal INT, so when the program is running (in terminal) i type in terminal Ctrl-C, and this lead me to function with menu and the user can type 1,2,3 ... and then i type Enter and then write some value (etc 123...).
Everything work well, but i want to do it automatically from bash script.
Hear is my code:
// Example program
#include <iostream>
#include <string>
#include <signal.h>
#include <stdio.h>
using namespace std;
int val=0;
void signal_callback_handler(int signum)
{
printf("Caught signal %d\n",signum);
// Cleanup and close up stuff here
int ans = -1;
/*Print the menu.*/
cout << "Press Your Choice"<<endl
<<"MENU:"<<endl
<<"1 - Exit."<<endl
<<"2 - Resume."<<endl
<<"3 - Add new computer."<<endl;
cin >> ans;
switch (ans)
{
case 1:
exit(signum);
break;
case 2:
cout <<" Resume"<< endl;
break;
case 3:
//creat_new_clinet();
cout<<"Option 3 choose"<<endl;
cout<<"Type value to val"<<endl;
cout<<"val before - "<<val<<endl;
cin>>val;
cout<<"val after - "<<val<<endl;
break;
default:
break;
}
}
int main(int argc,char **argv)
{
// Register signal and signal handler
signal(SIGINT, signal_callback_handler);
getchar();
}
i compiled it with g++ with flag "-std=c++11".
g++ temp.cpp -std=c++11 -o temp
After i compiled it i run it from terminal
./temp
So i type - Ctrl-C and then i got this message:
^CCaught signal 2
Press Your Choice
MENU:
1 - Exit.
2 - Resume.
3 - Add new computer.
Then i type 3, and here are the result:
Option 3 choose
Type value to val
val before - 0
Then i type for example - 123, and the result is:
val after - 123
So i press on Enter and the program finish.
I want to do it automatically by bash script. i tried to do it with next script:
pgrep -f temp | xargs kill -INT
pid_number=$(pidof temp)
echo $pid_number
arg='3\n'
echo $arg > /proc/$pid_number/fd/0
#xdotool key 3+Enter
#/usr/bin/xvkbd -xsendevent -text "\[3]\[Enter]"
If i start the program (temp) and i run this script i can see the menu but it doesen't do nothing, just show me the menu.
Any idea how to do it?
To simulate pressing the ENTER key, you have to send a Carriage return \r and not a newline \n

Exec fails due to Bad Address

I have a serious problem with exec.I've tried both options with list(execl) and array(execv) but the problem remains.I'll give the function in which i try to make the call.
#include <unistd.h>
#include <sys/types.h>
void MyFunc(string aparams[],char* infile,char* outfile,int k,int points){
int mcount=3;
char* offset= new char[5];
sprintf(offset,"%d",k);
char* pntr=new char[5];
sprintf(pntr,"%d",points);
char* *wparams=new char*[mcount];
for (int i = 0; i < mcount; i++) {
wparams[i] = new char[aparams[i].length() + 1];
strcpy(wparams[i], aparams[i].c_str());
}
char *cwd;
cwd=(char*)malloc(255);
getcwd(cwd,255);
strcat(cwd,"/");
strcat(cwd,wparams[0]);
cout << cwd << endl;
execl(cwd,wparams[0],"-i",infile,"-o",outfile,"-f",offset,"-n",pntr,"-a",wparams[1],wparams[2],wparams[3],(char*) NULL);
cout << "exec failed" << endl;
perror("The problem in exec is:");
exit(3);
}
aparams[0] contains a string with the name of an executable file,let's say "test".I compiled -> g++ test.cpp -o test -> so I got this executable.
The other positions of aparams contain some arguments for the test program.
So,test never runs(when I run it from command line it's ok) and perror shows the message "The problem in exec is: Bad Address."
I've also tried to cast all arguments(const char*) but nothing changed.
Is it a problem with arguments? Or it's a matter of the executable?
mcount is 3, so wparams points to an array with three elements - wparams[0], wparams[1] and wparams[2].
Then you access wparams[3] which is invalid and contains garbage.
Don't try to access array elements that don't exist.
Your problem is in this line:
execl(cwd,
wparams[0],
"-i", infile, "-o", outfile, "-f", offset, "-n", pntr,
"-a", wparams[1], wparams[2], wparams[3], (char*) NULL);
You're trying to send wparams[3], which doesn't exists! It's the 4th element of wparam array and you explicitly defined it as array[3] in the initialization of your variable mcount.

LuaPlus: How to make a function return a table?

I'm wondering how I you can create and register a function from the C++-side that returns a table when called from the Lua-side.
I've tried a lot of things but nothing did really work. :/
(sorry for the long code)
This for example won't work, because Register() expects a "luaCFunction"-styled function:
LuaPlus::LuaObject Test( LuaPlus::LuaState* state ) {
int top = state->GetTop();
std::string var( state->ToString(1) );
LuaPlus::LuaObject tableObj(state);
tableObj.AssignNewTable(state);
if (var == "aaa")
tableObj.SetString("x", "ABC");
else if (var == "bbb")
tableObj.SetString("x", "DEF");
tableObj.SetString("y", "XYZ");
return tableObj;
}
int main()
{
LuaPlus::LuaState* L = LuaPlus::LuaState::Create(true);
//without true I can't access the standard libraries like "math.","string."...
//with true, GetLastError returns 2 though (ERROR_FILE_NOT_FOUND)
//no side effects noticed though
LuaPlus::LuaObject globals = L->GetGlobals();
globals.Register("Test",Test);
char pPath[MAX_PATH];
GetCurrentDirectory(MAX_PATH,pPath);
strcat_s(pPath,MAX_PATH,"\\test.lua");
if(L->DoFile(pPath)) {
if( L->GetTop() == 1 ) // An error occured
std::cout << "An error occured: " << L->CheckString(1) << std::endl;
}
}
When I try to set it up as a luaCFunction-function it just crashes (0x3) and says:
Assertion failed: 0, file C:\......\luafunction.h, line 41
int Test( LuaPlus::LuaState* state ) {
int top = state->GetTop();
std::string var( state->ToString(1) );
LuaPlus::LuaObject tableObj(state);
tableObj.AssignNewTable(state);
if (var == "aaa")
tableObj.SetString("x", "ABC");
else if (var == "bbb")
tableObj.SetString("x", "DEF");
tableObj.SetString("y", "XYZ");
tableObj.Push();
return state->GetTop() - top;
}
For clarification: from the Lua side I wanted it to be callable like:
myVar = Test("aaa")
Print(myVar) -- output: ABC
EDIT: The Print function comes from here. And was basically the cause for this to not work. Print can only print strings not tables... The C++ code from above works fine if you just return 1.
This is the documentation that came with my LuaPlus version btw: http://luaplus.funpic.de/
I really hope you can help me.. I'm already starting to think that it is not possible. :'(
edit:
I totally forgot to say that using PushStack() lead into an error because "the member does not exist"...
After some painstaking probing from the long comment discussion, I'm posting this answer to help summary the situation and hopefully to offer some useful advice.
The main issue the OP was running into was that the wrong print function was being called in the lua test script. Contrary to the original code shown the real code the OP was testing against was calling Print(myVar) which is a custom provided lua_CFunction and not the builtin print function.
Somehow along the way, this ended up creating some instantiation of template <typename RT> class LuaFunction and calling the overloaded operator()(). From inspecting the luafunction.h from luaPlus any lua errors that occurs inside this call will get swallowed up without any kind of logging (not a good design decision on luaPlus's part):
if (lua_pcall(L, 0, 1, 0)) {
const char* errorString = lua_tostring(L, -1); (void)errorString;
luaplus_assert(0);
}
To help catch future errors like this, I suggest adding a new luaplus_assertlog macro. Specifically, this macro will include the errorString so that the context isn't completely lost and hopefully help with debugging. This change hopefully won't break existing uses of luaplua_assert from other parts of the API. In the long run though, it's probably better to modify luaplus_assert so it actually includes something meaningful.
Anyway here's a diff of the changes made:
LuaPlusInternal.h
## -81,5 +81,6 ##
} // namespace LuaPlus
#if !LUAPLUS_EXCEPTIONS
+#include <stdio.h>
#include <assert.h>
#define luaplus_assert(e) if (!(e)) assert(0)
## -84,5 +85,6 ##
#include <assert.h>
#define luaplus_assert(e) if (!(e)) assert(0)
+#define luaplus_assertlog(e, msg) if (!(e)) { fprintf(stderr, msg); assert(0); }
//(void)0
#define luaplus_throw(e) assert(0)
//(void)0
LuaFunction.h
## -21,7 +21,7 ##
class LuaFunction
{
public:
- LuaFunction(LuaObject& _functionObj)
+ LuaFunction(const LuaObject& _functionObj)
: functionObj(_functionObj) {
}
## -36,7 +36,7 ##
if (lua_pcall(L, 0, 1, 0)) {
const char* errorString = lua_tostring(L, -1); (void)errorString;
- luaplus_assert(0);
+ luaplus_assertlog(0, errorString);
}
return LPCD::Type<RT>::Get(L, -1);
}
In the change above, I opted not to use std::cerr simply because C++ streams tend to be heavier than plain-old C-style io functions. This is especially true if you're using mingw as your toolchain -- the ld linker is unable to eliminate unused C++ stream symbols even if your program never uses it.
With that in place, here's an example where an unprotected call is made to a lua function so you can see the errorString printed out prior to the crash:
// snip...
int main(int argc, const char *argv[])
{
LuaStateAuto L ( LuaState::Create(true) );
LuaObject globals = L->GetGlobals();
globals.Register("Test", Test);
globals.Register("Print", Print);
if(argc > 1)
{
/*
if (L->DoFile(argv[argc - 1]))
std::cout << L->CheckString(1) << '\n';
/*/
L->LoadFile( argv[argc - 1] );
LuaFunction<int> f ( LuaObject (L, -1) );
f();
//*/
}
}
Running the above will trigger the crash but will include a semi-helpful error message:
g++ -Wall -pedantic -O0 -g -I ./Src -I ./Src/LuaPlus/lua51-luaplus/src plustest.cpp -o plustest.exe lua51-luaplus.dll
plustest.exe plustest.lua
plustest.lua:2: bad argument #1 to 'Print' (string expected, got table)Assertion failed!
Program: G:\OSS\luaplus51-all\plustest.exe
File: ./Src/LuaPlus/LuaFunction.h, Line 39
Expression: 0
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
first you may try to register the function using RegisterDirect(), this may avoid lua_CFunction's problem, check the luaplus manual.like this
LuaPlus::LuaObject globals = L->GetGlobals();
globals.RegisterDirect("Test",Test);
second if I remeber to create a table have two solutions,like this
//first
LuaObject globalsObj = state->GetGlobals();
LuaObject myArrayOfStuffTableObj = globalsObj.CreateTable("MyArrayOfStuff");
//second
LuaObject aStandaloneTableObj;
aStandaloneTableObj.AssignNewTable(state);
check whether you have use the right function.
third I remember the lua stack object is not the luaobject, they have a conversion, may be you can try this
LuaStackObject stack1Obj(state, 1);
LuaObject nonStack1Obj = stack1Obj;
forth, like the function Test() you have give above, the table tableObj you have pushing onto the lua stack, you must remember to clear the object.