Setzt free() errno?

Lesezeit: 6 Minuten

Benutzeravatar von Paul
Paul

Wenn buf ist ein malloc() Zugewiesener Zeichenpuffer, tut es free(buf) setzen/zurücksetzen errno?

Nehmen wir an, ich möchte den Puffer in eine Datei schreiben und ihn dann freigeben, da ich ihn nicht mehr benötige.

Angenommen, die Fehlerrichtlinie für den Code besteht darin, bei einem Fehler -1 zurückzugeben.

Ist dies ein geeigneter Weg, um den Puffer und die Fehlerprüfung zu schreiben, ohne Speicher zu verlieren?

fputs(buf, somefile);
free(buf);
if (errno) return -1;

Oder muss ich erwägen, möglicherweise frei zu setzen errno, wie in …

fputs(buf, somefile);
if (errno){ 
    free(buf);
    return -1;
}
free(buf);

oder Schrecken aller Schrecken,

do { 
  fputs(buf, somefile);
  int save_errno = errno;
  free(buf);
  errno = save_errno;
  if (errno) return -1;
} while(0);  

wobei die Verwendung eines Blocks es ermöglicht, dass an verschiedenen Stellen ein lokaler save_errno vorhanden ist, falls dieser wiederverwendet werden muss.

All dies scheint davon abzuhängen, ob free() errno setzt.

Das Linux-Manpage kostenlos () ist auch die Manpage für malloc()etc. Es erwähnt malloc() Einstellung errno, aber nicht free().

Das Handbuchseite der GNU C-Bibliothek zum Freigeben von dynamischem Speicher erwähnt nicht, ob free() errno setzt.

Also habe ich ein kurzes Programm geschrieben, um einen Schreibfehler zu erzwingen, damit ich sehen kann, ob free() errno zurücksetzt, und das tut es nicht. Ich frage mich, ob ich mich auf dieses Ergebnis und die Tatsache verlassen sollte, dass free() so wichtig ist, dass “es natürlich keine errno setzt”.

# See if free() resets errno on a bad write
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char **argv)
{
  char * buf = malloc(256);
  snprintf(buf,256,"%s\n", "Hello, World!");

  FILE *badfile;

  badfile = fopen("/dev/null","r");

  fputs(buf, badfile);
  free(buf);
  printf("%d\n", errno);
  printf("%s\n", strerror(errno));
}

  • EIN gute Referenzen sollten helfen.

    – Irgendein Programmierer-Typ

    1. Juni 2015 um 9:32 Uhr

  • Auch der Wert von errno ist undefiniert, nachdem Funktionen aufgerufen wurden, die es nicht explizit festlegen, und dazu gehören Funktionsaufrufe, die nicht fehlschlagen. Mit anderen Worten, nicht überprüfen errno es sei denn, die früher Aufruf explizit fehlgeschlagen.

    – Irgendein Programmierer-Typ

    1. Juni 2015 um 9:34 Uhr

  • “Missbrauch” von freewie der Versuch, denselben Zeiger zweimal freizugeben, nicht haben zu stürzen, ist es einfach nicht definiert. Allerdings führt undefiniertes Verhalten in vielen Fällen zu Abstürzen.

    – Irgendein Programmierer-Typ

    1. Juni 2015 um 9:35 Uhr


  • pubs.opengroup.org/onlinepubs/9699919799/functions/…

    – Werner Henze

    1. Juni 2015 um 11:17 Uhr

  • Sie müssen nicht auf a zurückgreifen do {...} while(0); konstruieren, können Sie auch Blöcke mit einfachen geschweiften Klammern erstellen {...}.

    – QUentin

    1. Juni 2015 um 12:38 Uhr

Benutzeravatar von Sander De Dycker
Sander DeDycker

POSIX definiert nicht free zu setzen errno (Obwohl POSIX dies derzeit nicht verbietet, könnte eine Implementierung dies tun – weitere Einzelheiten finden Sie in der Antwort von @ArjunShankar). Aber das ist nicht wirklich relevant für Ihr Anliegen.

Die Art und Weise, wie Sie nach Fehlern suchen, ist falsch. Sie sollten den Rückgabewert von überprüfen fputsund prüfen Sie, ob es kleiner als ist 0. Wenn ja, dann kannst du das überprüfen errno um herauszufinden, was den Fehler verursacht hat, aber das ist optional (und sollte getan werden, bevor weitere Funktionen aufgerufen werden).

Also, so etwas sollte den Trick tun:

int result = fputs(buf, somefile);
/* optionally read errno here if result < 0 (before the free call) */
free(buf);
return (result < 0) ? -1 : 0;

  • Einschlägiges Zitat aus dem errno Manpage: Its value is significant only when the return value of the call indicated an error (i.e., -1 from most system calls; -1 or NULL from most library functions); a function that succeeds is allowed to change errno.

    – Markieren

    1. Juni 2015 um 23:06 Uhr

  • @Mark: Fun Fact: Ich habe es geschafft, das zu beobachten execvp() Änderungen errno auf Erfolg.

    – Josua

    5. September 2021 um 20:44 Uhr

Benutzeravatar von ArjunShankar
ArjunShankar

Ein POSIX-konformes free könnte setzen errno heute aber das wird sich in zukunft zum besseren ändern. Einzelheiten:

  1. Das The Open Group Base Specifications Ausgabe 7 Definition von errno gibt folgendes an:

Keine Funktion in diesem Band von POSIX.1-2008 darf errno auf 0 setzen. Das Setzen von errno nach einem erfolgreichen Aufruf einer Funktion ist unspezifiziert, es sei denn, die Beschreibung dieser Funktion gibt an, dass errno nicht geändert werden soll.

  1. Die Definition von free selbst gibt nicht an, was free macht mit errno.

Das bedeutet, dass eine konforme free Die Implementierung wird niemals zurückgesetzt errno auf 0. Aber es kann es auf einen Wert ungleich Null setzen oder nicht.

Ausgabe 8 (in Arbeit) der Spezifikation wird jedoch benötigen free um ausdrücklich zu garantieren, dass es nicht fest wird errno wenn eine gültige Eingabe übergeben wird.

glibc bereitet sich bereits darauf vor, diese neue Anforderung zu erfüllen.

  • Unter welchen Umständen kann free set errno setzen, wenn eine gültige Eingabe übergeben wird?

    – Random832

    1. Juni 2015 um 12:34 Uhr

  • @ Random832 Das würde von der Implementierung abhängen. Manche berühren sich vielleicht nicht errno. Schauen Sie sich den Glibc-Fehlerbericht an (aber um klar zu sein, dass dies noch kein Fehler ist, da POSIX noch nicht überarbeitet wurde), den ich in der letzten Zeile meiner Antwort verlinkt habe, um Einzelheiten darüber zu erfahren, wie dies in der Implementierung von glibc passieren kann free.

    – ArjunShankar

    1. Juni 2015 um 12:41 Uhr


  • @Random832 Stellen Sie sich eine malloc/free-Implementierung vor, die versucht, den Heap nach Möglichkeit zu verkleinern, indem Systemaufrufe verwendet werden, die dem zugrunde liegenden Betriebssystem entsprechen, z. B. mmap(), sbrk() usw. Wenn diese Systemaufrufe fehlschlagen, wird errno gesetzt.

    – Kyle Jones

    1. Juni 2015 um 16:43 Uhr

  • @ Random832, es ist vollkommen gültig, dass eine Funktion bedingungslos festgelegt wird errno auf den häufigsten Fehler und verwenden Sie dann den Rückgabewert, um anzugeben, ob dieser Fehler tatsächlich aufgetreten ist.

    – cjm

    1. Juni 2015 um 19:45 Uhr

Vlad aus Moskaus Benutzer-Avatar
Vlad aus Moskau

Da wird nichts gesagt errno in der Beschreibung von free im C-Standard. Sie dürfen sich also nicht auf diese Funktion verlassen.

Nach dem C-Standard (7.5 Errors <errno.h>)

3…Der Wert von errno darf durch einen Bibliotheksfunktionsaufruf auf einen Wert ungleich Null gesetzt werden, unabhängig davon, ob ein Fehler vorliegt oder nicht, vorausgesetzt, die Verwendung von errno ist nicht in der Beschreibung der Funktion in dieser Internationalen Norm dokumentiert.

Und die Verwendung von errno ist in der Beschreibung nicht dokumentiert free im C-Standard, wie ich oben schon sagte.

Benutzeravatar von molbdnilo
molbnilo

Wenn die Referenz nicht besagt, dass eine Funktion einen Fehlercode zurückgibt in errno bei einem Fehler wird es nicht.

Funktionen, die setzen errno ein fehlercode signalisiert das (fast) immer auf andere weise errno enthält den aktuellen Fehlercode – die Speicherzuweisungsfunktionen geben zurück NULLviele andere Funktionen geben Null oder eine negative Zahl zurück und so weiter.
Solche Funktionen müssen nicht geändert werden errno in irgendeiner Weise, wenn sie erfolgreich sind, und normalerweise nicht.

In der Regel kann man nicht kontrollieren errno um festzustellen, ob etwas schief gelaufen ist; Es dient nur dazu, weitere Informationen abzurufen, sobald Sie wissen, dass ein Fehler aufgetreten ist.

Eine Ausnahme von der letzten Regel ist die strto{l, d, ul} Familie, aber der erste Absatz gilt auch für diese.
Und sie setzen auch nicht unbedingt errno außer wenn sie fehlschlagen, also müssen Sie es zuerst löschen oder es kann einen veralteten Fehlercode enthalten.

Ja, free() kann errno auf verschiedenen Systemen beschädigen. gnulib vermeidet dieses Problem, indem es free() auf solchen Plattformen ersetzt, die es derzeit als „glibc 2.32, Mac OS X, FreeBSD, NetBSD, OpenBSD 4.4, Minix, AIX, HP-UX, IRIX, Cygwin, mingw, MSVC“ dokumentiert.

Benutzeravatar von user4531555
Benutzer4531555

Sie können RAII verwenden, um mallocierten Speicher freizugeben und den Rückgabewert von fputs zu überprüfen. Das wird Gnadencode sein.

//if malloc successfully
AutoFree af(buf);
if (fputs(buf, somefile)) {
LOG("something err:%s", strerror(errno));
}
return 0;

1414530cookie-checkSetzt free() errno?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy