[cffi-devel] Fwd: CFFI should defend itself against fragile handling of narrow return types in SBCL on x86!

Jean-Claude Beaudoin jean.claude.beaudoin at gmail.com
Sun Apr 12 06:24:12 UTC 2009


Hello Luis,

Sorry for the long silence, I was held up elsewhere.

On Mon, Mar 30, 2009 at 9:05 AM, Luís Oliveira <luismbo at gmail.com> wrote:

> 2009/3/28 Jean-Claude Beaudoin <jean.claude.beaudoin at gmail.com>:
> > Recent versions of GCC appear to be leaving spurious bits in the %eax
> > register used to return the value of a C function on x86 based platforms
> > when the return type is narrower than 32 bits (ie: short or char).
>
> Is that a GCC bug or is that behaviour here to stay?


As far as GCC is concerned there is no bug of its own in that area.
The oldest version of GCC I still have access to (3.4.6) shows that
even back then GCC emitted code on the caller side that always
extracted from %eax only the relevant bits and widened properly
the result.  I suspect that GCC has always done this although maybe
not with the most efficient instruction sequence.  What changed,
starting in 4.1.X (I think),  is that GCC started to use the upper part
of %eax on the callee side trusting that this would not influence the
caller side.  I would even say that 4.3 started to use this behavior
extensively.


> I'd like to make this work for all the supported Lisps but only when
> necessary. Can we check at compile time whether this workaround is
> needed? For example, would the following work? Define abs() with a
> short/char return value and check whether the upper bits are masked
> away.


I just tried your idea and it works.  Here is the code I used:


--------------------------------------------------
;;~/bin/sbcl

(define-alien-routine ("abs" my-uabs) unsigned-char (i int :in))
(define-alien-routine ("abs" my-abs) char (i int :in))

(format t "~%(my-abs #x0101) = ~S~%" (my-abs #x0101))
(format t "~%(my-abs #x080) = ~S~%" (my-abs #x080))
(format t "~%(my-uabs #x0101) = ~S~%" (my-uabs #x0101))
(format t "~%(my-uabs #x181) = ~S~%" (my-uabs #x181))


(let ((val (my-uabs #x181)))
  (cond ((= #x81 val)
     (format t "unsigned-char widened properly.~%")
     )
    ((= #x181 val)
     (format t "unsigned-char NOT widened properly.~%")
     )
    ((> 0 val)
     (format t "unsigned-char got sign extended!~%")
     )
    (t (format t "Stupefying result! val = ~D (#x~X).~%" val val))
    )
  )


;(quit)
--------------------------------------------------------

The proper results should be 1, -128, 1, 129.

SBCL got partially fixed in 1.0.25 for the "signed char" and "signed short"
case, and
I submitted a patch to be hopefully included in 1.0.28 for the "unsigned"
cases.
Prior to these, every other version of SBCL out there has the weakness.
By the way, CMUCL has the same problem.

Cheers,

Jean-Claude Beaudoin
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mailman.common-lisp.net/pipermail/cffi-devel/attachments/20090412/996a60f0/attachment.html>


More information about the cffi-devel mailing list