FLOATING-POINT-OVERFLOW triggered when calling Foreign Function in GLUT

Bug #2061291 reported by Bibek Panthi
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
SBCL
Invalid
Undecided
Unassigned

Bug Description

# Bug Description

I ran the following code:

```lisp
(require :cffi)

(cffi:define-foreign-library glut
  (:darwin (:framework "GLUT")))

(cffi:load-foreign-library 'glut)

(cffi:defcfun ("glutCreateWindow" create-window) :int
  (title :string))

(create-window "Test Window")
```

I expected the `create-window` function to return 1. If I use `ecl` to run the same code, it succeeds and returns 1. If I write an equivalent C code, it also returns 1.

```c
#include <stdio.h>

int glutCreateWindow(char *name);

int main() {
  int ret = glutCreateWindow(NULL);
  printf("%d", ret);
  return 0;
}
```

Running `gcc -framework GULT test.c -o test && ./test` prints 1.

So, the problem isn't in the GLUT library. But somewhere in SBCL. Since GLUT is installed by default in MacOS the above example must be simple to replicate. It would have been better if I could reproduce the problem without GLUT or reduce the replication code but I couldn't narrow down what triggers this.

# sbcl --version

SBCL 2.4.3

# uname -a

Darwin bpanthi977-mac.local 23.1.0 Darwin Kernel Version 23.1.0: Mon Oct 9 21:27:24 PDT 2023; root:xnu-10002.41.9~6/RELEASE_ARM64_T6000 arm64

# *features*

(:QUICKLISP :ASDF3.3 :ASDF3.2 :ASDF3.1 :ASDF3 :ASDF2 :ASDF :OS-MACOSX :OS-UNIX
 :NON-BASE-CHARS-EXIST-P :ASDF-UNICODE :ARM64 :GENCGC :64-BIT :ANSI-CL :BSD
 :COMMON-LISP :DARWIN :IEEE-FLOATING-POINT :LITTLE-ENDIAN :MACH-O
 :PACKAGE-LOCAL-NICKNAMES :SB-CORE-COMPRESSION :SB-LDB :SB-PACKAGE-LOCKS
 :SB-THREAD :SB-UNICODE :SBCL :UNIX)

Revision history for this message
Stas Boukarev (stassats) wrote :

You need sb-int:with-float-traps-masked

Changed in sbcl:
status: New → Invalid
Revision history for this message
Bibek Panthi (bpanthi977) wrote :

Thanks for the quick reply.

This following code runs. I haven't tested whether it cause any issue down the line for using GLUT though.
```
(sb-int:with-float-traps-masked (:overflow :invalid)
           (create-window "Test Window"))
```

I don't understand why this is needed in SBCL, and not required in ECL or C(?). Could you be kind enough to please explain or link to resources that explain this.

Revision history for this message
Stas Boukarev (stassats) wrote :

I don't know what it does in C or ECL.

Revision history for this message
Christophe Rhodes (csr21-cantab) wrote :

On process startup, the ABI says that the floating point control register will be in a certain state. For x86-64, that is in the System V ABI, available (for example) at https://raw.githubusercontent.com/wiki/hjl-tools/x86-psABI/x86-64-psABI-1.0.pdf -- summarizing, the process is set up so that various exceptional circumstances (e.g. divide by zero, overflow, and so on) do not trigger floating point exceptions.

However, SBCL (mostly) attempts to provide information to the user about these exceptional circumstances; rather than return infinities, not-a-number, or similar, it modifies the floating point control register at startup to turn on those floating point exceptions. So while in C,

float div(float a, float b) { return a/b; }
int main() {
  printf("%f", div(1.0, 0.0));
}

probably prints "+Inf.0" or something, in SBCL

(/ 1.0 0.0)

signals a DIVISION-BY-ZERO condition.

I don't know what glut is doing, but it seems that it is assuming that the state of the control word is to allow overflow and invalid operations without triggering a floating point exception. I don't think this is valid: if the GLUT library requires a particular state, it should ensure it, and restore it on return (the floating point control word is "callee-saved").

Other lisp implementations, or other software in general, may choose to enable a different set of floating point exceptions, or none at all, which can explain the differences in behaviour you are seeing. Your test C program does not set up any floating point exceptions, so it's not very surprising that it doesn't see any.

Revision history for this message
Stas Boukarev (stassats) wrote :

Saving and restoring floating point modes is somewhat expensive, so that has to be taken into account.

Revision history for this message
Bibek Panthi (bpanthi977) wrote :

Thanks for the explanation.

This is definitely something to be fixed in glut.

Revision history for this message
Christophe Rhodes (csr21-cantab) wrote :

> This is definitely something to be fixed in glut.

Well, as Stas says, manipulating the floating point control word is expensive. It might be that GLUT should document the requirements regarding the floating point modes in the control word. Then it would be down to the user to either wrap calls to glut with something that saves and restores the floating point modes (that's `sb-int:with-float-traps-masked`, for example) or else disables them globally for the process, using `sb-int:set-floating-point-modes`, e.g. `(sb-int:set-floating-point-modes :traps nil)`.

Revision history for this message
Anton Lobach (antlob) wrote :

I was also having the same issue when writing bindings to gpt4all and sb-int:with-float-traps-masked fixed it.
Christophe, thanks for your explanation, but I am still a bit confused. Does SBCL raise that exception because the C code actually overflowed or because it potentially could overflow?

To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.