Frage

Es gibt bestimmte Bedingungen, die verursachen können, stack-überläufe auf einem x86-Linux-system:

  • struct my_big_object[HUGE_NUMBER] auf dem Stapel.Zu Fuß durch es führt schließlich dazu, dass SIGSEGV.
  • Die alloca() routine (wie malloc(), sondern verwendet den Stapel automatisch befreit sich, und auch Schläge mit SIGSEGV wenn es zu groß ist). Update:alloca() nicht offiziell veraltet, wie ich ursprünglich angegeben;es wird lediglich abgeraten.

Gibt es eine Möglichkeit, programmgesteuert zu erkennen, ob die lokalen Stapel ist groß genug für ein bestimmtes Objekt?Ich weiß, die stack-Größe ist einstellbar ulimit,, so ich Hoffnung habe gibt es eine Möglichkeit (jedoch nicht tragbar, es kann sein).Im Idealfall würde ich mag in der Lage sein, etwas zu tun wie diese:

int min_stack_space_available = /* ??? */;
if (object_size < min_stack_space_available)
{
    char *foo = alloca(object_size);
    do_stuff(foo);
}
else
{
    char *foo = malloc(object_size);
    do_stuff(foo);
    free(foo);
}
War es hilfreich?

Lösung

Sie können bestimmen, Platz auf dem stack des Prozesses zur Verfügung hat, finden die Größe eines Prozess' Stapelspeicher und dann zieht man die Höhe verwendet.

ulimit -s

zeigt die stack-Größe auf einem linux-system.Für einen programmatischen Ansatz, check out getrlimit().Dann, um zu bestimmen, den aktuellen stack-Tiefe, subtrahieren Sie einen Zeiger auf die top der Stapel von einem bis unten.Zum Beispiel (code nicht getestet):

unsigned char *bottom_of_stack_ptr;

void call_function(int argc, char *argv) {
    unsigned char top_of_stack;
    unsigned int depth = (&top_of_stack > bottom_of_stack_ptr) ? 
        &top_of_stack-bottom_of_stack_ptr : 
        bottom_of_stack_ptr-&top_of_stack;

    if( depth+100 < PROGRAMMATICALLY_DETERMINED_STACK_SIZE ) {
        ...
    }
}

int main(int argc, char *argv) {
    unsigned char bottom_of_stack;
    bottom_of_stack_ptr = &bottom_of_stack;
    my_function();
    return 0;
}

Andere Tipps

Die veralteten alloca () - routine (wie malloc(), aber es verwendet den Stapel automatisch befreit sich, und auch Schläge mit SIGSEGV, wenn es zu groß ist).

Warum ist alloca veraltet?

Jedenfalls, wie viel schneller in Ihrem Fall ist alloca vs malloc?(Ist es das Wert?)

Und nicht, erhalten Sie null zurück von alloca, wenn es nicht genug Platz?(auf die gleiche Weise wie malloc?)

Und wenn Ihr code abstürzt, wo kommt der crash?ist es in alloca oder in doStuff()?

/Johan

Nicht sicher, ob dies gilt auch für Linux, aber unter Windows ist es möglich, in Zugriffsverletzungen mit großen stack Zuweisungen selbst wenn Sie Erfolg haben!

Dies ist, da standardmäßig Windows' VMM nur eigentlich markiert den Anfang einige (nicht sicher, wie viele genau) 4096-byte-Seiten des stack-RAM als pageable (d.h.unterstützt von der Auslagerungsdatei), da es glaubt, dass der Stapel zugreift, wird in der Regel im März nach unten von der Spitze;da greift sich näher und näher an den aktuellen "Grenze", die unteren und die unteren Seiten sind markiert als pageable.Das aber bedeutet, dass eine frühzeitige Speicher Lesen/schreiben, die weit unterhalb der Spitze des Stapels wird eine Zugriffsverletzung ausgelöst als Speicher, dass ist eigentlich nicht zugewiesenen, noch nicht!

alloca() wird NULL zurückgegeben, im Fehlerfall, ich glaube, dass das Verhalten von alloca(0) ist undefiniert und Plattform-Variante.Wenn Sie überprüfen, die vor do_something(), sollten Sie niemals mit einem hit werden SEGV.

Ich habe ein paar Fragen:

  1. Warum, oh, warum, tun Sie etwas, das groß auf den stack?Die Standard Größe auf den meisten Systemen ist 8M, das ist immer noch zu klein?
  2. Wenn der aufrufenden Funktion alloca() blockiert, würde den Schutz der gleichen Menge an heap mittels mlock() / mlockall () - Garantie der Nähe der gleichen access-Leistung (d.h."Don' T swap mich, bro!") im Laufe der Zeit?Wenn Ihr mit einem aggressiveren 'rt' scheduler, seine empfohlen, rufen Sie diese trotzdem.

Die Frage ist interessant, aber hebt eine Augenbraue.Er wirft die Nadel auf mein square-peg-Runde-Loch-o-meter.

Sie sagen nicht viel darüber nach, warum Sie zuweisen möchten, auf dem Stapel, aber wenn es die stack-Speicher-Modell, die ist Ansprechend, könnten Sie implementieren stack Allokation auf dem heap als gut.Reservieren Sie ein großes Stück der Speicher am Anfang des Programms und halten einen Stapel von Zeigern auf diese die entsprechen würde, um frames auf den regulären Stapel.Sie brauchen nur daran zu erinnern, um pop-Ihre private stack-pointer, wenn die Funktion zurückgegeben wird.

Mehrere Compiler, zum Beispiel Open Watcom C/C++, Unterstützung stackavail () - Funktion, mit der Sie genau das tun

Sie können verwenden GNU libsigsegv zu Griff ein Seitenfehler, einschließlich Fällen, in denen ein Stapelüberlauf Auftritt (von Ihrer website):

In einigen Anwendungen, die stack-overflow-handler führt etwas Aufräumen oder benachrichtigt den Benutzer und dann unverzüglich beendet die Anwendung.In anderen Anwendungen, die stack overflow handler longjmps zurück an einen zentralen Punkt in der Anwendung.Diese Bibliothek unterstützt sowohl verwendet.Im zweiten Fall muss der Hundeführer zu gewährleisten, zur Wiederherstellung der normalen signal-Maske (weil viele Signale sind blockiert, während der handler ausgeführt wird), und muss auch anrufen sigsegv_leave_handler (), um die übertragung Kontrolle;nur dann kann es longjmp entfernt.

Die alloca-Funktion nicht veraltet.Jedoch, es ist nicht in POSIX und es ist auch Maschine - und compiler-abhängig.Der Linux-man-page für alloca stellt fest, dass "für bestimmte Anwendungen, kann seine Verwendung zu verbessern die Effizienz im Vergleich zur Verwendung von malloc, und in bestimmten Fällen kann es auch vereinfachen memory deallocation in Anwendungen, longjmp() oder siglongjmp().Andernfalls, ist seine Verwendung abgeraten."

Die manpage sagt auch, dass "es gibt keine Fehleranzeige, wenn der stack-frame kann nicht verlängert werden.Jedoch, nach einem fehlerhaften Zuordnung, der Programm ist, erhalten Sie wahrscheinlich ein SIGSEGV."

Die Leistung von malloc wurde eigentlich erwähnt, auf der Stackoverflow Podcast #36.

(Ich weiß, das ist nicht die richtige Antwort auf Ihre Frage, aber ich dachte, es könnte nützlich sein, trotzdem.)

Auch wenn dies nicht eine direkte Antwort zu deiner Frage, ich hoffe Sie sind sich bewusst von der Existenz von valgrind - ein wunderbares Werkzeug für die Erkennung solcher Probleme in der runtime auf Linux.

In Bezug auf das stack-problem, Sie können versuchen, zuordnen von Objekten dynamisch aus einem festen pool, erkennt diese überläuft.Mit einem einfachen makro-Zauberei machen Sie dies ausführen im debug-Zeit, mit der richtigen code läuft release-Zeit, und damit wissen (zumindest für die Szenarien, die Sie ausführen), dass Sie nicht zu viel. Hier gibt ' s mehr Infos und ein link um ein Beispiel für die Implementierung.

Gibt es nicht ein schöner Weg, den ich denken kann.Vielleicht ist es möglich, durch mit getrlimit() (schlug vor) und einige Zeiger-Arithmetik?Aber zuerst Fragen Sie sich, wenn Sie es wirklich wollen.

void *closeToBase;

main () {
  int closeToBase;
  stackTop = &closeToBase;
}

int stackHasRoomFor(int bytes) {
  int currentTop;
  return getrlimit(...) - (¤tTop  - closeToBase) > bytes + SomeExtra;
}

Ich persönlich würde das nicht tun.Reservieren Sie große Dinge auf den heap, den stack war nicht für ihn bestimmt.

Am Ende der Stapel bestimmt wird dynamisch vom OS.Obwohl finden Sie die "statische" Grenzen des stack durch das betrachten der virtuellen Speicherbereiche (VMAs) in einer hoch-OS-abhängigen Weise (siehe die stackvma* Dateien in libsigsegv/src/), ist zusätzlich zu berücksichtigen

Entschuldige mich, wenn diese Aussage offensichtlich ist, aber Sie könnten leicht eine Funktion schreiben, um zu testen für einen bestimmten stack-Zuweisung Größe, indem Sie nur versuchen, die alloca (in der Größe), und fangen mit einem stack-overflow-exception.Wenn Sie wollten, könnten Sie es in eine Funktion, mit der einige VORGEGEBENE Mathematik für die Funktion stack-overhead.ZB:

bool CanFitOnStack( size_t num_bytes )
{
    int stack_offset_for_function = 4; // <- Determine this
    try
    {
        alloca( num_bytes - stack_offset_for_function );
    }
    catch ( ... )
    {
        return false;
    }

    return true;
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top