(address . guix-patches@gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
Hello Guix,
Record type constructors and accessors are inlined, which is nice for
performance, but causes ABI breakage whenever we change a record type
definition and forget to recompile the files that use it. In that case,
we get an obscure error, sometimes mentioning ‘allocate-struct’ (coming
from the record constructor), sometimes suggesting that the wrong field
of the record is picked up.
This patch introduces ABI checks everywhere a record type constructor is
used. When an ABI mismatch is detected, a specific exception is raised:
Toggle snippet (28 lines)
$ ./pre-inst-env guix system vm gnu/system/examples/bare-bones.tmpl -n
Backtrace:
12 (apply-smob/1 #<catch-closure ec8c80>)
In ice-9/boot-9.scm:
705:2 11 (call-with-prompt _ _ #<procedure default-prompt-handler (k proc)>)
In ice-9/eval.scm:
619:8 10 (_ #(#(#<directory (guile-user) f76140>)))
In guix/ui.scm:
1535:12 9 (run-guix-command _ . _)
In ice-9/boot-9.scm:
829:9 8 (catch _ _ #<procedure 7f9c5e1468b8 at guix/ui.scm:586:2 (key c)> _)
829:9 7 (catch _ _ #<procedure 7f9c5e1468d0 at guix/ui.scm:694:6 (key proc form…> …)
In guix/scripts/system.scm:
1218:8 6 (_)
1088:6 5 (process-action _ _ _)
In guix/store.scm:
1443:24 4 (run-with-store _ _ #:guile-for-build _ #:system _ #:target _)
In guix/scripts/system.scm:
1101:13 3 (_ _)
799:18 2 (perform-action vm #<<operating-system> kernel: #<package linux-libre@4…> …)
In gnu/system/vm.scm:
821:31 1 (system-qemu-image/shared-store-script #<<operating-system> kernel: #<p…> …)
715:2 0 (virtualized-operating-system _ _ _)
gnu/system/vm.scm:715:2: In procedure virtualized-operating-system:
ERROR: #<record-type <operating-system>>: record ABI mismatch; recompilation needed
In this case that’s because I modified <operating-system> without
recompiling gnu/system/vm.scm. Once I’ve rebuilt it, everything is
alright.
The shortcoming of the approach is that accessors do not perform these
ABI checks, so we can still silently miss ABI mismatch issues, but I
think it would be too costly to do that. The overhead of those checks
in constructors is probably OK since we’re allocating anyway.
This is what constructors now expand to:
Toggle snippet (19 lines)
scheme@(guix records)> (define-record-type* <thing> thing make-thing
thing?
(name thing-name (default 32))
(port thing-port
(default (current-output-port)) (thunked)))
scheme@(guix records)> ,optimize (thing)
$40 = (begin
(if (eq? #{% <thing> abi-cookie}# 1515259617)
(if #f #f)
(throw 'record-abi-mismatch-error <thing>))
(let ((s (allocate-struct <thing> 2)))
(struct-set! s 0 32)
(struct-set!
s
1
(lambda () (current-output-port)))
s))
Thoughts?
Ludo’.
Ludovic Courtès (1):
records: Insert record type ABI checks in constructors.
guix/records.scm | 54 ++++++++++++++++++++++++++++++++++++++++++++---
tests/records.scm | 30 +++++++++++++++++++++++++-
2 files changed, 80 insertions(+), 4 deletions(-)
--
2.17.0