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.
Related
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
Following is a sample code compiled using GNU compiler (g++ command) on an Ubuntu OS 16.04:
#include<iostream>
#include<unistd.h>
#include<fcntl.h>
#include <errno.h>
int main()
{ char* pBuffer;
char* storedfilepath = "/home/rtpl/Desktop/ts.mp4";
std::cout<<"\n Opening file at "<<storedfilepath<<"\n";
int NumBytesToRead = 1000 ;
int filedes = open(storedfilepath,O_RDONLY);
std::cout<<"\n value of error is "<<errno<<"\n";
std::cout<<"\n value of filedes is "<<filedes;
if (filedes==0)
std::cout<<"\n File cannot be opened";
else
{
std::cout<<"\n File opened successfully";
std::cout<<"\n Now reading file\n";
}
//if(
int ret = read(filedes,pBuffer,NumBytesToRead);
std::cout<<"\n value of error is "<<errno<<"\n";
if(ret!= -1)
std::cout<<"\n File read successfully";
else
std::cout<<"\n File contents cannot be read";
std::cout<<"\nEnd.\n";
close(filedes);
return 0;
}
When compiled; I get this message:
rtpl#rtpl-desktop:~/Desktop$ g++ -g checkts.cpp
checkts.cpp: In function ‘int main()’:
checkts.cpp:8:27: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
char* storedfilepath = "/home/rtpl/Desktop/ts.mp4";
Upon execution:
rtpl#rtpl-desktop:~/Desktop$ ./a.out
Opening file at /home/rtpl/Desktop/ts.mp4
value of error is 0
value of filedes is 3
File opened successfully
Now reading file
value of error is 14
File contents cannot be read
End.
Entire gdb debug can be found here.
Question : Why won't the file contents be read when the file is legit and the compiler throws no error?
Assuming you're running Linux, an errno value of 14 is EFAULT, or "bad address".
Given the code
char* pBuffer;
.
.
.
int ret = read(filedes,pBuffer,NumBytesToRead);
pBuffer is not initialized or otherwise set, so the value in pBuffer is indeterminate and it certainly doesn't point to a valid address.
You need to actually provide a buffer where read() can place the data read:
char buffer[ 1024 ]
.
.
.
ssize_t ret = read(filedes,buffer,NumBytesToRead);
would work, as long as NumBytesToRead does not exceed the number of bytes in buffer. Note also that ret is now the proper ssize_t instead of int.
I have a Linux program, that from time to time ends with a segmentation fault. The program is running periodically every hour, but the segmentation fault occurs only sometimes.
I have a problem to debug this, because if I run the program again with the same input, no error is reported and all is OK.
Is there a way, how to "report" in which part of the code error occured or what caused the problem?
The usual way is to have the crashing program generate a corefile and analyze this after the crash. Make sure, that:
the maximum corefile-size is big enough (i.e. unlimited) by calling ulimit -c unlimited in the shell, which starts the process.
The cwd is writable by the segfaulting process.
Then you can analyze the file with
gdb <exe> <corefile>
Since your code not crashing every time, you can use backtrace as well. Using this you can see the function call stack at the time of crash. There are many examples available. In my projects I normally use the following code for backtracing.
/*
* call reg_usr2 function from main
* gcc -rdynamic myfile.c -o output
*/
#include <stdio.h>
#include <stdarg.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <execinfo.h>
#define FILE_NAME "/tmp/debug"
#define MODE 0xFFFF
void dbgprint(int flag, char* fmt, ...)
{
if(flag & MODE) {
char buf[100];
va_list vlist;
FILE *fp = fopen(FILE_NAME,"a");
va_start(vlist, fmt);
vsnprintf( buf, sizeof( buf), fmt, vlist);
va_end( vlist);
fprintf(fp,"[%x]->%s\n", flag, buf);
fclose(fp);
}
}
/** Here is the code to print backtrace **/
void print_stack_trace ()
{
void *array[20];
size_t size;
char **strings;
size_t i;
size = backtrace (array, 20);
strings = backtrace_symbols (array, size);
dbgprint(0xFFFF, "Obtained %zd stack frames.", size);
dbgprint(0xFFFF, "-------------------------");
dbgprint(0xFFFF, "---------Backtrace-------");
for (i = 0; i < size; i++)
dbgprint (0xFFFF, "%s", strings[i]);
dbgprint(0xFFFF, "-------------------------");
free (strings);
}
void sig_handler(int signo)
{
FILE *fp = fopen(FILE_NAME,"a");
if (signo == SIGUSR2){
dbgprint(0xFFFF, "received SIGUSR2");
dbgprint(0xFFFF, "----------------");
}
print_stack_trace();
exit(0);
}
void reg_usr2()
{
if (signal(SIGUSR2, sig_handler) == SIG_ERR)
printf("\ncan't catch SIGUSR2\n");
}
int main()
{
reg_usr2(); //should be first line of main after variables
//Code.....
return 0;
}
You can generate backtrace by catching SIGSEGV signal, and see where your application throw an invalid access.
see https://stackoverflow.com/a/77336/4490542
But there is more easier solution, try running your application with catchsegv
catchsegv './program args'
and better alternative, valgrind
valgrind --tool=none ./program args
I am trying to interface with an OEM library. Everything worked on one computer but I am getting lots of problems on another computer.
I the code is throwing a COM exception but I can't figure out the meaning of a error code that doesn't have a ErrorMessage();
The code
#include "stdafx.h"
#include <afx.h>
#include <iostream>
using namespace std;
#import "MTBApi.tlb" named_guids //raw_interfaces_only
using namespace MTBApi;
void DisplayError(_com_error* e)
{
CString message;
// if it is an application error thrown by .NET
if (e->Error() >= 0x80041000)
{
IErrorInfo* info;
BSTR msg;
info = e->ErrorInfo();
info->GetDescription(&msg);
info->Release();
message = CString(msg);
}
// other com errors
else
{
message = e->ErrorMessage();
}
cout << "MTB Error: " << message <<":"<<(unsigned int) e->Error()<< endl;
}
int main(int argc, char **argv)
{
for (int i = 0 ; i < 4 ; i++)
{
IMTBConnectionPtr m_MTBConnection;
try
{
cout <<"1" << endl;
HRESULT a = CoInitializeEx(NULL,COINIT_SPEED_OVER_MEMORY);
cout <<"2" << endl;
m_MTBConnection = IMTBConnectionPtr(CLSID_MTBConnection);
cout <<"3" << endl;
m_MTBConnection->Close();
cout <<"4" << endl;
CoUninitialize();
cout <<"5" << endl;
}
catch(_com_error e)
{
DisplayError(&e);
}
cout << endl;
}
}
The runtime output
1
2
MTB Error: 00000000002205F8:2147746132
1
2
MTB Error: 00000000002205F8:2147746132
1
2
MTB Error: 00000000002205F8:2147746132
1
2
MTB Error: 00000000002205F8:2147746132
Rather Verbose Output from Dependency Walker
http://pastebin.com/7Y33z3Pj
cout << "MTB Error: " << message <<":"<<(unsigned int) e->Error()<< endl;
cout isn't very good at displaying Unicode strings, it merely displays the string pointer value. Not useful of course, use wcout instead. And favor displaying the error code in hex. 0x80040154 is a very common COM error, "Class not registered". Thousands of questions about it already, you just need to get the COM server registered properly. Ask the vendor or author if you don't know how to do that.
00000000002205F8 looks like a memory pointer. You are passing a CString to cout, which only accepts char* or std::string for string values. Maybe the CString contains a Unicode string that is not being converted to Ansi correctly. Also, when calling IErrorInfo::GetDescription(), you are leaking the returned BSTR. You need to free it with SysFreeString() when you are done using it.
Error code 2147746132 (hex 0x80040154) is Severity=FAIL, Facility=FACILITY_ITF, Code=340. FACILITY_ITF typically means the error code is a custom error code defined by the interface that failed. But in this case, 0x80040154 is also a standard error code: REGDB_E_CLASSNOTREG.
If your problem is to rectify the error which you are getting then
then issue is as #Remy pointed out , your com assembly is not registered in the machine you are currently executing your program rather in the other machine it got registered. Register the assembly (for eg COMAssembly.dll which is in C:\ drive) by running the following command in command prompt.
regsvr32 c:\COMAssembly.dll
if its a C++ com assembly , if its a C# assembly register it by using command
regasm c:\COMAssembly.dll
(where regasm can be run in a VS command prompt , otherwise if you are running in normal command prompt then you have to first call vsvars32.bat then call regasm)
This question is similar to cuModuleLoadDataEx options but I would like to bring the topic up again and in addition provide more information.
When loading a PTX string with the NV driver via cuModuleLoadDataEx it seems to ignore all options all together. I provide full working examples so that anyone interested can directly and with no effort reproduce this. First a small PTX kernel (save this as small.ptx) then the C++ program that loads the PTX kernel.
.version 3.1
.target sm_20, texmode_independent
.address_size 64
.entry main()
{
ret;
}
main.cc
#include<cstdlib>
#include<iostream>
#include<fstream>
#include<sstream>
#include<string>
#include<map>
#include "cuda.h"
int main(int argc,char *argv[])
{
CUdevice cuDevice;
CUcontext cuContext;
CUfunction func;
CUresult ret;
CUmodule cuModule;
cuInit(0);
std::cout << "trying to get device 0\n";
ret = cuDeviceGet(&cuDevice, 0);
if (ret != CUDA_SUCCESS) { exit(1);}
std::cout << "trying to create a context\n";
ret = cuCtxCreate(&cuContext, 0, cuDevice);
if (ret != CUDA_SUCCESS) { exit(1);}
std::cout << "loading PTX string from file " << argv[1] << "\n";
std::ifstream ptxfile( argv[1] );
std::stringstream buffer;
buffer << ptxfile.rdbuf();
ptxfile.close();
std::string ptx_kernel = buffer.str();
std::cout << "Loading PTX kernel with driver\n" << ptx_kernel;
const unsigned int jitNumOptions = 3;
CUjit_option *jitOptions = new CUjit_option[jitNumOptions];
void **jitOptVals = new void*[jitNumOptions];
// set up size of compilation log buffer
jitOptions[0] = CU_JIT_INFO_LOG_BUFFER_SIZE_BYTES;
int jitLogBufferSize = 1024*1024;
jitOptVals[0] = (void *)&jitLogBufferSize;
// set up pointer to the compilation log buffer
jitOptions[1] = CU_JIT_INFO_LOG_BUFFER;
char *jitLogBuffer = new char[jitLogBufferSize];
jitOptVals[1] = jitLogBuffer;
// set up wall clock time
jitOptions[2] = CU_JIT_WALL_TIME;
float jitTime = -2.0;
jitOptVals[2] = &jitTime;
ret = cuModuleLoadDataEx( &cuModule , ptx_kernel.c_str() , jitNumOptions, jitOptions, (void **)jitOptVals );
if (ret != CUDA_SUCCESS) { exit(1);}
std::cout << "walltime: " << jitTime << "\n";
std::cout << std::string(jitLogBuffer) << "\n";
}
Build (assuming CUDA is installed under /usr/local/cuda, I use CUDA 5.0):
g++ -I/usr/local/cuda/include -L/usr/local/cuda/lib64/ main.cc -o main -lcuda
If someone is able to extract any sensible information from the compilation process that would be great! The documentation of CUDA driver API where cuModuleLoadDataEx is explained (and which options it is supposed to accept) http://docs.nvidia.com/cuda/cuda-driver-api/index.html
If I run this, the log is empty and jitTime wasn't even touched by the NV driver:
./main small.ptx
trying to get device 0
trying to create a context
loading PTX string from file empty.ptx
Loading PTX kernel with driver
.version 3.1
.target sm_20, texmode_independent
.address_size 64
.entry main()
{
ret;
}
walltime: -2
EDIT:
I managed to get the JIT compile time. However it seems that the driver expects an array of 32bit values as OptVals. Not as stated in the manual as an array of pointers (void *) which are on my system 64 bits. So, this works:
const unsigned int jitNumOptions = 1;
CUjit_option *jitOptions = new CUjit_option[jitNumOptions];
int *jitOptVals = new int[jitNumOptions];
jitOptions[0] = CU_JIT_WALL_TIME;
// here the call to cuModuleLoadDataEx
std::cout << "walltime: " << (float)jitOptions[0] << "\n";
I believe that it is not possible to do the same with an array of void *. The following code does not work:
const unsigned int jitNumOptions = 1;
CUjit_option *jitOptions = new CUjit_option[jitNumOptions];
void **jitOptVals = new void*[jitNumOptions];
jitOptions[0] = CU_JIT_WALL_TIME;
// here the call to cuModuleLoadDataEx
// here I also would have a problem casting a 64 bit void * to a float (32 bit)
EDIT
Looking at the JIT compilation time jitOptVals[0] was misleading. As mentioned in the comments, the JIT compiler caches previous translations and won't update the JIT compile time if it finds a cached compilation. Since I was looking whether this value has changed or not I assumed that the call ignores the options all together. Which it doesn't. It's works fine.
Your jitOptVals should not contain pointers to your values, instead cast the values to void*:
// set up size of compilation log buffer
jitOptions[0] = CU_JIT_INFO_LOG_BUFFER_SIZE_BYTES;
int jitLogBufferSize = 1024*1024;
jitOptVals[0] = (void *)jitLogBufferSize;
// set up pointer to the compilation log buffer
jitOptions[1] = CU_JIT_INFO_LOG_BUFFER;
char *jitLogBuffer = new char[jitLogBufferSize];
jitOptVals[1] = jitLogBuffer;
// set up wall clock time
jitOptions[2] = CU_JIT_WALL_TIME;
float jitTime = -2.0;
//Keep jitOptVals[2] empty as it only an Output value:
//jitOptVals[2] = (void*)jitTime;
and after cuModuleLoadDataEx, you get your jitTime like jitTime = (float)jitOptions[2];