chicken-users
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Chicken-users] Passing zero-length (sub-)buffers to C functions


From: Jim Ursetto
Subject: Re: [Chicken-users] Passing zero-length (sub-)buffers to C functions
Date: Sun, 17 Feb 2013 12:16:36 -0600

On Feb 17, 2013, at 2:01 AM, Florian Zumbiehl wrote:

> Here is a trivial example that would seem like a natural way to wrap the
> write() syscall (ignoring error handling for the moment) that fails due to
> this mismatch:
> 
> | (define (sys-write fd buf)
> |   ((foreign-lambda int "write" int c-pointer int)
> |     fd
> |     (make-locative buf)
> |     (string-length buf)))
> | 
> | (sys-write 0 "hello world\n")
> | (sys-write 0 "")
> 
> Which gives this output:
> 
> | hello world
> | 
> | Error: (make-locative) out of range

scheme-pointer is a better choice here.

(define (sys-write fd buf)
   ((foreign-lambda int "write" int scheme-pointer int)
     fd
     buf
     (string-length buf)))


> OpenSSL's EVP_CipherFinal_ex() expects a pointer where it puts any
> remaining output that's produced by padding and encrypting the last partial
> plaintext block that OpenSSL holds in its internal buffer. The natural way
> to use that is by adding the amount of output data received so far to the
> pointer to the start of the destination buffer, which gives you a pointer
> to the remaining free space.  Now, if you are using a stream cipher or a
> block cipher with some stream cipher mode, there is zero remaining free
> space, but there is also zero remaining output, so that is still perfectly
> compatible with this approach: You pass the pointer that points "one past
> the end" of the destination buffer (which is guaranteed to be legal in C,
> you just may not dereference it), and EVP_CipherFinal_ex() does not
> dereference it, and everything is fine.

Instead of binding to EVP_CipherFinal_ex() directly, create a small
wrapper in C which takes a pointer to beginning of buffer and an offset,
add them together, and call EVP_CipherFinal_ex().  We do not have a way
to create a shared subslice of a bytevector-like object right now, so
you have to fudge it.

(define (evp-cipher-final buf offset)
 ((foreign-lambda* int ((scheme-pointer ptr) (int offset))
  "return EVP_CipherFinal_ex(ptr+offset);")
  buf offset)
  
(untested, but typical pattern)

I assume you have no need to check that offset <= size buf, as you are somehow
guaranteed this by the algorithm.

By the way, the best way to figure out how to do stuff like this (other than
asking here of course) is to study existing eggs, many of which naturally
have encountered the same problem countless times.  For example, the sendfile
egg answers both your questions in one place:

(let ((write/offset
 (foreign-lambda* int ((int dst) (nonnull-scheme-pointer buff)
                       (unsigned-integer write_offset) (unsigned-integer bytes))
   "C_return(write(dst,buff + write_offset,bytes));")))
 ...)

Jim




reply via email to

[Prev in Thread] Current Thread [Next in Thread]