Wenn `malloc(0)` einen Nicht-Null-Zeiger zurückgibt, kann ich das an `free` übergeben?

Lesezeit: 5 Minuten

Benutzeravatar von pnkfelix
pnkfelix

Ich habe über Diskussionen darüber gelesen, wie malloc verhält sich, wenn Sie einen Block der Größe Null anfordern.

Ich verstehe, dass das Verhalten von malloc(0) ist implementierungsdefiniert und soll entweder einen Nullzeiger zurückgeben, oder ein Nicht-Null-Zeiger, auf den ich trotzdem nicht zugreifen soll. (Was sinnvoll ist, da es keine Garantie dafür gibt, dass es auf einen verwendbaren Speicher verweist.)

Wenn ich jedoch einen solchen nicht zugänglichen Nicht-Null-Zeiger bekomme, darf ich ihn weitergeben free auf die übliche Weise? Oder ist das illegal, da bekomme ich den Hinweis ab malloc(0) möglicherweise nicht auf einen tatsächlich zugewiesenen Speicherblock?

Hat der folgende Code konkret ein wohldefiniertes Verhalten:

#include <stdio.h>
#include <stdlib.h>

int main() {
    int* x = (int*) malloc(0);
    if (x == NULL) {
        printf("Got NULL\n");
        return 0;
    } else {
        printf("Got nonnull %p\n", x);
    }
    free(x); // is calling `free` here okay?
}

  • Ja, du kannst free das Ergebnis von malloc

    – MM

    2. Juni 2017 um 14:26 Uhr

  • “Wenn size 0 ist, gibt malloc() entweder NULL oder einen eindeutigen Zeigerwert zurück, der später erfolgreich an free() übergeben werden kann.”, linux.die.net/man/3/mallocRTFM: p.

    – Sternengatter

    2. Juni 2017 um 14:27 Uhr

  • Sie werden auch garantiert bestehen können NULL zu free(). Wie auch immer malloc() Rücksendungen können sicher sein free()d (einmal).

    – Rici

    2. Juni 2017 um 14:32 Uhr

  • @MM, nein, wirf überhaupt keine Zeiger. Verwenden Sie in Code wie diesem void* Anstatt von int*werfen Sie nicht das Ergebnis von malloc wie auch immer, und verwenden Sie die %p Bezeichner zum Drucken von Zeigern.

    – Jens Gustedt

    2. Juni 2017 um 14:40 Uhr

  • @JensGustedt %p Das Format ist nicht definiert, ob es hexadezimal oder dezimal ist, wie die Formatierung ist … es gibt Gründe, Zeiger zum Drucken in Ganzzahlen umzuwandeln, um das Ausgabeformat zu steuern

    – MM

    2. Juni 2017 um 14:43 Uhr

Benutzeravatar von apriori
a priori

Der C99-Standard (eigentlich WG14/N1124. Committee Draft – 6. Mai 2005. ISO/IEC 9899:TC2) sagt ungefähr malloc():

Der zurückgegebene Zeiger zeigt auf den Anfang (niedrigste Byte-Adresse) des zugewiesenen Speicherplatzes. Wenn der Speicherplatz nicht zugewiesen werden kann, wird ein Nullzeiger zurückgegeben. Wenn die Größe des angeforderten Speicherplatzes Null ist, ist das Verhalten implementierungsdefiniert: Entweder wird ein Nullzeiger zurückgegeben, oder das Verhalten ist so, als ob die Größe ein Wert ungleich Null wäre, außer dass der zurückgegebene Zeiger nicht verwendet werden soll, um auf ein Objekt zuzugreifen

und über free():

Andernfalls, wenn das Argument nicht mit einem Zeiger übereinstimmt, der zuvor von der Funktion calloc, malloc oder realloc zurückgegeben wurde, oder wenn der Speicherplatz durch einen Aufruf von free oder realloc freigegeben wurde, ist das Verhalten undefiniert.

IEEE Std 1003.1-2008 (POSIX), Ausgabe 2016 sagt ungefähr free():

Die Funktion free() soll bewirken, dass der Raum, auf den ptr zeigt, freigegeben wird; das heißt, zur weiteren Zuordnung verfügbar gemacht. Wenn ptr ein Nullzeiger ist, soll keine Aktion stattfinden. Andernfalls, wenn das Argument nicht mit einem Zeiger übereinstimmt, der zuvor von einer Funktion in POSIX.1-2008 zurückgegeben wurde, die Speicher wie durch malloc() zuweist, oder wenn der Speicherplatz durch einen Aufruf von free() oder realloc() freigegeben wurde, Das Verhalten ist undefiniert.

Was auch immer *alloc() zurückkehrt, können Sie zu übergeben free().

Wie für die aktuellen Implementierungen von malloc():

FreeBSD verwendet das beigesteuerte jemalloc, das dies tut

void *
je_malloc(size_t size)
{
    void *ret;
    size_t usize JEMALLOC_CC_SILENCE_INIT(0);

    if (size == 0)
        size = 1;
    [...]

Während Apples libmalloc dies tut

void *
szone_memalign(szone_t *szone, size_t alignment, size_t size)
{
    if (size == 0) {
        size = 1; // Ensures we'll return an aligned free()-able pointer
    [...]

Der GLIBC ändert auch die angeforderte Größe; Es verwendet einen Aufruf dieses Makros mit der angeforderten Größe in Bytes als Parameter, um die Größe an einer bestimmten Grenze oder einfach an der minimalen Zuordnungsgröße auszurichten:

#define request2size(req)                                       \
    (((req) + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE)  ?         \
    MINSIZE :                                                   \
    ((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)

Ja, in der Tat müssen Sie dies tun, um ein mögliches Speicherleck zu vermeiden.

Das malloc-System gibt normalerweise einen versteckten Steuerblock in dem Raum unmittelbar vor dem Zeiger zurück, mit Informationen wie der Zuordnungsgröße. Wenn die Zuweisungsgröße null ist, existiert dieser Block immer noch und belegt Speicher, wenn malloc nicht null zurückgibt.

  • Aha. (Ich hatte angenommen, dass es einen Sentinel-Block für Zuweisungen der Größe Null verwenden könnte, aber ich kann glauben, dass dies keine universelle Wahl ist. Wenn ich mir die Linux-Manpage ansehe, führt mich die Verwendung des Ausdrucks „oder ein eindeutiger Zeigerwert“ zu Fragen wenn die Verwendung eines Sentinels überhaupt legal wäre …)

    – pnkfelix

    2. Juni 2017 um 14:33 Uhr

  • Das Problem ist, dass Sie Code wie if(!allocatedptr) outofmemoryhandler() erhalten, der ausgelöst wird, wenn N = 0 und malloc NULL zurückgibt. Es ist wohl besser, einen Wert zurückzugeben. Ich habe es gerade getestet und auf dem auf diesem Computer installierten System (clang) bekomme ich eine Rückgabe ungleich Null.

    – Malcolm McLean

    2. Juni 2017 um 14:42 Uhr

  • @PaulOgilvie dein Kommentar ist etwas verwirrend; Wenn malloc NULL zurückgibt, KÖNNEN Sie es an free übergeben

    – MM

    2. Juni 2017 um 14:44 Uhr

  • @PaulOgilvie – weshalb der Standard dies angibt “Wenn ptr ein Nullzeiger ist, findet keine Aktion statt.”

    – ad absurdum

    2. Juni 2017 um 15:21 Uhr

  • @PaulOgilvie: Wie Malcolms Kommentar sagt, gehen die meisten Leute in der Praxis davon aus malloc Null zurückzugeben bedeutet OOM. Laut Sprache ist dies keine korrekte Annahme, da es ein Szenario gibt, in dem malloc darf null zurückgeben, solange noch Speicher verfügbar ist. Also nein, es zeigt nicht OOM an. Sie und viele andere können das natürlich annehmen, aber sagen Sie nicht, dass es definitiv so ist. Es möchten es ist richtig, das zu sagen malloc Die Rückgabe von null bei einer Größe ungleich Null würde auf OOM hinweisen – ja, das ist technisch gesehen ein willkommenes Land für Sprachanwälte.

    – GManNickG

    2. Juni 2017 um 22:00 Uhr

1403180cookie-checkWenn `malloc(0)` einen Nicht-Null-Zeiger zurückgibt, kann ich das an `free` übergeben?

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

Privacy policy