Austin Group Defect Tracker

Aardvark Mark III


Viewing Issue Simple Details Jump to Notes ] Issue History ] Print ]
ID Category Severity Type Date Submitted Last Update
0000824 [1003.1(2013)/Issue7+TC1] System Interfaces Objection Error 2014-02-12 00:29 2014-04-01 13:32
Reporter eblake View Status public  
Assigned To
Priority normal Resolution Accepted  
Status Interpretation Required  
Name Eric Blake
Organization Red Hat
User Reference ebb.posix_spawn
Section posix_spawn
Page Number 1436
Line Number 47378, 47385
Interp Status Approved
Final Accepted Text See Note: 0002164
Summary 0000824: children should not inherit fcntl file locks from parent calling posix_spawn
Description The posix_spawn interface requires (line 47448):

All process attributes, other than those influenced by the attributes set in the object referenced by attrp as specified above or by the file descriptor manipulations specified in file_actions, shall appear in the new process image as though fork( ) had been called to create a child process and then a member of the exec family of functions had been called by the child process to execute the new process image.

It also requires that whether file_actions is NULL (line 47378) or not (line 47385), that for file descriptors that remain open in the child "all attributes of the corresponding open file descriptions, including file locks (see fcntl( )), shall remain unchanged."

However, this contradicts wording elsewhere in the standard. The description of fcntl states (line 27302): "An exclusive lock shall prevent any other process from setting a shared lock or an exclusive lock on any portion of the protected area." and (line 27337) "Locks are not inherited by a child process."

Likewise, fork states (line 29714) "File locks set by the parent process shall not be inherited by the child process."

Note that locks CAN be inherited across exec (line 26070): "Locks that are not removed by closing of file descriptors remain unchanged." - but in this case, there is only one process owning the lock, since exec is not creating a new process, but reusing an existing one.

Implementation wise, it is impossible to have both parent and child own an exclusive lock across posix_spawn, since only one process can own an exclusive lock at a time; and it does not make sense to inherit shared locks if it is impossible to inherit exclusive locks. Furthermore, the intent of posix_spawn is to create a child that is independent enough from the parent that an implementation might be able to implement it in a manner other than using fork, but that a conforming implementation can be built by using fork (see XRAT B.3.3 for a sample implementation - and overlook the bugs in that sample such as not being robust to a posix_spawn_file_actions_addopen of a file name containing '*'). Since an implementation built on fork drops locks, it makes the most sense to assume the requirement on posix_spawn to preserve locks into the child is a mistake.

To demonstrate existing practice, as further evidence that the standard is wrong, this sample program shows that the parent continues to own the lock (as the parent does not detect any problems in a request to change from shared to exclusive), while the child detects a conflict in trying to request a write lock because the parent still owns a lock. If the child had indeed inherited a lock, then the child would have the same behavior as the parent when calling detect():

#include <stdio.h>
#include <spawn.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
extern char **environ;

static struct flock l;

int detect(void)
{
    l.l_type = F_WRLCK;
    if (fcntl(3, F_GETFD) < 0) {
        perror("fd 3 not open");
        return 1;
    }
    if (fcntl(3, F_GETLK, &l) < 0)
        perror("getlock failed");
    else if (l.l_type == F_UNLCK)
        printf("%d: no lock detected\n", (int) getpid());
    else
        printf("%d: conflicting lock type %d, whence %d, start %lld, "
               "len %lld, owner %d\n",
               (int) getpid(), l.l_type, l.l_whence, (long long) l.l_start,
               (long long) l.l_len, (int) l.l_pid);
    return 0;
}

int main(int argc, char **argv)
{
    l.l_type = F_RDLCK;
    l.l_whence = SEEK_SET;
    l.l_start = 0;
    l.l_len = 0;
    if (argc == 1) {
        printf("In child %d\n", (int) getpid());
        return detect();
    }
    pid_t p;
    char *newargv[] = { argv[0], NULL };
    int fd = open("file", O_RDWR | O_CREAT, 0600);
    if (fd < 0) {
        perror("cannot create file");
        return 1;
    } else if (fd != 3) {
        printf("unexpected fd %d\n", fd);
        return 1;
    }
    if (fcntl(3, F_SETLK, &l) < 0) {
        perror("could not lock");
        return 1;
    }
    detect();
    printf("In parent %d, before spawn, fd = %d\n", (int) getpid(), fd);
    posix_spawn(&p, argv[0], NULL, NULL, newargv, environ);
    sleep(1);
    printf("In parent, after spawn\n");
    detect();
    close(fd);
    unlink("file");
    return 0;
}

$ ./a 1
14034: no lock detected
In parent 14034, before spawn, fd = 3
In child 14035
14035: conflicting lock type 0, whence 0, start 0, len 0, owner 14034
In parent, after spawn
14034: no lock detected
Desired Action At line 47378 page 1436 (posix_spawn DESCRIPTION), change:
For those file descriptors that remain open, all attributes of the corresponding open file descriptions, including file locks (see fcntl( )), shall remain unchanged.
to:
For those file descriptors that remain open, the child process shall not inherit any file locks, but all remaining attributes of the open file descriptions (see fcntl( )) shall remain unchanged.


At line 47385, change:
All attributes of the corresponding open file descriptions, including file locks (see fcntl( )), shall remain unchanged.
to:
The child process shall not inherit any file locks, but all remaining attributes of the corresponding open file descriptions (see fcntl( )) shall remain unchanged.
Tags tc2-2008
Attached Files

- Relationships
related to 0000768New add "fd-private" POSIX locks to spec 

-  Notes
(0002164)
Don Cragun (manager)
2014-02-27 16:21
edited on: 2014-02-27 16:24

Interpretation response
------------------------
The standard states that locks are inherited when using posix_spawn() and are not inherited when using fork()/exec(), and conforming implementations must conform to this. However, concerns have been raised about this which are being referred to the sponsor.

Rationale:
-------------
The behavior seen when creating a child using posix_spawn() and when using fork()/exec() should be the same.

Notes to the Editor (not part of this interpretation):
-------------------------------------------------------
Make the changes suggested in the Desired Action.

(0002169)
ajosey (manager)
2014-02-28 10:19

Interpretation Proposed 28 Feb 2014
(0002211)
ajosey (manager)
2014-04-01 13:32

Interpretation approved 1 April 2014

- Issue History
Date Modified Username Field Change
2014-02-12 00:29 eblake New Issue
2014-02-12 00:29 eblake Name => Eric Blake
2014-02-12 00:29 eblake Organization => Red Hat
2014-02-12 00:29 eblake User Reference => ebb.posix_spawn
2014-02-12 00:29 eblake Section => posix_spawn
2014-02-12 00:29 eblake Page Number => 1436
2014-02-12 00:29 eblake Line Number => 47378, 47385
2014-02-12 00:29 eblake Interp Status => ---
2014-02-12 00:32 eblake Desired Action Updated
2014-02-27 16:21 Don Cragun Note Added: 0002164
2014-02-27 16:21 Don Cragun Status New => Interpretation Required
2014-02-27 16:21 Don Cragun Resolution Open => Accepted
2014-02-27 16:22 eblake Relationship added related to 0000768
2014-02-27 16:22 Don Cragun Interp Status --- => Pending
2014-02-27 16:22 Don Cragun Final Accepted Text => See Note: 0002164
2014-02-27 16:22 Don Cragun Tag Attached: tc2-2008
2014-02-27 16:24 Don Cragun Note Edited: 0002164
2014-02-28 10:19 ajosey Interp Status Pending => Proposed
2014-02-28 10:19 ajosey Note Added: 0002169
2014-04-01 13:32 ajosey Interp Status Proposed => Approved
2014-04-01 13:32 ajosey Note Added: 0002211


Mantis 1.1.6[^]
Copyright © 2000 - 2008 Mantis Group
Powered by Mantis Bugtracker