bug#42345: "Wrong number of arguments to 1"

Taylan Kammer <[email protected]>
Newsgroups gmane.lisp.guile.bugs
Message-ID <[email protected]>
Note: merged with https://bugs.gnu.org/42757 as it's the same bug.

Andy is in CC since we almost certainly need his input. :-)


I've been working on this since a few days (had to learn much about the VM)
and here's an explanation of what's going on.


Firstly here's a minimal procedure that exhibits the bug:

  (define (test x)
    (define (inner-proc a) #f)
    (inner-proc 0 x))


Calling this procedure will always result in the error message:

  Wrong number of arguments to 0


Because the first argument to inner-proc is 0.  Were the first argument x,
then the argument we pass to 'test' would appear in the error message.

That's our bug at a high level: the first argument to inner-proc being
reported as the procedure that raised the error.


The disassembly is quite slim:


Disassembly of #<procedure test (x)> at #x559c98764348:

   0    (instrument-entry 82)
   2    (assert-nargs-ee/locals 2 0)    ;; 2 slots (1 arg)
   3    (make-immediate 1 2)            ;; 0
   4    (handle-interrupts)
   5    (tail-call-label 2)             ;; inner-proc at #x559c98764364

----------------------------------------
Disassembly of inner-proc at #x559c98764364:

   0    (instrument-entry 81)
   2    (assert-nargs-ee/locals 1 0)    ;; 1 slot (0 args)
   3    (make-immediate 0 4)            ;; #f
   4    (handle-interrupts)             
   5    (return-values)                 


Here's some explanations for those who aren't savvy with the VM, starting
from the top.  (The instructions, like assert-nargs-ee/locals, are defined
in libguile/vm-engine.c.)

Ignore the instrument-entry and handle-interrupts instructions.

- (assert-nargs-ee/locals 2 0) checks the number of arguments, ensuring
  that there's a total of 2 slots on the stack. [1]

- (make-immediate 1 2) puts the Scheme number 0 in slot 0. [2]

- (tail-call-label 2) jumps to the beginning of inner-proc. [3]

- (assert-nargs-ee/locals 1 0) checks the number of arguments, ensuring
  that there's a total of 1 slot on the stack. [4]

That's where the error is raised, by calling error_wrong_num_args from
libguile/intrinsics.c, because there's 2 slots on the stack, not 1.
Error_wrong_num_args tries to get the currently executed procedure from
slot 0, and finds the number 0 there, wrongly using that instead.

[1] Slot 0 is usually filled with the procedure being executed itself,
    before it's called, so the number of slots is usually the number of
    arguments plus one.

[2] Slot references in the VM are referenced backwards from N-1 to 0,
    where N is the number of slots.  In our case, as we have 2 slots,
    the number 1 refers to slot 0.  The reason has to do with the Guile
    stack growing downwards.  The constant 0 is represented by 2 because
    of its type tag as an "immediate" int, see scm.h for details.

[3] The 2 represents the relative position of the first instruction of
    inner-proc, in 4-byte units.  It's pretty close, as it's compiled
    right aside our top-level procedure 'test'.  Since we're currently
    on instruction 5 of 'test', and instructions are 4 bytes long, and
    'test' begins at 0x559c98764348, this means we're jumping to:

      0x559c98764348 + 5*4 + 2*4 = 0x559c98764364

    Which happens to be the address of inner-proc, see? :-)

[4] I don't know why only one slot even though it has one argument; it
    should be two slots.  Maybe an optimization, as the compiler decides
    that the procedure doesn't ever need a reference to itself?


To summarize: for some reason the compiler decides to *not* use an extra
slot for the currently-executed procedure when calling inner-proc, which
leads to the first argument to inner-proc (in this case 0) being used as
the "procedure being executed" during error reporting.

Perhaps that optimization (assuming it is one and not simply a bug in
the compiler) should be disabled, or maybe the code shouldn't even
compile since it can be statically proven that a procedure is being
called with the wrong number of arguments.  This is where I defer to
the Guile compiler experts.

-- 
Taylan
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.