unofficial mirror of bug-guile@gnu.org 
 help / color / mirror / Atom feed
From: Maxime Devos <maximedevos@telenet.be>
To: Matt Wette <matt.wette@gmail.com>,
	27782@debbugs.gnu.org, guile-devel@gnu.org
Subject: bug#27782: patch for mmap and friends
Date: Sat, 14 Jan 2023 16:18:58 +0100	[thread overview]
Message-ID: <445d3567-9bbf-487b-f338-8a16903e9e62__31257.9369683348$1673709624$gmane$org@telenet.be> (raw)
In-Reply-To: <1ee846ab-e9ce-d616-94dd-0056e4b840f9@gmail.com>


[-- Attachment #1.1.1: Type: text/plain, Size: 3395 bytes --]



On 14-01-2023 01:49, Matt Wette wrote:
> Please consider this patch for adding mmap(), munmap() and msync()
>   to libguile/filesys.c.  Included is update for posix.texi and test 
> file mman.test.
> Once included, feature 'mman should be #t.
> 
> Matt




> +  if (SCM_UNBNDP (fd))
> +    c_fd = -1;
> +  else
> +    c_fd = scm_to_int (fd);

Port objects should be accepted too, as previously asked on 
<https://lists.gnu.org/archive/html/guile-user/2022-06/msg00060.html>.
As implied by later comments, using a raw fd causes problems with 
'move->fdes'.  For the remaining response, I'll assume that the function 
accepts ports as well.

  (---)

After this code, the port 'fd' becomes unreferenced by this function.

> +  if (SCM_UNBNDP (offset))
> +    c_offset = 0;
> +  else
> +    c_offset = scm_to_off_t (offset);
> +
> +  if ((c_addr == NULL) && (c_flags & MAP_FIXED))
> +    scm_misc_error ("mmap", "cannot have NULL addr w/ MAP_FIXED", SCM_EOL);

Hence, if the GC is run here, its possible for fd to be automatically 
closed here.

> +  SCM_SYSCALL (c_mem = mmap(c_addr, c_len, c_prot, c_flags, c_fd, c_offset));

As such, C 'mmap' could be called on a closed file descriptor even even 
if the argument to Scheme 'mmap' was an open port, which isn't going to 
work.

(While it is recommended for Scheme code to keep a reference to the port 
to manually close afterwards, to free resources faster than waiting for 
GC, it is not actually required.)

Worse, if the port is closed (by GC), in the mean time another thread 
may have opened a new port, whose file descriptor coincides with c_fd.

To avoid this problem, you can add

   scm_remember_upto_here_1 (fd);

after the SCM_SYSCALL.

Even then, a problem remains -- a concurrent thread might be using 
'move->fdes' to 'move' the file descriptor, hence invalidating c_fd.
Functions like 'scm_seek' handle this with 'scm_dynwind_acquire_port' 
(IIUC, it takes a mutex to delay concurrent 'move->fdes' until finished).

IIUC, the solution then looks like (ignoring wrapping) (the lack of 
scm_remember_upto_here_1 is intentional):

scm_dynwind_begin (0);
scm_dynwind_acquire_port (fd); // (accepts both ports and numbers, IIUC)
// needs to be after scm_dynwind_acquire_port
if (SCM_UNBNDP (fd))
   c_fd = -1;
else
   c_fd = scm_to_int (fd);

SCM_SYSCALL (c_mem = mmap(c_addr, c_len, c_prot, c_flags, c_fd, c_offset));
if (c_mem == MAP_FAILED)
     scm_syserror ("mmap");
scm_dynwind_end ();

(I'm not really familiar with scm_dynwind_begin & friends, I'm mostly 
copy-pasting from libguile/ports.c here.)

> +  if (c_mem == MAP_FAILED)
> +    scm_syserror ("mmap");              /* errno set */
> +
> +  pointer = scm_cell (scm_tc7_pointer, (scm_t_bits) c_mem);
> +  bvec = scm_c_take_typed_bytevector((signed char *) c_mem + c_offset, c_len,
> +                                    SCM_ARRAY_ELEMENT_TYPE_VU8, pointer);

> +  assert(sizeof(void*) <= sizeof(size_t));

IIRC there is a C trick involving fields, arrays and types to check this 
at compile-time instead.  Maybe:

struct whatever {
    /* if availability of zero-length arrays can be assumed */
    int foo[sizeof(size_t) - sizeof(void*)];
    /* alternatively, a weaker but portable check */
    int foo[sizeof(size_t) - sizeof(void*) + 1];
};

Greetings,
Maxime.

[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 929 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 236 bytes --]

  parent reply	other threads:[~2023-01-14 15:18 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <1ee846ab-e9ce-d616-94dd-0056e4b840f9@gmail.com>
2023-01-14  1:00 ` bug#27782: patch for mmap and friends Matt Wette
2023-01-14 15:18 ` Maxime Devos [this message]
     [not found] ` <445d3567-9bbf-487b-f338-8a16903e9e62@telenet.be>
     [not found]   ` <5fda49f2-6e23-9a53-85d2-c1cc38cf0cce@gmail.com>
     [not found]     ` <c7e20254-6387-00c4-ea15-f3ed64668923@gmail.com>
     [not found]       ` <23890f8a-8891-d888-b289-c0d06304fff1@telenet.be>
2023-01-14 23:46         ` Matt Wette
2017-07-21 13:39 bug#27782: [wishlist] scheme level mmap Matt Wette
2023-01-14  0:49 ` bug#27782: patch for mmap and friends Matt Wette

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/guile/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='445d3567-9bbf-487b-f338-8a16903e9e62__31257.9369683348$1673709624$gmane$org@telenet.be' \
    --to=maximedevos@telenet.be \
    --cc=27782@debbugs.gnu.org \
    --cc=guile-devel@gnu.org \
    --cc=matt.wette@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).