Monorepo for Aesthetic.Computer aesthetic.computer
4
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix: mask SBCL FP traps around all QuickJS calls

SBCL enables floating-point exception traps by default. QuickJS does
normal FP math (NaN, Inf) that triggers SIGFPE under SBCL's traps.
Wrap all qjs-eval and lifecycle calls with sb-int:with-float-traps-masked.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

+27 -15
+27 -15
fedac/native/cl/js-bridge.lisp
··· 8 8 9 9 (defvar *ctx* nil "Active QuickJS context") 10 10 (defvar *rt* nil "Active QuickJS runtime") 11 + 12 + (defmacro with-fp-traps-masked (&body body) 13 + "Disable SBCL floating-point exception traps around BODY. 14 + QuickJS does normal FP math (NaN, Inf) that triggers SBCL's traps." 15 + `(sb-int:with-float-traps-masked (:invalid :overflow :divide-by-zero :underflow :inexact) 16 + ,@body)) 11 17 (defvar *graph* nil "Current graph context for JS callbacks") 12 18 (defvar *fb* nil "Current framebuffer for JS callbacks") 13 19 (defvar *audio* nil "Audio engine for JS callbacks") ··· 169 175 (ac-native.quickjs:qjs-set-global-int *ctx* "__screen_h" screen-h) 170 176 ;; Eval the API bootstrap JS 171 177 (let ((api-code (build-api-js))) 172 - (ac-native.quickjs:qjs-eval *ctx* api-code (length api-code) "<api-init>" 0)) 178 + (with-fp-traps-masked 179 + (ac-native.quickjs:qjs-eval *ctx* api-code (length api-code) "<api-init>" 0))) 173 180 (format *error-output* "[js-bridge] QuickJS initialized (~Dx~D)~%" screen-w screen-h) 174 181 (force-output *error-output*)) 175 182 ··· 223 230 if (typeof leave === 'function') globalThis.__piece_leave = leave;~%" 224 231 stripped)) 225 232 (bytes (sb-ext:string-to-octets wrapper :external-format :utf-8))) 226 - (let ((rc (ac-native.quickjs:qjs-eval *ctx* wrapper (length bytes) 227 - path 0))) ; 0 = JS_EVAL_TYPE_GLOBAL 233 + (let ((rc (with-fp-traps-masked 234 + (ac-native.quickjs:qjs-eval *ctx* wrapper (length bytes) 235 + path 0)))) ; 0 = JS_EVAL_TYPE_GLOBAL 228 236 (when (= rc -1) 229 237 (format *error-output* "[js-bridge] Failed to load ~A~%" path) 230 238 (return-from js-load-piece nil)))) ··· 243 251 (defun js-boot () 244 252 "Call the piece's boot() with the API object." 245 253 (when *has-boot* 246 - (ac-native.quickjs:qjs-call-with-api *ctx* "__piece_boot") 247 - (ac-native.quickjs:qjs-execute-pending *ctx*))) 254 + (with-fp-traps-masked 255 + (ac-native.quickjs:qjs-call-with-api *ctx* "__piece_boot") 256 + (ac-native.quickjs:qjs-execute-pending *ctx*)))) 248 257 249 258 (defun js-paint (paint-count) 250 259 "Call the piece's paint() with the API object." 251 260 (when *has-paint* 252 - (ac-native.quickjs:qjs-set-global-int *ctx* "__paintCount" paint-count) 253 - (ac-native.quickjs:qjs-call-with-api *ctx* "__piece_paint") 254 - (ac-native.quickjs:qjs-execute-pending *ctx*))) 261 + (with-fp-traps-masked 262 + (ac-native.quickjs:qjs-set-global-int *ctx* "__paintCount" paint-count) 263 + (ac-native.quickjs:qjs-call-with-api *ctx* "__piece_paint") 264 + (ac-native.quickjs:qjs-execute-pending *ctx*)))) 255 265 256 266 (defun js-act (event-type event-key event-code) 257 267 "Call the piece's act() with an event." 258 268 (when *has-act* 259 - (ac-native.quickjs:qjs-set-global-int *ctx* "__evType" event-type) 260 - (ac-native.quickjs:qjs-set-global-string *ctx* "__evKey" event-key) 261 - (ac-native.quickjs:qjs-set-global-int *ctx* "__evCode" event-code) 262 - (ac-native.quickjs:qjs-call-with-api *ctx* "__piece_act") 263 - (ac-native.quickjs:qjs-execute-pending *ctx*))) 269 + (with-fp-traps-masked 270 + (ac-native.quickjs:qjs-set-global-int *ctx* "__evType" event-type) 271 + (ac-native.quickjs:qjs-set-global-string *ctx* "__evKey" event-key) 272 + (ac-native.quickjs:qjs-set-global-int *ctx* "__evCode" event-code) 273 + (ac-native.quickjs:qjs-call-with-api *ctx* "__piece_act") 274 + (ac-native.quickjs:qjs-execute-pending *ctx*)))) 264 275 265 276 (defun js-sim () 266 277 "Call the piece's sim()." 267 278 (when *has-sim* 268 - (ac-native.quickjs:qjs-call-with-api *ctx* "__piece_sim") 269 - (ac-native.quickjs:qjs-execute-pending *ctx*))) 279 + (with-fp-traps-masked 280 + (ac-native.quickjs:qjs-call-with-api *ctx* "__piece_sim") 281 + (ac-native.quickjs:qjs-execute-pending *ctx*)))) 270 282 271 283 ;;; ── Build the JS API object ── 272 284 ;;; This JS code creates __ac_api with all the graphics/audio/system