I live in an environment with Win7/MSVC 2010sp1, two different Linux boxes (Red Hat) with g++ versions (4.4.7, 4.1.2), and AIX with xlc++ (08.00.0000.0025).
Not so long ago it was requested that we move some code from AIX over to Linux. It didn't take too long to see that Linux was a bit different. Normally when a signal is thrown, we handle it and throw a C++ exception. That was not working as expected.
Long story short, throwing c++ exceptions from a signal handler isn't going to work.
Sometime later, I put together a fix that uses setjmp/longjmp to move the exception out of the handler. Aftersome testing and the dang thing works on all platforms. After an obligatory round of cubical happy dance I moved on to setting up some unit tests. Oops.
Some of my tests were failing on Linux. What I observed was that the raise function only worked once. With two tests using SIGILL, the first one passed, and the second one failed. I broke out an axe, and started chopping away at the code to remove as much cruft as possible. That yielded this smaller example.
#include <csetjmp>
#include <iostream>
#include <signal.h>
jmp_buf mJmpBuf;
jmp_buf *mpJmpBuf = &mJmpBuf;
int status = 0;
int testCount = 3;
void handler(int signalNumber)
{
signal(signalNumber, handler);
longjmp(*mpJmpBuf, signalNumber);
}
int main(void)
{
if (signal(SIGILL, handler) != SIG_ERR)
{
for (int test = 1; test <= testCount; test++)
{
try
{
std::cerr << "Test " << test << "\n";
if ((status = setjmp(*mpJmpBuf)) == 0)
{
std::cerr << " About to raise SIGILL" << "\n";
int returnStatus = raise(SIGILL);
std::cerr << " Raise returned value " << returnStatus
<< "\n";
}
else
{
std::cerr << " Caught signal. Converting signal "
<< status << " to exception" << "\n";
std::exception e;
throw e;
}
std::cerr << " SIGILL should have been thrown **********\n";
}
catch (std::exception &)
{ std::cerr << " Caught exception as expected\n"; }
}
}
else
{ std::cerr << "The signal handler wasn't registered\n"; }
return 0;
}
For the Windows and the AIX boxes I get the expected output.
Test 1
About to raise SIGILL
Caught signal. Converting signal 4 to exception
Caught exception as expected Test 2
About to raise SIGILL
Caught signal. Converting signal 4 to exception
Caught exception as expected Test 3
About to raise SIGILL
Caught signal. Converting signal 4 to exception
Caught exception as expected
For both Linux boxes it looks like this.
Test 1
About to raise SIGILL
Caught signal. Converting signal 4 to exception
Caught exception as expected
Test 2
About to raise SIGILL
Raise returned value 0
SIGILL should have been thrown **********
Test 3
About to raise SIGILL
Raise returned value 0
SIGILL should have been thrown **********
So, my real question is "What is going on here?"
My retorical questions are:
Is anyone else observing this behavior?
What should I do to try to troubleshoot this issue?
What other things should I be aware of?
You must use sigsetjmp/siglongjmp to ensure the correct behavior when mixing signals and jumps. If you change your code it will correctly work under Linux.
You also used the old signal API which not recommended. I encourage you to use the much more reliable sigaction interface. The first benefits will be that you have no more need to reset the signal catch in the handler...
Related
I have a code that depends on many external libraries that works fine in debug mode but it crashes in release mode.
When checking the root cause I found that there is a true condition that's evaluated to false
My code looks like
#include <iostream>
enum fruits
{
a, b, c
}
...
int main()
{
auto condition (fruits::a == 99);
std::cout << condition;
if (fruits::a == 99) std::cout << " FATAL ERROR ";
...
}
The progam outputs :
0 FATAL ERROR
The program is using c++20 with O2 optimisation flag
The issue is not present if I execute the code in a separated program.
#include <iostream>
#include <float.h>
#pragma fenv_access (on)
int main(int, char**argv)
{
unsigned int fp_control_word;
_controlfp_s(&fp_control_word, 0, 0);
const unsigned int new_fp_control_word = fp_control_word | _EM_INVALID | _EM_DENORMAL
| _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW | _EM_INEXACT;
_controlfp_s(&fp_control_word, new_fp_control_word, _MCW_EM);
try
{ std::cout << std::atof(argv[1]) / std::atof(argv[2]) << std::endl;
} catch (...)
{ std::cout << "caught exception" << std::endl;
}
}
I remember that it is possible to catch memory access errors on windows using a try-catch block.
There is already a question regarding this subject. But it is 10 years old and the code provided does not result in an exception, but in printing a NAN.
I was always curious about using this feature to abort some piece of numerical code in a nice way. The motivation is to abort some VERY COMPLEX piece of code immediately, if anywhere in this code a floating point exception occurred rather than keeping evaluating the rest of the code with NAN results -- which is rather slow and anyway does not make sense.
Please: I don't care if this is not supported by the C++ standard!
The question is, how to get this code to run into the catch-block -- e.g. by using the command line parameters 0.0 0.0!
For me it always prints out NAN.
What compiler options need to be used?
Or does the code need to be changed?
If one provokes a nullptr dereference in the try-block one will end up in the catch-block. But not for division by zero.
One needs to use the compiler option /EHa to enable structured exception handling.
Thanks to https://stackoverflow.com/users/17034/hans-passant for the solution.
Here comes the working code:
#include <iostream>
#include <float.h>
#pragma fenv_access (on)
int main(int, char**argv)
{
unsigned int fp_control_word;
_controlfp_s(&fp_control_word, 0, _MCW_EM);
const unsigned int new_fp_control_word = fp_control_word & ~(_EM_INVALID
| _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW | _EM_INEXACT);
_controlfp_s(&fp_control_word, new_fp_control_word, _MCW_EM);
try
{ std::cout << std::atof(argv[1]) / std::atof(argv[2]) << std::endl;
} catch (...)
{ std::cout << "caught exception" << std::endl;
}
}
I have searched considerably for an answer to this without success.
In a debugger, one may write instructions and then execute them.
This requires special permissions in the executable image.
I seek to perform this function without the debugger.
Please show me an ASM "hello world" program that has self-modifying code
(perhaps replacing a series of 090H with code to uppercase the 'h' in hello)
and the commands necessary to enable its execution.
The next 2 lines are the before and after machine code for the h->H replacement.
90 90 90 90 90 90 90 90 90 90 90 ; 11 NOPs
8a 26 50 00 80 e4 df 88 26 50 00 ; MOV AH,[BX]; AND AH,0DFH; MOV [BX],AH;
I have complete competence and confidence constructing iAPX86 machine code.
My problem is convincing linux, darwin/yosemite, and windows to allow execution.
In the end, I want to be able to construct and modify an executable
on-the-fly for a new language I am writing.
The architecture of the new language has no parallels in modern practice.
I expect much criticism for flying in the face of convention,
but I will proceed with my plans notwithstanding.
Thank you all for taking my question seriously.
This code works! It turned out to be far simpler than I thought;
without special compiler flags, or ELF or MACHO specialization.
In iAPX86 machine code, C3 is near RET without a return value.
I have a few improvements to make, listed after the code,
but this question, as asked, is completely answered to my satisfaction.
working code
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <string>
using namespace std;
typedef void (*fptr)();
int main(int argc, char **argv) {
try {
fptr p = (fptr)"\xc3";
p();
cout << "Hello world" << endl;
}
catch (const int e) { cout << "int exception: " << e << endl; }
catch (const char e) { cout << "char exception: " << e << endl; }
catch (const string &e) { cout << "string exception: " << e << endl; }
catch (...) { cout << "default exception" << endl; }
exit(0);
}
TODO
bracket opcode strings with safety code.
prevent certain opcodes from appearing in strings.
catch signals as well as exceptions.
I wrote this code for my class and when i debug it runs but shuts down within seconds i dont know what i'm doing wrong here. I am really new to C++ so.
here is the code:
#include "stdafx.h"
#include<iostream>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
double gallons;
double startmile;
double endmile;
double totalmilestravelled;
cout << "This Program Calculates your vehicle's gas mileage on this trip\n" << endl;
cout << "What is the number of gallons consumed on the trip: ";
cin >> gallons;
cout << "\nWhat was your ending mile?";
cin >> endmile;
cout << "\nWhat was your starting mile?";
cin >> startmile;
totalmilestravelled = endmile-startmile;
double mpg = totalmilestravelled/gallons;
cout << "your gas mileage is: " << mpg << endl;
return 0;
}
and this is the error:
The program '[9848] gasmileage.exe: Native' has exited with code 0 (0x0).
That's not an error. The program exited normally. When you run a program, it executes and exits with an exit code specified by the program. In this case you return 0, so the program exits with code 0. If you want the program to "pause" to allow you to see the result of the program before it closes, add this just before the return statement:
cin.ignore(128, '\n');
cin.get();
The first line discards newlines that were left over in the standard input. Don't worry about this too much until you learn more about the input stream, but you need to do this if you are attempting to read a string after reading numeric input from the user. The second line will prompt the user for some input (push return). You don't care what the input is, and you aren't going to do anything with the input. You just want to force the program to wait for user input so that you can see what's going on before continuing with the program (which in this case the program immediately exit).
Think about programs that say "Press any key." It's the same thing we're doing here. Giving the user a moment to view the output.
I'm trying to read a processes memory on Linux (Xubuntu, to be precise). I'm pretty new to Linux, though I've done this same read using Win32API ReadProcessMemory() before in Windows. The general idea is that I'm trying to develop some software for a game which will get my stats and upload them to a server, which will track my progress and keep a log of it. The end goal is to make a bot which will automatically play and farm data about the game. In order to do this, I need to be able to access the processes memory. In Windows, that's dead easy. In Linux, it's proving a little more complex.
I've found a memory address which contains information I want to read. The information is an int32, and it is stored at 84a1bd8. I found it using GameConqueror 0.13. The address remains correct after restarting, so it appears there is no ASLR (as there was in Windows). I also know the ProcessID (I can find this using task manager for now, though if someone knows a simple way to get a PID by either ClassName, Exe name, or similar, that would be great too!) So, that looks like it should be all I really need to use PTRACE_PEEKDATA to read the memory, right? Well, that's the problem, it doesn't appear to be. My code looks like this:
#include <iostream>
#include <string>
#include <sys/ptrace.h>
#include <errno.h>
using namespace std;
int main()
{
pid_t pid = 4847;
int addr = 0x84a1bd8;
long ret = ptrace(PTRACE_TRACEME, pid, NULL, NULL);
cout << "ptrace Status: " << ret << endl;
cout << "Errno: " << errno << endl;
ret = ptrace(PTRACE_PEEKDATA, pid, (void*)addr, NULL);
cout << "ptrace Status: " << ret << endl;
cout << "Errno: " << errno << endl;
ret = ptrace(PTRACE_DETACH, pid, NULL, NULL);
cout << "ptrace Status: " << ret << endl;
cout << "Errno: " << errno << endl;
return 0;
}
The output looks like this:
ptrace Status: 0
Errno: 0
ptrace Status: -1
Errno: 3
ptrace Status: -1
Errno: 3
Being quite new to Linux, I don't know where I'm to find error codes and how I can work out what this error actually means, and nor do I know if I am even declaring the address correctly. Should I declare it as an int in it's decimal equivalent? Is there anything I'm missing?
Thanks for your time
Found the solution to be that when using ptrace() you must call in an order:
ptrace(PTRACE_ATTACH, pid, NULL, NULL)
ptrace(PTRACE_PEEKDATA, pid, addr, NULL)
ptrace(PTRACE_DETACH, pid, NULL, NULL)
So the simple answer: You need to attach and detach before and after reading the memory.
It may also be useful to know that between the attach and detach commands, the process will sleep, meaning this method isn't so good for my purpose, but may be useful to others :)
Thanks to #PeterL. for your help.