Repository: jqlang/jq

Problem statement:
Floating point exception in builtin.c
Tested against the current master and jqplay.org

```
$ ./jq -n 'infinite%-1'                                                                                
Floating point exception
```

gdb

```
Program received signal SIGFPE, Arithmetic exception.
0x0000000000493836 in f_mod (jq=<optimized out>, input=..., a=..., b=...) at src/builtin.c:263
263         return jv_number((intmax_t)jv_number_value(a) % (intmax_t)jv_number_value(b));
(gdb) bt
#0  0x0000000000493836 in f_mod (jq=<optimized out>, input=..., a=..., b=...) at src/builtin.c:263
#1  0x0000000000415510 in jq_next (jq=jq@entry=0x716150) at src/execute.c:786
#2  0x00000000004077e8 in process (jq=0x716150, value=..., flags=flags@entry=0, dumpopts=dumpopts@entry=645) at src/main.c:151
#3  0x0000000000406607 in main (argc=<optimized out>, argv=<optimized out>) at src/main.c:546
(gdb) l
 258     static jv f_mod(jq_state *jq, jv input, jv a, jv b) {
 259       jv_free(input);
 260       if (jv_get_kind(a) == JV_KIND_NUMBER && jv_get_kind(b) == JV_KIND_NUMBER) {
 261         if ((intmax_t)jv_number_value(b) == 0)
 262           return type_error2(a, b, "cannot be divided (remainder) because the divisor is zero");
>263         return jv_number((intmax_t)jv_number_value(a) % (intmax_t)jv_number_value(b));
 264       } else {
 265         return type_error2(a, b, "cannot be divided (remainder)");
 266       }
 267     }
```

Possibly related to #750 ?

Floating point exception in builtin.c
Tested against the current master and jqplay.org

```
$ ./jq -n 'infinite%-1'                                                                                
Floating point exception
```

gdb

```
Program received signal SIGFPE, Arithmetic exception.
0x0000000000493836 in f_mod (jq=<optimized out>, input=..., a=..., b=...) at src/builtin.c:263
263         return jv_number((intmax_t)jv_number_value(a) % (intmax_t)jv_number_value(b));
(gdb) bt
#0  0x0000000000493836 in f_mod (jq=<optimized out>, input=..., a=..., b=...) at src/builtin.c:263
#1  0x0000000000415510 in jq_next (jq=jq@entry=0x716150) at src/execute.c:786
#2  0x00000000004077e8 in process (jq=0x716150, value=..., flags=flags@entry=0, dumpopts=dumpopts@entry=645) at src/main.c:151
#3  0x0000000000406607 in main (argc=<optimized out>, argv=<optimized out>) at src/main.c:546
(gdb) l
 258     static jv f_mod(jq_state *jq, jv input, jv a, jv b) {
 259       jv_free(input);
 260       if (jv_get_kind(a) == JV_KIND_NUMBER && jv_get_kind(b) == JV_KIND_NUMBER) {
 261         if ((intmax_t)jv_number_value(b) == 0)
 262           return type_error2(a, b, "cannot be divided (remainder) because the divisor is zero");
>263         return jv_number((intmax_t)jv_number_value(a) % (intmax_t)jv_number_value(b));
 264       } else {
 265         return type_error2(a, b, "cannot be divided (remainder)");
 266       }
 267     }
```

Possibly related to #750 ?



Hints:
I just ran into this too. The issue is that due to the size of the dividend and the fact that the negative divisor inverts the sign, the result can not be represented in intmax_t.
~~Yeah, so we need to disable generation of `SIGFPE`, with `fedisableexcept(FE_ALL_EXCEPT)`.  If not available, I guess we can always ignore `SIGFPE`.~~
Something like the following hack fixes this particular crash, but the sin here is to have defined the `%` remainder operator in terms of the C integer remainder operator rather than using `fmod()` from `libm`, so it might be better to actually re-implement the `f_mod()` function:

```
diff --git a/src/builtin.c b/src/builtin.c
index 01528b6..ca1ba72 100644
--- a/src/builtin.c
+++ b/src/builtin.c
@@ -349,6 +349,9 @@ static jv f_mod(jq_state *jq, jv input, jv a, jv b) {
   if (jv_get_kind(a) == JV_KIND_NUMBER && jv_get_kind(b) == JV_KIND_NUMBER) {
     if ((intmax_t)jv_number_value(b) == 0)
       return type_error2(a, b, "cannot be divided (remainder) because the divisor is zero");
+    double x = fmod(jv_number_value(a), jv_number_value(b));
+    if (isnan(x))
+      return type_error2(a, b, "integer overflow computing remainder");
     return jv_number((intmax_t)jv_number_value(a) % (intmax_t)jv_number_value(b));
   } else {
     return type_error2(a, b, "cannot be divided (remainder)");
```
I just ran into this too. The issue is that due to the size of the dividend and the fact that the negative divisor inverts the sign, the result can not be represented in intmax_t.
~~Yeah, so we need to disable generation of `SIGFPE`, with `fedisableexcept(FE_ALL_EXCEPT)`.  If not available, I guess we can always ignore `SIGFPE`.~~
Something like the following hack fixes this particular crash, but the sin here is to have defined the `%` remainder operator in terms of the C integer remainder operator rather than using `fmod()` from `libm`, so it might be better to actually re-implement the `f_mod()` function:

```
diff --git a/src/builtin.c b/src/builtin.c
index 01528b6..ca1ba72 100644
--- a/src/builtin.c
+++ b/src/builtin.c
@@ -349,6 +349,9 @@ static jv f_mod(jq_state *jq, jv input, jv a, jv b) {
   if (jv_get_kind(a) == JV_KIND_NUMBER && jv_get_kind(b) == JV_KIND_NUMBER) {
     if ((intmax_t)jv_number_value(b) == 0)
       return type_error2(a, b, "cannot be divided (remainder) because the divisor is zero");
+    double x = fmod(jv_number_value(a), jv_number_value(b));
+    if (isnan(x))
+      return type_error2(a, b, "integer overflow computing remainder");
     return jv_number((intmax_t)jv_number_value(a) % (intmax_t)jv_number_value(b));
   } else {
     return type_error2(a, b, "cannot be divided (remainder)");
```

Patch:
diff --git a/src/builtin.c b/src/builtin.c
index 6fa1c52f6d..649dec3a5c 100644
--- a/src/builtin.c
+++ b/src/builtin.c
@@ -396,9 +396,11 @@ static jv f_divide(jq_state *jq, jv input, jv a, jv b) {
 static jv f_mod(jq_state *jq, jv input, jv a, jv b) {
   jv_free(input);
   if (jv_get_kind(a) == JV_KIND_NUMBER && jv_get_kind(b) == JV_KIND_NUMBER) {
-    if ((intmax_t)jv_number_value(b) == 0)
+    intmax_t bi = (intmax_t)jv_number_value(b);
+    if (bi == 0)
       return type_error2(a, b, "cannot be divided (remainder) because the divisor is zero");
-    jv r = jv_number((intmax_t)jv_number_value(a) % (intmax_t)jv_number_value(b));
+    // Check if the divisor is -1 to avoid overflow when the dividend is INTMAX_MIN.
+    jv r = jv_number(bi == -1 ? 0 : (intmax_t)jv_number_value(a) % bi);
     jv_free(a);
     jv_free(b);
     return r;


Test patch:
diff --git a/tests/jq.test b/tests/jq.test
index 9aa435a2ea..86239fa5a5 100644
--- a/tests/jq.test
+++ b/tests/jq.test
@@ -540,6 +540,10 @@ null
 null
 172
 
+[(infinite, -infinite) % (1, -1)]
+null
+[0,0,0,0]
+
 1 + tonumber + ("10" | tonumber)
 4
 15