Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python Enhancement Proposals

PEP 433 – Einfachere Unterdrückung der Vererbung von Dateideskriptoren

Autor:
Victor Stinner <vstinner at python.org>
Status:
Abgelöst
Typ:
Standards Track
Erstellt:
10-Jan-2013
Python-Version:
3.4
Ersetzt-Durch:
446

Inhaltsverzeichnis

Zusammenfassung

Füge einen neuen optionalen Parameter cloexec zu Funktionen hinzu, die Dateideskriptoren erstellen, füge verschiedene Möglichkeiten hinzu, Standardwerte dieses Parameters zu ändern, und füge vier neue Funktionen hinzu

  • os.get_cloexec(fd)
  • os.set_cloexec(fd, cloexec=True)
  • sys.getdefaultcloexec()
  • sys.setdefaultcloexec(cloexec)

Begründung

Ein Dateideskriptor hat ein Close-on-Exec-Flag, das angibt, ob der Dateideskriptor vererbt wird oder nicht.

Unter UNIX wird der Dateideskriptor nicht vererbt, wenn das Close-on-Exec-Flag gesetzt ist: Er wird bei der Ausführung von Kindprozessen geschlossen; andernfalls wird der Dateideskriptor von Kindprozessen geerbt.

Unter Windows wird der Dateideskriptor nicht vererbt, wenn das Close-on-Exec-Flag gesetzt ist; der Dateideskriptor wird von Kindprozessen geerbt, wenn das Close-on-Exec-Flag gelöscht ist und wenn CreateProcess() mit dem Parameter bInheritHandles auf TRUE gesetzt aufgerufen wird (wenn subprocess.Popen beispielsweise mit close_fds=False erstellt wird). Windows hat kein "Close-on-Exec"-Flag, sondern ein Vererbungsflag, das einfach den umgekehrten Wert hat. Das Setzen des Close-on-Exec-Flags bedeutet beispielsweise das Löschen des HANDLE_FLAG_INHERIT-Flags eines Handles.

Status in Python 3.3

Unter UNIX schließt das `subprocess`-Modul seit Python 3.2 standardmäßig Dateideskriptoren größer als 2 [1]. Alle vom Elternprozess erstellten Dateideskriptoren werden im Kindprozess automatisch geschlossen.

xmlrpc.server.SimpleXMLRPCServer setzt das Close-on-Exec-Flag des lauschenden Sockets, die Elternklasse socketserver.TCPServer setzt dieses Flag nicht.

Es gibt andere Fälle, bei denen beim Erstellen eines Subprozesses oder beim Ausführen eines neuen Programms Dateideskriptoren nicht geschlossen werden: Funktionen der Familien os.spawn*() und os.exec*() und Drittanbieter-Module, die exec() oder fork() + exec() aufrufen. In diesem Fall werden Dateideskriptoren zwischen dem Eltern- und dem Kindprozess geteilt, was normalerweise unerwartet ist und verschiedene Probleme verursacht.

Dieses PEP schlägt vor, die mit der Änderung in `subprocess` in Python 3.2 begonnene Arbeit fortzusetzen, um das Problem in jeglichem Code zu beheben und nicht nur in Code, der `subprocess` verwendet.

Probleme mit vererbten Dateideskriptoren

Das Schließen des Dateideskriptors im Elternprozess schließt die zugehörige Ressource (Datei, Socket usw.) nicht, da sie im Kindprozess noch geöffnet ist.

Der lauschende Socket von `TCPServer` wird bei exec() nicht geschlossen: Der Kindprozess kann Verbindungen von neuen Clients empfangen; wenn der Elternprozess den lauschenden Socket schließt und einen neuen lauschenden Socket an derselben Adresse erstellt, würde er eine Fehlermeldung "Adresse wird bereits verwendet" erhalten.

Das Nichtschließen von Dateideskriptoren kann zu Ressourcenerschöpfung führen: Selbst wenn der Elternprozess alle Dateien schließt, kann die Erstellung eines neuen Dateideskriptors mit "zu viele Dateien" fehlschlagen, da Dateien im Kindprozess noch geöffnet sind.

Siehe auch folgende Probleme

Sicherheit

Das Leck von Dateideskriptoren ist eine schwerwiegende Sicherheitslücke. Ein nicht vertrauenswürdiger Kindprozess kann sensible Daten wie Passwörter lesen und über geleckte Dateideskriptoren die Kontrolle über den Elternprozess übernehmen. Es ist beispielsweise eine bekannte Schwachstelle, um aus einem chroot zu entkommen.

Siehe auch die CERT-Empfehlung: FIO42-C. Stellen Sie sicher, dass Dateien ordnungsgemäß geschlossen werden, wenn sie nicht mehr benötigt werden.

Beispiele für Schwachstellen

Atomarität

Die Verwendung von fcntl() zum Setzen des Close-on-Exec-Flags ist in einer Multithread-Anwendung nicht sicher. Wenn ein Thread fork() und exec() zwischen der Erstellung des Dateideskriptors und dem Aufruf von fcntl(fd, F_SETFD, new_flags) aufruft: Der Dateideskriptor wird vom Kindprozess geerbt. Moderne Betriebssysteme bieten Funktionen, um das Flag während der Erstellung des Dateideskriptors zu setzen, was die Race Condition vermeidet.

Portabilität

Python 3.2 fügte das Flag socket.SOCK_CLOEXEC hinzu, Python 3.3 fügte das Flag os.O_CLOEXEC und die Funktion os.pipe2() hinzu. Es ist bereits möglich, das Close-on-Exec-Flag atomar in Python 3.3 zu setzen, wenn eine Datei geöffnet und eine Pipe oder ein Socket erstellt wird.

Das Problem ist, dass diese Flags und Funktionen nicht portabel sind: nur neuere Versionen von Betriebssystemen unterstützen sie. O_CLOEXEC und SOCK_CLOEXEC Flags werden von alten Linux-Versionen ignoriert und daher muss das FD_CLOEXEC Flag mit fcntl(fd, F_GETFD) überprüft werden. Wenn der Kernel das O_CLOEXEC oder SOCK_CLOEXEC Flag ignoriert, ist ein Aufruf von fcntl(fd, F_SETFD, flags) erforderlich, um das Close-on-Exec-Flag zu setzen.

Hinweis

OpenBSD älter als 5.2 schließt den Dateideskriptor mit gesetztem Close-on-Exec-Flag nicht, wenn fork() vor exec() verwendet wird, aber es funktioniert korrekt, wenn exec() ohne fork() aufgerufen wird. Versuchen Sie openbsd_bug.py.

Umfang

Anwendungen müssen immer noch explizit Dateideskriptoren nach einem fork() schließen. Das Close-on-Exec-Flag schließt Dateideskriptoren nur nach exec(), und somit nach fork() + exec().

Dieses PEP ändert nur das Close-on-Exec-Flag von Dateideskriptoren, die von der Python-Standardbibliothek oder von Modulen, die die Standardbibliothek verwenden, erstellt werden. Drittanbieter-Module, die die Standardbibliothek nicht verwenden, sollten angepasst werden, um diesem PEP zu entsprechen. Die neue Funktion os.set_cloexec() kann beispielsweise verwendet werden.

Hinweis

Siehe Schließen von Dateideskriptoren nach fork für eine mögliche Lösung für fork() ohne exec().

Vorschlag

Füge einen neuen optionalen Parameter cloexec zu Funktionen hinzu, die Dateideskriptoren erstellen, und verschiedene Möglichkeiten, den Standardwert dieses Parameters zu ändern.

Füge neue Funktionen hinzu

  • os.get_cloexec(fd:int) -> bool: Holt das Close-on-Exec-Flag eines Dateideskriptors. Nicht auf allen Plattformen verfügbar.
  • os.set_cloexec(fd:int, cloexec:bool=True): Setzt oder löscht das Close-on-Exec-Flag eines Dateideskriptors. Nicht auf allen Plattformen verfügbar.
  • sys.getdefaultcloexec() -> bool: Holt den aktuellen Standardwert des cloexec-Parameters
  • sys.setdefaultcloexec(cloexec: bool): Setzt den Standardwert des cloexec-Parameters

Füge einen neuen optionalen Parameter cloexec zu

  • asyncore.dispatcher.create_socket()
  • io.FileIO
  • io.open()
  • open()
  • os.dup()
  • os.dup2()
  • os.fdopen()
  • os.open()
  • os.openpty()
  • os.pipe()
  • select.devpoll()
  • select.epoll()
  • select.kqueue()
  • socket.socket()
  • socket.socket.accept()
  • socket.socket.dup()
  • socket.socket.fromfd
  • socket.socketpair()

Der Standardwert des cloexec-Parameters ist sys.getdefaultcloexec().

Füge eine neue Kommandozeilenoption -e und eine Umgebungsvariable PYTHONCLOEXEC hinzu, um das Close-on-Exec-Flag standardmäßig zu setzen.

subprocess löscht das Close-on-Exec-Flag von Dateideskriptoren des Parameters pass_fds.

Alle Funktionen, die Dateideskriptoren in der Standardbibliothek erstellen, müssen den Standardwert des cloexec-Parameters respektieren: sys.getdefaultcloexec().

Dateideskriptoren 0 (stdin), 1 (stdout) und 2 (stderr) werden voraussichtlich vererbt, aber Python behandelt sie nicht unterschiedlich. Wenn os.dup2() verwendet wird, um Standardströme zu ersetzen, muss cloexec=False explizit angegeben werden.

Nachteile des Vorschlags

  • Es ist nicht mehr möglich zu wissen, ob das Close-on-Exec-Flag für einen neu erstellten Dateideskriptor gesetzt wird oder nicht, nur durch Lesen des Quellcodes.
  • Wenn die Vererbung eines Dateideskriptors wichtig ist, muss der cloexec-Parameter nun explizit angegeben werden, oder die Bibliothek oder die Anwendung wird je nach Standardwert des cloexec-Parameters nicht funktionieren.

Alternativen

Vererbung standardmäßig aktiviert, Standard kann nur auf True gesetzt werden

Füge einen neuen optionalen Parameter cloexec zu Funktionen hinzu, die Dateideskriptoren erstellen. Der Standardwert des cloexec-Parameters ist False, und dieser Standard kann nicht geändert werden. Die standardmäßige Aktivierung der Dateideskriptor-Vererbung ist auch der Standard unter POSIX und Windows. Diese Alternative ist die konservativste Option.

Diese Option löst die im Abschnitt Begründung aufgeführten Probleme nicht, sie bietet lediglich eine Hilfe zur Behebung. Alle Funktionen, die Dateideskriptoren erstellen, müssen geändert werden, um cloexec=True in jedem von einer Anwendung verwendeten Modul zu setzen, um all diese Probleme zu beheben.

Vererbung standardmäßig aktiviert, Standard kann nur auf True gesetzt werden

Diese Alternative basiert auf dem Vorschlag: Der einzige Unterschied ist, dass sys.setdefaultcloexec() kein Argument nimmt, es kann nur verwendet werden, um den Standardwert des cloexec-Parameters auf True zu setzen.

Vererbung standardmäßig deaktivieren

Diese Alternative basiert auf dem Vorschlag: Der einzige Unterschied ist, dass der Standardwert des cloexec-Parameters True ist (statt False).

Wenn eine Datei von Kindprozessen geerbt werden soll, kann der Parameter cloexec=False verwendet werden.

Vorteile des standardmäßigen Setzens des Close-on-Exec-Flags

Nachteile des standardmäßigen Setzens des Close-on-Exec-Flags

  • Es verstößt gegen das Prinzip der geringsten Überraschung. Entwickler, die das `os`-Modul verwenden, erwarten möglicherweise, dass Python dem POSIX-Standard entspricht und dass das Close-on-Exec-Flag nicht standardmäßig gesetzt ist.
  • Das `os`-Modul ist als dünne Hülle für Systemaufrufe (für Funktionen der C-Standardbibliothek) geschrieben. Wenn atomare Flags zum Setzen des Close-on-Exec-Flags nicht unterstützt werden (siehe Anhang: Betriebssystemunterstützung), kann ein einzelner Python-Funktionsaufruf 2 oder 3 Systemaufrufe erfordern (siehe Abschnitt Leistung).
  • Zusätzliche Systemaufrufe, falls vorhanden, können Python verlangsamen: siehe Leistung.

Abwärtskompatibilität: Nur wenige Programme sind auf die Vererbung von Dateideskriptoren angewiesen, und sie übergeben nur wenige Dateideskriptoren, normalerweise nur einen. Diese Programme schlagen sofort mit einem EBADF-Fehler fehl, und es wird einfach sein, sie zu beheben: Füge den Parameter cloexec=False hinzu oder verwende os.set_cloexec(fd, False).

Das `subprocess`-Modul wird ohnehin geändert, um das Close-on-Exec-Flag für Dateideskriptoren zu löschen, die im Parameter pass_fds des Popen-Konstruktors aufgeführt sind. Daher ist es möglich, dass diese Programme keine Korrektur benötigen, wenn sie das `subprocess`-Modul verwenden.

Schließe Dateideskriptoren nach fork

Dieses PEP behebt keine Probleme mit Anwendungen, die fork() ohne exec() verwenden. Python benötigt einen generischen Prozess zur Registrierung von Rückruffunktionen, die nach einem fork aufgerufen werden, siehe #16500: Hinzufügen eines atfork-Moduls. Eine solche Registrierung könnte verwendet werden, um Dateideskriptoren direkt nach einem fork() zu schließen.

Nachteile

  • Es löst das Problem unter Windows nicht: fork() existiert unter Windows nicht
  • Diese Alternative löst das Problem nicht für Programme, die exec() ohne fork() verwenden.
  • Ein Drittanbieter-Modul kann direkt die C-Funktion fork() aufrufen, die keine "atfork"-Rückruffunktionen aufruft.
  • Alle Funktionen, die Dateideskriptoren erstellen, müssen geändert werden, um einen Rückruf zu registrieren und dann ihren Rückruf zu deregistrieren, wenn die Datei geschlossen wird. Oder es muss eine Liste aller offenen Dateideskriptoren geführt werden.
  • Das Betriebssystem ist besser geeignet als Python, um Dateideskriptoren automatisch zu schließen. Es ist beispielsweise nicht einfach, eine Race Condition zwischen dem Schließen der Datei und dem Deregistrieren des Rückrufs, der die Datei schließt, zu vermeiden.

open(): füge das "e"-Flag zum Modus hinzu

Ein neuer Modus "e" würde das Close-on-Exec-Flag setzen (bestmögliche Bemühung).

Diese Alternative löst das Problem nur für open(). `socket.socket()` und `os.pipe()` haben beispielsweise keinen mode-Parameter.

Seit Version 2.7 unterstützt die GNU libc das Flag "e" für fopen(). Es verwendet O_CLOEXEC, falls verfügbar, oder verwendet fcntl(fd, F_SETFD, FD_CLOEXEC). Mit Visual Studio akzeptiert `fopen()` ein "N"-Flag, das O_NOINHERIT verwendet.

Bikeshedding am Namen des neuen Parameters

  • inherit, inherited: näher an der Windows-Definition
  • sensibel
  • sterile: „produziert keine Nachkommen.“

Anwendungen, die die Vererbung von Dateideskriptoren nutzen

Die meisten Entwickler wissen nicht, dass Dateideskriptoren standardmäßig vererbt werden. Die meisten Programme sind nicht auf die Vererbung von Dateideskriptoren angewiesen. Beispielsweise wurde subprocess.Popen in Python 3.2 geändert, um standardmäßig alle Dateideskriptoren größer als 2 im Kindprozess zu schließen. Bisher hat sich kein Benutzer über diese Verhaltensänderung beschwert.

Netzwerkserver, die fork verwenden, möchten möglicherweise den Client-Socket an den Kindprozess übergeben. Zum Beispiel übergibt ein CGI-Server unter UNIX den Client-Socket über die Dateideskriptoren 0 (stdin) und 1 (stdout) mittels dup2().

Um auf eine eingeschränkte Ressource zuzugreifen, wie z. B. das Erstellen eines Sockets, der auf einem TCP-Port unter 1024 lauscht, oder das Lesen einer Datei mit sensiblen Daten wie Passwörtern, ist eine gängige Praxis: Als Root-Benutzer starten, einen Dateideskriptor erstellen, einen Kindprozess erstellen, die Berechtigungen fallen lassen (z. B. den aktuellen Benutzer ändern), den Dateideskriptor an den Kindprozess übergeben und den Elternprozess beenden.

Sicherheit ist in einem solchen Anwendungsfall sehr wichtig: Das Leck eines anderen Dateideskriptors wäre eine kritische Sicherheitslücke (siehe Sicherheit). Der Root-Prozess beendet sich möglicherweise nicht, sondern überwacht den Kindprozess und startet einen neuen Kindprozess neu und übergibt denselben Dateideskriptor, wenn der vorherige Kindprozess abgestürzt ist.

Beispiele für Programme, die Dateideskriptoren über eine Kommandozeilenoption vom Elternprozess übernehmen

  • gpg: --status-fd <fd>, --logger-fd <fd>, usw.
  • openssl: -pass fd:<fd>
  • qemu: -add-fd <fd>
  • valgrind: --log-fd=<fd>, --input-fd=<fd>, usw.
  • xterm: -S <fd>

Unter Linux ist es möglich, den Dateinamen "/dev/fd/<fd>" zu verwenden, um einen Dateideskriptor an ein Programm zu übergeben, das einen Dateinamen erwartet.

Leistung

Das Setzen des Close-on-Exec-Flags kann zusätzliche Systemaufrufe für jede Erstellung neuer Dateideskriptoren erfordern. Die Anzahl der zusätzlichen Systemaufrufe hängt von der Methode ab, die zum Setzen des Flags verwendet wird

  • O_NOINHERIT: kein zusätzlicher Systemaufruf
  • O_CLOEXEC: ein zusätzlicher Systemaufruf, aber nur bei der Erstellung des ersten Dateideskriptors, um zu prüfen, ob das Flag unterstützt wird. Wenn das Flag nicht unterstützt wird, muss Python auf die nächste Methode zurückfallen.
  • ioctl(fd, FIOCLEX): ein zusätzlicher Systemaufruf pro Dateideskriptor
  • fcntl(fd, F_SETFD, flags): zwei zusätzliche Systemaufrufe pro Dateideskriptor, einer zum Abrufen der alten Flags und einer zum Setzen der neuen Flags

Unter Linux hat das Setzen des Close-on-Flag geringe Auswirkungen auf die Leistung. Ergebnisse von bench_cloexec.py auf Linux 3.6

  • Close-on-Flag nicht gesetzt: 7,8 us
  • O_CLOEXEC: 1 % langsamer (7,9 us)
  • ioctl(): 3 % langsamer (8,0 us)
  • fcntl(): 3 % langsamer (8,0 us)

Implementierung

os.get_cloexec(fd)

Holt das Close-on-Exec-Flag eines Dateideskriptors.

Pseudocode

if os.name == 'nt':
    def get_cloexec(fd):
        handle = _winapi._get_osfhandle(fd);
        flags = _winapi.GetHandleInformation(handle)
        return not(flags & _winapi.HANDLE_FLAG_INHERIT)
else:
    try:
        import fcntl
    except ImportError:
        pass
    else:
        def get_cloexec(fd):
            flags = fcntl.fcntl(fd, fcntl.F_GETFD)
            return bool(flags & fcntl.FD_CLOEXEC)

os.set_cloexec(fd, cloexec=True)

Setzt oder löscht das Close-on-Exec-Flag eines Dateideskriptors. Das Flag wird nach der Erstellung des Dateideskriptors gesetzt und ist daher nicht atomar.

Pseudocode

if os.name == 'nt':
    def set_cloexec(fd, cloexec=True):
        handle = _winapi._get_osfhandle(fd);
        mask = _winapi.HANDLE_FLAG_INHERIT
        if cloexec:
            flags = 0
        else:
            flags = mask
        _winapi.SetHandleInformation(handle, mask, flags)
else:
    fnctl = None
    ioctl = None
    try:
        import ioctl
    except ImportError:
        try:
            import fcntl
        except ImportError:
            pass
    if ioctl is not None and hasattr('FIOCLEX', ioctl):
        def set_cloexec(fd, cloexec=True):
            if cloexec:
                ioctl.ioctl(fd, ioctl.FIOCLEX)
            else:
                ioctl.ioctl(fd, ioctl.FIONCLEX)
    elif fnctl is not None:
        def set_cloexec(fd, cloexec=True):
            flags = fcntl.fcntl(fd, fcntl.F_GETFD)
            if cloexec:
                flags |= FD_CLOEXEC
            else:
                flags &= ~FD_CLOEXEC
            fcntl.fcntl(fd, fcntl.F_SETFD, flags)

ioctl wird `fcntl` vorgezogen, da es nur einen Systemaufruf erfordert, im Gegensatz zu zwei Systemaufrufen für `fcntl`.

Hinweis

fcntl(fd, F_SETFD, flags) unterstützt nur ein Flag (FD_CLOEXEC), sodass fcntl(fd, F_GETFD) vermieden werden könnte. Es kann jedoch in Zukunft andere Flags fallen lassen, daher ist es sicherer, die beiden Funktionsaufrufe beizubehalten.

Hinweis

fopen()-Funktion der GNU libc ignoriert den Fehler, wenn fcntl(fd, F_SETFD, flags) fehlschlägt.

open()

  • Windows: open() mit O_NOINHERIT Flag [atomar]
  • open() mit O_CLOEXEC Flag [atomar]
  • open() + os.set_cloexec(fd, True) [bestmögliche Bemühung]

os.dup()

  • Windows: DuplicateHandle() [atomar]
  • fcntl(fd, F_DUPFD_CLOEXEC) [atomar]
  • dup() + os.set_cloexec(fd, True) [bestmögliche Bemühung]

os.dup2()

  • fcntl(fd, F_DUP2FD_CLOEXEC, fd2) [atomar]
  • dup3() mit O_CLOEXEC Flag [atomar]
  • dup2() + os.set_cloexec(fd, True) [bestmögliche Bemühung]

os.pipe()

  • Windows: CreatePipe() mit SECURITY_ATTRIBUTES.bInheritHandle=TRUE oder _pipe() mit O_NOINHERIT Flag [atomar]
  • pipe2() mit O_CLOEXEC Flag [atomar]
  • pipe() + os.set_cloexec(fd, True) [bestmögliche Bemühung]

socket.socket()

  • Windows: WSASocket() mit WSA_FLAG_NO_HANDLE_INHERIT Flag [atomar]
  • socket() mit SOCK_CLOEXEC Flag [atomar]
  • socket() + os.set_cloexec(fd, True) [bestmögliche Bemühung]

socket.socketpair()

  • socketpair() mit SOCK_CLOEXEC Flag [atomar]
  • socketpair() + os.set_cloexec(fd, True) [bestmögliche Bemühung]

socket.socket.accept()

  • accept4() mit SOCK_CLOEXEC Flag [atomar]
  • accept() + os.set_cloexec(fd, True) [bestmögliche Bemühung]

Abwärtskompatibilität

Es gibt keine abwärtskompatiblen Änderungen. Das Standardverhalten bleibt unverändert: Das Close-on-Exec-Flag ist standardmäßig nicht gesetzt.

Anhang: Betriebssystemunterstützung

Windows

Windows hat ein O_NOINHERIT-Flag: „Nicht in Kindprozessen vererben“.

Es wird beispielsweise von open() und _pipe() unterstützt.

Das Flag kann mit SetHandleInformation(fd, HANDLE_FLAG_INHERIT, 0) gelöscht werden.

CreateProcess() hat einen Parameter bInheritHandles: Wenn er FALSE ist, werden die Handles nicht vererbt. Wenn er TRUE ist, werden Handles mit gesetztem HANDLE_FLAG_INHERIT-Flag vererbt. subprocess.Popen verwendet die Option close_fds, um bInheritHandles zu definieren.

ioctl

Funktionen

  • ioctl(fd, FIOCLEX, 0): Setzt das Close-on-Exec-Flag
  • ioctl(fd, FIONCLEX, 0): Löscht das Close-on-Exec-Flag

Verfügbarkeit: Linux, Mac OS X, QNX, NetBSD, OpenBSD, FreeBSD.

fcntl

Funktionen

  • flags = fcntl(fd, F_GETFD); fcntl(fd, F_SETFD, flags | FD_CLOEXEC): Setzt das Close-on-Exec-Flag
  • flags = fcntl(fd, F_GETFD); fcntl(fd, F_SETFD, flags & ~FD_CLOEXEC): Löscht das Close-on-Exec-Flag

Verfügbarkeit: AIX, Digital UNIX, FreeBSD, HP-UX, IRIX, Linux, Mac OS X, OpenBSD, Solaris, SunOS, Unicos.

Atomare Flags

Neue Flags

  • O_CLOEXEC: verfügbar auf Linux (2.6.23), FreeBSD (8.3), OpenBSD 5.0, Solaris 11, QNX, BeOS, nächste NetBSD-Veröffentlichung (6.1?). Dieses Flag ist Teil von POSIX.1-2008.
  • SOCK_CLOEXEC Flag für socket() und socketpair(), verfügbar auf Linux 2.6.27, OpenBSD 5.2, NetBSD 6.0.
  • WSA_FLAG_NO_HANDLE_INHERIT Flag für WSASocket(): unterstützt unter Windows 7 mit SP1, Windows Server 2008 R2 mit SP1 und neuer
  • fcntl(): F_DUPFD_CLOEXEC Flag, verfügbar auf Linux 2.6.24, OpenBSD 5.0, FreeBSD 9.1, NetBSD 6.0, Solaris 11. Dieses Flag ist Teil von POSIX.1-2008.
  • fcntl(): F_DUP2FD_CLOEXEC Flag, verfügbar auf FreeBSD 9.1 und Solaris 11.
  • recvmsg(): MSG_CMSG_CLOEXEC, verfügbar auf Linux 2.6.23, NetBSD 6.0.

Auf Linux älter als 2.6.23 wird das Flag O_CLOEXEC einfach ignoriert. Daher müssen wir prüfen, ob das Flag unterstützt wird, indem wir fcntl() aufrufen. Wenn es nicht funktioniert, müssen wir das Flag mithilfe von ioctl() oder fcntl() setzen.

Auf Linux älter als 2.6.27 schlägt bei Setzen des Flags SOCK_CLOEXEC im Socket-Typ socket() oder socketpair() fehl und errno wird auf EINVAL gesetzt.

Unter Windows XPS3 gibt WSASocket() mit WSAEPROTOTYPE zurück, wenn das Flag WSA_FLAG_NO_HANDLE_INHERIT verwendet wird.

Neue Funktionen

  • dup3(): verfügbar auf Linux 2.6.27 (und glibc 2.9)
  • pipe2(): verfügbar auf Linux 2.6.27 (und glibc 2.9)
  • accept4(): verfügbar auf Linux 2.6.28 (und glibc 2.10)

Wenn accept4() auf Linux älter als 2.6.28 aufgerufen wird, gibt accept4() -1 (Fehler) zurück und errno wird auf ENOSYS gesetzt.

Fußnoten


Quelle: https://github.com/python/peps/blob/main/peps/pep-0433.rst

Zuletzt geändert: 2025-02-01 08:59:27 GMT