2016-04-19 5 views
-2

Warum funktioniert das?Odd Verhalten in Bezug auf malloc()

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

int main() 
{ 

    char * abc = malloc(1) + 4; //WRONG use of malloc. 
    char * xyz = "abc"; 
    strcpy(abc, xyz); //Should fail. 
    printf("%s\n", abc); //Prints abc 
} 

Ich würde die strcpy erwarten für nicht mit genügend Speicher zum Scheitern verurteilt, da ich (in 1 auf das Argument von malloc vorbei). Stattdessen kompiliert und läuft es einwandfrei (sowohl in GCC unter Linux als auch unter Windows unter deC++).

Ist dieses erwartete Verhalten oder ein glücklicher Zufall?

Ich nehme an, das ist keine gute Praxis, aber warum funktioniert es?

Ohne die +4 am Ende der malloc(), bekomme ich einen Segmentierungsfehler. Das ist hauptsächlich was ich interessiere.

+2

Das ist nicht was "Arbeit" bedeutet. –

+0

Können Sie es ausarbeiten? – ale10ander

+4

Aufrufen von undefiniertem Verhalten ist immer eine schlechte Idee. Und es macht keinen Sinn zu erforschen, warum sich Code nach dem Aufruf so verhält. Nicht sicher, warum Sie vermuten, nicht genug Speicher zu haben, um 1 Byte zuzuordnen, aber Sie könnten ein Missverständnis über 'malloc' & Freunde haben. Und Arithmetik für 'void *' ist ebenfalls nicht definiert. – Olaf

Antwort

5

Diese im Grunde ein weiterer Beweis für die Tatsache ist, dass Zeiger in C sind schwach- und (in der Regel) nicht überprüft. Du hast gesagt, dass du erwartet hast, dass es "fehlschlägt, weil du nicht genug Speicher hast", aber denke darüber nach: Was hast du erwartet, dass es scheiterte? Die strcpy Funktion überprüft am sichersten nicht, dass genug Platz für die Zeichenfolge ist, die kopiert wird. Es hat keinen Weg dies zu tun; Alles was es bekommt, ist ein Zeiger. Es beginnt einfach, Zeichen zu kopieren, und in der Praxis ist es entweder erfolgreich oder stirbt bei einer Segmentierungsverletzung. (Aber der Punkt ist es tut nicht sterben auf "nicht genügend Speicher".)

6

Dies ist undefined behavior. Tu das nicht !!.

Sie versuchen, auf den Speicherort außerhalb der zugewiesenen Region zuzugreifen. So ist der Speicherort ungültig und Zugriff auf ungültigen Speicher ruft UB auf.

FWIW,

  • es in dem C-Standard wird darauf hingewiesen, dass stoppt Sie den Zugriff aus den gebundenen (ungültig) Speichern und

  • auch nicht strcpy() Prüfung für die Größe des Ziels Puffer im Vergleich zur Quelllänge

so, dieser Code (irgendwie) kompiliert. Sobald Sie es ausführen und es UB trifft, ist nichts mehr garantiert.

P.S - the only guaranteed thing here is undefined behavior.

+0

Siehe [this] (http://stackoverflow.com/a/25636788/841108) über was passieren könnte bei undefiniertem Verhalten * –

+0

@BasileStarynkevitch Danke für den Link, eingebettet in meine Antwort. :) –

1

Verlasse dich nicht auf dieses Verhalten. Die Antworter, die "energisch" antworten, sind dadurch gerechtfertigt, dass sich ein solches Verhalten jahrelang unbemerkt halten kann und dann, eines Tages, eine geringfügige Anpassung des Laufzeitsystems plötzlich katastrophale Fehler verursacht.

Es scheint, weil zu arbeiten, seit dem Aufkommen von 32-Bit-Computern, viele — wenn nicht den meisten — C-Laufzeitbibliotheken malloc/free, die den Haufen mit 16-Byte-Granularität verwalten implementieren. Das heißt, das Aufrufen von malloc() mit einem Parameter von 1 bis 16 liefert die gleiche Zuordnung. Also bekommst du etwas mehr Speicher, als du verlangt hast, und das erlaubt es auszuführen.

Ein Tool wie valgrind würde sicherlich ein Problem erkennen.