-1

I'm getting an unwanted result of division by zero in my code (the code is written in C++):

#include <iostream>
#include <signal.h>
#include <fenv.h>

void div0(int signo, siginfo_t *info, void *ucontext)
{
    if(signo == SIGFPE && info->si_code == FPE_FLTDIV)
    {
        std::cout << "You can't divide numbers by 0, idiot!\n";
        exit(EXIT_FAILURE);
    }
}

int main()
{
    feenableexcept(FE_ALL_EXCEPT);

    struct sigaction act;
    act.sa_flags = SA_SIGINFO | SA_NODEFER;
    act.sa_sigaction = div0;

    int retn = sigaction(SIGFPE, &act, NULL);
    if(retn == -1)
    {
        perror("sigaction");
        return -1;
    }

    int n1, n2;

    std::cout << "Enter a number: ";
    std::cin >> n1;

    std::cout << "Enter another number to divide by: ";
    std::cin >> n2;

    double div = n1 / 1.0 / n2;
    std::cout << n1 << " / " << n2 << " = " << div << "\n";

    return 0;
}

When I assign the value 0 in the variable n2, the result is, for example: 5 / 0 = inf. But I want to get: You can't divide numbers by zero, idiot!. I used the SIGFPE signal with the FPE_FLTDIV signal code, and I tried to change the double to float, but it still didn't work. I searched on the Internet and I didn't find any solution. Did I miss something? Thanks for the help.

Matan
  • 169
  • 1
  • 10
  • 2
    First, how are you compiling your program? And you can't safely use `cout` in a signal handler. Per [footnote 188 of the C11 standard](https://port70.net/~nsz/c/c11/n1570.html#note188): "Thus, a signal handler cannot, in general, call standard library functions." POSIX allows you to call async-signal-safe functions, but `cout` is not one of them. [Linux provides a list](https://man7.org/linux/man-pages/man7/signal-safety.7.html) of Linux-specific async-signal-safe functions. If it's not on that list, you can't safely use it in a signal handler - which means no C++ streams... – Andrew Henle Feb 28 '21 at 12:40
  • @AndrewHenle so which IO function is signal-safe? I compile the program in g++. – Matan Feb 28 '21 at 12:42
  • `write()`. That's about it. No C++ stream, not even `fprintf()` or `fwrite()`. You can get away with using even `cout` in a small program like this (most of the time...), but when things get more complex it gets dangerous. – Andrew Henle Feb 28 '21 at 12:43
  • I don't know whether that's relevant here, but generally, floating point errors don't throw any signals - the result is just NaN. You might need to change some floating point settings as well. – PMF Feb 28 '21 at 12:43
  • @PMF With GCC, that can depend on the compilation options. See https://gcc.gnu.org/wiki/FloatingPointMath – Andrew Henle Feb 28 '21 at 12:45
  • Why are you doing it like that? Can you not just check the value beforehand? – anastaciu Feb 28 '21 at 12:45
  • `std::cout` and `std::cin` aren't signal-safe, but it doesn't interferes. I changed the `div` to `int` and I got the wanted output. – Matan Feb 28 '21 at 12:55
  • @AndrewHenle I used all of those flags, but it still gave me the same output. – Matan Feb 28 '21 at 13:13
  • I enabled floating-point-exceptions via `feenableexcept` and I got the wanted output. Thanks for the help. – Matan Feb 28 '21 at 13:53
  • @Matan> note that division by zero is undefined behavior, so you cannot get a consistent result. If the compiler can optimize your code by removing the division entirely, it is allowed to do so (and thus you won't get a signal). It might not, but it can - and it might not today, but maybe a future version will. – spectras Feb 28 '21 at 13:57
  • @spectras It's unlikely the compiler will eliminate the division here, since the arguments are coming from the command line. – PMF Feb 28 '21 at 15:46
  • @PMF> unlikely does not mean impossible. And the point is also that whatever specific behavior you witness here and now cannot be extrapolated to any other piece of code, or even to the same piece of code with another compiler. The compiler is allowed to assume that n2 cannot and will not ever be 0, and generate binary accordingly. What this means depends on many details. – spectras Feb 28 '21 at 18:10
  • I edited the code to the correct code. – Matan Mar 02 '21 at 06:00

1 Answers1

1

Why not trying simple if (n2 == 0) std::cout << "You can't divide numbers by zero, i***t!"

Another approach would be if isnan(div) std::cout << "You already divided by zero, i***t!"

The devision 0/0 is silent in double and float. You will receive a NaN instead of any exception. This will allow you to better handle the error.

Added to address the comment

If you want to generate the signal, you need to use all of the variables as integer and avoid optimizations from the compiler. There is very good example in the book "The linux programming interface" which you can find here

jordanvrtanoski
  • 5,104
  • 1
  • 20
  • 29