Dlaczego stosowanie alloca() nie jest uważane za dobrą praktykę?

alloca() przydziela pamięć ze stosu, a nie stosu, co ma miejsce w malloc(). Więc, kiedy wracam z rutyny, pamięć zostaje uwolniona. Tak naprawdę rozwiązuje to mój problem uwolnienia dynamicznie przydzielanej pamięci. Uwolnienie pamięci przydzielonej przez malloc() jest poważnym bólem głowy i jeśli w jakiś sposób pominięte prowadzi do wszelkiego rodzaju problemów z pamięcią.

Dlaczego stosowanie alloca() jest zniechęcane pomimo powyższych cech?

Author: Mohit Kanwar, 2009-06-19

24 answers

Odpowiedź znajduje się na stronie man (przynajmniej na Linuksie):

RETURN VALUE Funkcja alloca () zwraca wskaźnik na początek przydzielone miejsce. Jeśli przyczyny alokacji przepełnienie stosu, zachowanie programu jest niezdefiniowane.

Co nie oznacza, że nigdy nie powinno być używane. Jeden z projektów OSS, nad którym pracuję, używa go szeroko i dopóki nie nadużywasz go (alloca'ING huge values), jest w porządku. Po przejściu obok znak" kilkaset bajtów", czas użyć malloc i przyjaciół, zamiast tego. Nadal możesz mieć błędy alokacji, ale przynajmniej będziesz miał pewne wskazania niepowodzenia zamiast po prostu wydmuchiwać stos.

 193
Author: Sean Bright,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-01 21:49:26

Jednym z najbardziej pamiętnych błędów, jakie miałem, było działanie funkcji inline, która używała alloca. Manifestuje się jako przepełnienie stosu (ponieważ przydziela na stosie) w losowych punktach wykonania programu.

W pliku nagłówkowym:

void DoSomething() {
   wchar_t* pStr = alloca(100);
   //......
}

W pliku implementacji:

void Process() {
   for (i = 0; i < 1000000; i++) {
     DoSomething();
   }
}

Stało się więc, że kompilator jest wbudowany w funkcję DoSomething, a wszystkie przydziały stosu dzieliły się wewnątrz funkcji Process() i tym samym wysadzały stos. Na swoją obronę (i nie byłem jeden, który znalazł problem, musiałem iść i płakać do jednego ze starszych programistów, gdy nie mogłem go naprawić), to nie było proste alloca, to było jedno z makr konwersji ciągów ATL.

Więc lekcja jest taka - nie używaj alloca w funkcjach, które Twoim zdaniem mogą być wbudowane.

 169
Author: Igor Zevaka,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-04 23:35:07

Stare pytanie, ale nikt nie wspomniał, że powinno być zastąpione tablicami o zmiennej długości.

char arr[size];

Zamiast

char *arr=alloca(size);

Jest w standardzie C99 i istnieje jako rozszerzenie kompilatora w wielu kompilatorach.

 57
Author: Patrick Schlüter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-12 10:19:37

Alloca() jest bardzo przydatna, jeśli nie możesz użyć standardowej zmiennej lokalnej, ponieważ jej rozmiar musi być określony w czasie wykonywania i możesz absolutnie gwarantuję, że wskaźnik otrzymany z alloca() nigdy nie zostanie użyty po tym, jak ta funkcja zwróci.

Możesz być dość bezpieczny, jeśli

  • nie zwracaj wskaźnika ani niczego, co go zawiera.
  • nie przechowuj wskaźnika w żadnej strukturze przydzielonej na stercie
  • nie pozwól, aby jakikolwiek inny wątek używał wskaźnik

Prawdziwe niebezpieczeństwo pochodzi z szansy, że ktoś inny naruszy te warunki kiedyś później. Mając to na uwadze, świetnie nadaje się do przekazywania buforów do funkcji formatujących tekst do nich:)]}

 49
Author: Arthur Ulfeldt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-22 23:59:42

Jak wspomniano w tej grupie dyskusyjnej posting, istnieje kilka powodów, dla których używanie alloca może być uważane za trudne i niebezpieczne:

  • nie wszystkie Kompilatory obsługują alloca.
  • Niektóre Kompilatory inaczej interpretują zamierzone zachowanie alloca, więc przenośność nie jest gwarantowana nawet pomiędzy kompilatorami, które ją obsługują.
  • niektóre implementacje są wadliwe.
 37
Author: FreeMemory,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-29 05:43:31

Jeden problem polega na tym, że nie jest standardowy, chociaż jest szeroko obsługiwany. Inne rzeczy są równe, zawsze używam standardowej funkcji, a nie wspólnego rozszerzenia kompilatora.

 25
Author: David Thornley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-19 16:35:44

Nadal stosowanie alloca jest odradzane, dlaczego?

Nie widzę takiego konsensusu. Wiele mocnych plusów; kilka minusów:

  • C99 zapewnia tablice o zmiennej długości, które często będą używane preferencyjnie jako notacja bardziej zgodna z tablicami o stałej długości i intuicyjna całość
  • wiele systemów ma mniej ogólnej pamięci / przestrzeni adresowej dostępnej dla stosu niż dla sterty, co sprawia, że program jest nieco więcej podatne na wyczerpanie pamięci (przez przepełnienie stosu): może to być postrzegane jako dobra lub zła rzecz - jednym z powodów, dla których stos nie rośnie automatycznie tak, jak robi to sterta, jest zapobieganie takiemu niekorzystnemu wpływowi programów poza kontrolą na całą maszynę]}
  • W przypadku użycia w bardziej lokalnym zakresie (takim jak pętla while lub for) lub w kilku zakresach, pamięć gromadzi się w iteracji/zakresie i nie jest zwalniana, dopóki funkcja nie zakończy działania. zdefiniowana w zakresie struktury kontrolnej (np. for {int i = 0; i < 2; ++i) { X } będzie gromadzić alloca-Pamięć ed wymagana w X, ale pamięć dla tablicy o stałej wielkości będzie przetwarzana na iterację).
  • współczesne Kompilatory zazwyczaj nie wywołują inline funkcji, które wywołują alloca, ale jeśli je wymusisz, to alloca stanie się w kontekście wywołujących (tzn. stos nie zostanie zwolniony, dopóki wywołujący nie powróci)
  • dawno temu alloca przeszedłem z nie-przenośnej funkcji / hack na standardowe rozszerzenie, ale niektóre negatywne postrzeganie może utrzymywać
  • Czas życia jest związany z zakresem funkcji, który może, ale nie musi, pasować do programisty lepiej niż jawna kontrola malloc]}
  • konieczność użycia malloc zachęca do myślenia o dealokacji - jeśli jest ona zarządzana za pomocą funkcji wrappera (np. WonderfulObject_DestructorFree(ptr)), to funkcja zapewnia punkt do implementacji operacji czyszczenia (takich jak zamykanie deskryptorów plików, uwalnianie wewnętrznych wskaźników lub rejestrowanie) bez wyraźnych zmian w kliencie kod: czasem jest to dobry model do konsekwentnego
    • w tym pseudo-oo stylu programowania naturalne jest, aby chcieć czegoś w rodzaju WonderfulObject* p = WonderfulObject_AllocConstructor(); - jest to możliwe, gdy "konstruktor" jest funkcją zwracającą malloc - pamięć ed (ponieważ pamięć pozostaje przydzielona po tym, jak funkcja zwraca wartość, która ma być przechowywana w p), ale nie jeśli "konstruktor" używa alloca
      • wersja makra WonderfulObject_AllocConstructor może to osiągnąć, ale "makra są złe", ponieważ mogą ze sobą kolidować i nie-makro kod i tworzyć niezamierzone podstawienia i w konsekwencji trudne do zdiagnozowania problemy
    • brakujące operacje free mogą być wykryte przez ValGrind, Purify itp. niektóre implementacje alloca() (takie jak GCC) używają wbudowanego makra dla alloca(), więc zastępowanie biblioteki diagnostycznej użycia pamięci nie jest możliwe w taki sposób, w jaki jest to możliwe. malloc/realloc/free (np. ogrodzenie elektryczne)
  • niektóre implementacje mają subtelne problemy: na przykład ze strony podręcznika systemu Linux:

    W wielu systemach nie można użyć alloca() wewnątrz listy argumentów wywołania funkcji, ponieważ przestrzeń stosu zarezerwowana przez alloca () pojawiałaby się na stosie w środku przestrzeni dla argumentów funkcji.


Wiem, że to pytanie jest oznaczone C, ale jako programista C++ pomyślałem, że użyję C++ aby zilustrować potencjalną użyteczność alloca: poniższy kod (i tutaj w ideone) tworzy wektor śledzący różnej wielkości typy polimorficzne, które są przydzielane stosem (z czasem życia związanym z powrotem funkcji), a nie przydzielane stosem.

#include <alloca.h>
#include <iostream>
#include <vector>

struct Base
{
    virtual ~Base() { }
    virtual int to_int() const = 0;
};

struct Integer : Base
{
    Integer(int n) : n_(n) { }
    int to_int() const { return n_; }
    int n_;
};

struct Double : Base
{
    Double(double n) : n_(n) { }
    int to_int() const { return -n_; }
    double n_;
};

inline Base* factory(double d) __attribute__((always_inline));

inline Base* factory(double d)
{
    if ((double)(int)d != d)
        return new (alloca(sizeof(Double))) Double(d);
    else
        return new (alloca(sizeof(Integer))) Integer(d);
}

int main()
{
    std::vector<Base*> numbers;
    numbers.push_back(factory(29.3));
    numbers.push_back(factory(29));
    numbers.push_back(factory(7.1));
    numbers.push_back(factory(2));
    numbers.push_back(factory(231.0));
    for (std::vector<Base*>::const_iterator i = numbers.begin();
         i != numbers.end(); ++i)
    {
        std::cout << *i << ' ' << (*i)->to_int() << '\n';
        (*i)->~Base();   // optionally / else Undefined Behaviour iff the
                         // program depends on side effects of destructor
    }
}
 21
Author: Tony Delroy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-23 02:50:57

Wszystkie pozostałe odpowiedzi są poprawne. Jeśli jednak rzecz, którą chcesz alloc używając alloca() jest dość mała, myślę, że jest to dobra technika, która jest szybsza i wygodniejsza niż użycie malloc() lub w inny sposób.

Innymi słowy, alloca( 0x00ffffff ) jest niebezpieczny i może powodować przepełnienie, dokładnie tak samo jak char hugeArray[ 0x00ffffff ]; jest. Bądź ostrożny i rozsądny, a wszystko będzie dobrze.

 11
Author: JSBձոգչ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-19 16:32:27

Wszyscy już zwrócili uwagę na wielką rzecz, którą jest potencjalne niezdefiniowane zachowanie z przepełnienia stosu, ale powinienem wspomnieć, że środowisko Windows ma świetny mechanizm, aby złapać to za pomocą ustrukturyzowanych WYJĄTKÓW (SEH) i stron strażników. Ponieważ stos rośnie tylko w razie potrzeby, te strony ochronne znajdują się w obszarach, które nie są przydzielone. Jeśli przydzielisz do nich (przez przepełnienie stosu), zostanie wyrzucony wyjątek.

Możesz złapać ten wyjątek SEH i wywołać _resetstkoflw, aby zresetować stos i kontynuować na swojej wesołej drodze. Nie jest idealny, ale jest to kolejny mechanizm, aby przynajmniej wiedzieć, że coś poszło nie tak, gdy coś trafi w wentylator. * nix może mieć coś podobnego, o czym Nie wiem.

Zalecam ograniczenie maksymalnego rozmiaru alokacji przez owinięcie alloca i śledzenie go wewnętrznie. Jeśli byłeś naprawdę hardcore o tym, można rzucić niektóre wartowników zakresu na górze swojej funkcji, aby śledzić wszelkie alokacje alloca w zakresie funkcji i sanity sprawdzić to przed Maksymalna kwota dozwolona dla Twojego projektu.

Poza tym, że alloca nie pozwala na wycieki pamięci, nie powoduje fragmentacji pamięci, co jest dość ważne. Nie sądzę, że alloca jest złą praktyką, jeśli używasz jej inteligentnie, co jest w zasadzie prawdą dla wszystkiego. :-)

 11
Author: SilentDirge,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-21 16:19:04

Oto dlaczego:

char x;
char *y=malloc(1);
char *z=alloca(&x-y);
*z = 1;

Nie, żeby ktoś napisał ten kod, ale argument o rozmiarze, który przekazujesz alloca prawie na pewno pochodzi z jakiegoś rodzaju danych wejściowych, które złośliwie mogłyby doprowadzić Twój program do alloca czegoś wielkiego. W końcu, jeśli rozmiar nie jest oparty na danych wejściowych lub nie ma możliwości być duży, dlaczego po prostu nie zadeklarowałeś małego bufora lokalnego o stałym rozmiarze?

Praktycznie cały kod używający alloca i/lub C99 vlas ma poważne błędy, które doprowadzą do awarie (jeśli masz szczęście) lub kompromis z przywilejami(jeśli nie masz tyle szczęścia).

 9
Author: R..,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-06 06:30:38

Alloca () jest miła i skuteczna... ale jest również głęboko złamany.

  • broken Scope behavior (function scope zamiast Block scope)
  • użyj niekonsekwentnego z malloc ( alloca () -ted pointer nie powinien być wolny, od tej pory musisz śledzić, skąd pointer pochodzi do free () tylko tych, których masz z malloc())
  • bad behavior when you also use inlining (scope sometimes goes to the caller function depending if callee is inlined or not).
  • no stack boundary check
  • undefined behavior in case of failure (nie zwraca NULL jak malloc... a co oznacza awaria, ponieważ i tak nie sprawdza granic stosu...)
  • nie standard ansi

W większości przypadków można go zastąpić za pomocą zmiennych lokalnych i wielkości głównej. Jeśli jest używany do dużych przedmiotów, umieszczenie ich na stosie jest zwykle bezpieczniejszym pomysłem.

Jeśli naprawdę potrzebujesz C, możesz użyć VLA(brak vla w C++, szkoda). Oni są znacznie lepsze niż alloca() pod względem zachowania zakresu i spójności. Z tego co widzę to VLA są rodzajem alloca () zrobionym dobrze.

Oczywiście lokalna struktura lub tablica używająca majoranta potrzebnej przestrzeni jest jeszcze lepsza, a jeśli nie masz takiej majorantowej alokacji sterty za pomocą plain malloc (), prawdopodobnie jest rozsądna. Nie widzę żadnego rozsądnego przypadku użycia, w którym naprawdę naprawdę potrzebujesz alloca() lub VLA.

 9
Author: kriss,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-17 08:48:02

Wiele ciekawych odpowiedzi na to "stare" pytanie, nawet kilka stosunkowo nowych odpowiedzi, ale nie znalazłem żadnej, która o tym wspomina....

Przy prawidłowym i ostrożnym stosowaniu, konsekwentne stosowanie alloca() (być może w całej aplikacji) do obsługi małych przydziałów o zmiennej długości (lub C99 VLAs, jeśli jest dostępny) może prowadzić do niższego ogólnego stosu wzrost niż równoważna implementacja z wykorzystaniem ponadgabarytowych tablice lokalne o stałej długości. Więc alloca() może być dobre dla Twojego stosu jeśli używasz go ostrożnie.

Znalazłem ten cytat w.... Zmyśliłem ten cytat. Ale naprawdę, pomyśl o tym....

@j_random_hacker ma rację w swoich komentarzach pod innymi odpowiedziami: unikanie używania alloca() Na Rzecz zbyt dużych tablic lokalnych nie czyni Twojego programu bezpieczniejszym od przepełnień stosu (chyba że Twój kompilator jest wystarczająco stary, aby pozwolić na inlining funkcji, które używają alloca() W takim przypadku powinieneś uaktualnić, lub jeśli nie używasz użyj alloca() wewnątrz pętli, w takim przypadku powinieneś... nie używać alloca() wewnątrz pętli).

Pracowałem w środowiskach desktopowych / serwerowych i systemach wbudowanych. Wiele systemów wbudowanych w ogóle nie używa sterty (nawet nie łączy jej obsługa), z powodów, które obejmują postrzeganie, że dynamicznie przydzielana pamięć jest zła ze względu na ryzyko wycieków pamięci w aplikacji, która nigdy nie uruchamia się ponownie przez lata, lub bardziej rozsądne uzasadnienie, że pamięć dynamiczna jest niebezpieczna ponieważ nie można być pewnym, że aplikacja nigdy nie fragmentuje swojej sterty do punktu fałszywego wyczerpania pamięci. Tak więc wbudowani Programiści pozostają z kilkoma alternatywami.

alloca() (lub VLAs) może być właściwym narzędziem do tego zadania.

Widziałem time & time again, gdzie programista robi przydzielany stos bufor "wystarczająco duży, aby obsłużyć każdą możliwą sprawę". W głęboko zagnieżdżonym drzewie wywołań, wielokrotne użycie tego (anty -) wzór prowadzi do przesadnego użycia stosu. (Imagine a drzewo wywołań 20 poziomów głębokich, gdzie na każdym poziomie z różnych powodów funkcja ślepo naddziela bufor 1024 bajtów "tylko dla bezpieczeństwa", gdy ogólnie będzie używać tylko 16 lub mniej z nich, a tylko w bardzo rzadkich przypadkach może użyć więcej.) Alternatywą jest użycie alloca() lub VLAs i przydzielenie tylko tyle miejsca na stosie, ile potrzebuje twoja funkcja, aby uniknąć niepotrzebnego obciążania stosu. Miejmy nadzieję, że gdy jedna funkcja w drzewie wywołań potrzebuje większej niż normalna alokacji, inne w drzewie wywołań są nadal używają swoich normalnych małych alokacji, a ogólne użycie stosu aplikacji jest znacznie mniejsze niż w przypadku, gdy każda funkcja ślepo nadmiernie alokuje lokalny bufor.

Ale jeśli zdecydujesz się użyć alloca()...

Bazując na innych odpowiedziach na tej stronie, wydaje się, że VLAs powinien być bezpieczny (nie składają alokacji stosu, jeśli są wywoływane z pętli), ale jeśli używasz alloca(), uważaj, aby nie używać go wewnątrz pętli, i upewnij się, że twoja funkcja nie może być inlined, jeśli jest szansa, że zostanie wywołana w pętli innej funkcji.

 9
Author: phonetagger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-31 22:25:32

Miejsce, w którym alloca() jest szczególnie niebezpieczne niż malloc(), to jądro-jądro typowego systemu operacyjnego ma stałą przestrzeń stosu zakodowaną na twardo w jednym z jego nagłówków; nie jest tak elastyczne jak stos aplikacji. Wywołanie alloca() o nieuzasadnionym rozmiarze może spowodować awarię jądra. Niektóre Kompilatory ostrzegają przed użyciem alloca() (a nawet VLAs) pod pewnymi opcjami, które powinny być włączone podczas kompilacji kodu jądra - tutaj lepiej jest przydzielić pamięć w stercie, która nie jest ustalona przez twardo zakodowany limit.

 7
Author: Sondhi Chakraborty,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-13 11:01:01

Niestety naprawdę niesamowite alloca() brakuje z prawie niesamowite tcc. Gcc mA alloca().

  1. Sieje ziarno własnej destrukcji. Z powrotem jako Destruktor.

  2. Podobnie jak malloc() zwraca nieprawidłowy wskaźnik fail, który będzie segfault na nowoczesnych systemach z MMU (i miejmy nadzieję, że ponownie uruchomi te bez).

  3. W przeciwieństwie do zmiennych auto można określić rozmiar w czasie wykonywania.

Działa dobrze z rekurencją. Możesz użyj zmiennych statycznych, aby osiągnąć coś podobnego do rekurencji ogonowej i użyj tylko kilku innych informacji przekazywanych do każdej iteracji.

Jeśli naciskasz zbyt głęboko, masz pewność, że segfault (jeśli masz MMU).

Zauważ, że malloc() nie oferuje więcej, ponieważ zwraca NULL (które również będzie segfault, jeśli zostanie przypisane), gdy system nie ma pamięci. Wszystko, co możesz zrobić, to wpłacić kaucję lub po prostu spróbować ją przypisać w jakikolwiek sposób.

Aby użyć malloc() używam globali i przypisuję im NULL. Jeśli wskaźnik nie jest NULL i wolny to przed użyciem malloc().

Możesz również użyć realloc() jako ogólnego przypadku, jeśli chcesz skopiować istniejące dane. Musisz sprawdzić wskaźnik przed treningiem, jeśli zamierzasz skopiować lub połączyć po realloc().

3.2.5.2 zalety alloca

 4
Author: zagam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-10 22:52:00

Jeśli przypadkowo zapiszesz poza blokiem przydzielonym za pomocą alloca (Na przykład z powodu przepełnienia bufora), to nadpiszesz adres zwrotny swojej funkcji, ponieważ ten znajduje się "powyżej" na stosie, tzn. po przydzielonym bloku.

_alloca blok na stosie

Konsekwencją tego jest dwukrotność:

  1. Program ulegnie spektakularnej awarii i nie będzie można powiedzieć, dlaczego i gdzie się rozbił (stos najprawdopodobniej z powodu nadpisanego wskaźnika ramki).

  2. Powoduje to, że przepełnienie bufora jest wielokrotnie bardziej niebezpieczne, ponieważ złośliwy użytkownik może stworzyć specjalny ładunek, który zostanie umieszczony na stosie, a tym samym może zakończyć się wykonaniem.

W przeciwieństwie, jeśli piszesz poza blokiem na stercie," po prostu " dostajesz korupcję sterty. Program prawdopodobnie zakończy się nieoczekiwanie, ale rozwiąże stos prawidłowo, zmniejszając w ten sposób szansę na złośliwy kod egzekucja.

 4
Author: rustyx,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-03 14:09:56

Myślę, że nikt o tym nie wspomniał: użycie alloca w funkcji utrudni lub wyłączy pewne optymalizacje, które w przeciwnym razie mogłyby zostać zastosowane w funkcji, ponieważ kompilator nie może znać rozmiaru ramki stosu funkcji.

Na przykład, powszechną optymalizacją kompilatorów C jest wyeliminowanie użycia wskaźnika ramki w funkcji, dostęp do ramki jest wykonywany względem wskaźnika stosu; więc jest jeszcze jeden rejestr do ogólnego użytku. Ale jeśli alloca nazywa się w ramach funkcji różnica między sp i fp będzie nieznana dla części funkcji, więc tej optymalizacji nie można wykonać.

Biorąc pod uwagę rzadkość jego użycia i jego szemrany status jako standardowej funkcji, konstruktorzy kompilatorów prawdopodobnie wyłączają wszelkieoptymalizacje, które mogłyby powodować problemy z alloca, jeśli potrzeba więcej niż trochę wysiłku, aby to działało z alloca.

 4
Author: greggo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-18 19:11:45

Jedną z pułapek z alloca jest to, że longjmp przewraca go.

To znaczy, jeśli zapiszesz kontekst za pomocą setjmp, wtedy alloca trochę pamięci, a następnie {[1] } do kontekstu, możesz stracić alloca pamięć (bez jakiegokolwiek powiadomienia). Wskaźnik stosu jest z powrotem tam, gdzie był, więc pamięć nie jest już zarezerwowana; jeśli wywołasz funkcję lub wykonasz inną alloca, zatrzaśniesz oryginalną alloca.

Dla wyjaśnienia, chodzi mi tu konkretnie o sytuację, w której longjmp nie return out of the function where the alloca was place! Zamiast tego funkcja zapisuje kontekst za pomocą setjmp; następnie przydziela pamięć za pomocą alloca i na koniec następuje longjmp do tego kontekstu. Pamięć alloca tej funkcji nie jest zwalniana; tylko cała pamięć przydzielona od setjmp. Oczywiście mówię o zaobserwowanym zachowaniu; nie udokumentowano żadnego alloca, który znam.

W dokumentacji skupiamy się zazwyczaj na pojęciu, że alloca pamięć jest powiązane z aktywacją funkcji, a nie z żadnym blokiem; że wielokrotne wywołania alloca po prostu chwytają więcej pamięci stosu, która jest zwalniana po zakończeniu funkcji. Nie tak; pamięć jest rzeczywiście związana z kontekstem procedury. Gdy kontekst zostanie przywrócony za pomocą longjmp, tak samo jest z poprzednim stanem alloca. Jest to konsekwencja użycia rejestru wskaźnika stosu do alokacji, a także (koniecznie) zapisywania i przywracania w jmp_buf.

Nawiasem mówiąc, to, jeśli to działa w ten sposób, zapewnia wiarygodny mechanizm celowego uwalniania pamięci, która została przydzielona za pomocą alloca.

Natknąłem się na to jako główną przyczynę błędu.

 4
Author: Kaz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-18 02:25:01

Procesy mają tylko ograniczoną ilość dostępnej przestrzeni stosu-znacznie mniejszą niż ilość pamięci dostępnej dla malloc().

Używając alloca() znacznie zwiększasz szanse na błąd przepełnienia stosu(jeśli masz szczęście, lub niewytłumaczalną awarię, jeśli nie).

 3
Author: RichieHindle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-19 16:27:46

Niezbyt ładny, ale jeśli wydajność naprawdę ma znaczenie, można wstępnie przydzielić trochę miejsca na stosie.

Jeśli już teraz maksymalny rozmiar bloku pamięci, którego potrzebujesz i chcesz zachować kontrolę przepełnienia, możesz zrobić coś takiego:

void f()
{
    char array_on_stack[ MAX_BYTES_TO_ALLOCATE ];
    SomeType *p = (SomeType *)array;

    (...)
}
 2
Author: Sylvain Rodrigue,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-19 17:21:29

Właściwie, alloca nie ma gwarancji, że użyje stosu. Rzeczywiście, implementacja alloca gcc-2.95 przydziela pamięć ze sterty za pomocą samego malloca. Ponadto implementacja jest błędna, może prowadzić do wycieku pamięci i nieoczekiwanego zachowania, jeśli wywołasz ją wewnątrz bloku z dalszym wykorzystaniem goto. Nie, aby powiedzieć, że nigdy nie należy go używać, ale czasami alloca prowadzi do więcej nad głową niż releaves odme.

 2
Author: user7491277,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-30 18:14:22

IMHO, alloca jest uważana za złą praktykę, ponieważ wszyscy boją się wyczerpania limitu rozmiaru stosu.

Wiele się nauczyłem czytając ten wątek i kilka innych linków:

Używam alloca głównie po to, aby moje zwykłe pliki C były kompilowane na msvc i gcc bez żadnych change, C89 style, no # ifdef _MSC_VER, etc.

Dziękuję ! Ten wątek zmusił mnie do zarejestrowania się na tej stronie:)

 0
Author: ytoto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:25

Funkcja alloca jest świetna i wszyscy przeciwnicy po prostu rozprzestrzeniają FUD.

void foo()
{
    int x = 50000; 
    char array[x];
    char *parray = (char *)alloca(x);
}

Array i parray są dokładnie takie same z dokładnie tymi samymi zagrożeniami. Stwierdzenie, że jeden jest lepszy od drugiego jest wyborem składniowym, a nie technicznym.

Jeśli chodzi o wybór zmiennych stosu vs zmiennych stosu, istnieje wiele zalet długich programów używających stack over heap dla zmiennych z okresem życia w zakresie. Unikasz fragmentacji sterty i możesz uniknąć rozwoju procesu przestrzeń z nieużywaną (bezużyteczną) przestrzenią sterty. Nie musisz tego sprzątać. Możesz kontrolować alokację stosu w procesie.

Dlaczego jest źle?
 0
Author: mlwmohawk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-13 21:10:51

Moim zdaniem alloca (), o ile jest dostępna, powinna być używana tylko w sposób ograniczony. Podobnie jak użycie "goto", dość duża liczba rozsądnych ludzi ma silną niechęć nie tylko do używania, ale także do istnienia alloca ().

Do zastosowań wbudowanych, gdzie rozmiar stosu jest znany i limity mogą być narzucane poprzez konwencję i analizę wielkości alokacji, i gdzie kompilator nie może być uaktualniony do obsługi C99+, użycie alloca() jest w porządku, oraz Znam się na tym.

Gdy jest dostępna, VLAs może mieć pewne zalety w stosunku do alloca (): kompilator może generować kontrole limitu stosu, które wychwytują dostęp poza granicami stosu, gdy używany jest dostęp w stylu tablicy (Nie wiem, czy jakikolwiek kompilator to robi, ale można to zrobić), a analiza kodu może określić, czy wyrażenia dostępu do tablicy są poprawnie ograniczone. Należy pamiętać, że w niektórych środowiskach programistycznych, takich jak motoryzacja, sprzęt medyczny i awionika, analiza ta musi być wykonywane nawet dla tablic o stałym rozmiarze, zarówno automatycznej (na stosie), jak i statycznej alokacji (globalnej lub lokalnej).

Na architekturach, które przechowują zarówno dane, jak i adresy zwrotne / wskaźniki ramki na stosie (z tego, co wiem, to wszystkie), każda przydzielona stos zmienna może być niebezpieczna, ponieważ adres zmiennej może być pobrany, a niezaznaczone wartości wejściowe mogą pozwolić na różnego rodzaju psoty.

Przenośność jest mniej niepokojąca w przestrzeni wbudowanej, jednak jest dobrym argumentem przeciwko stosowaniu alloca () poza ściśle kontrolowanymi okolicznościami.

Poza osadzoną przestrzenią używałem alloca() głównie wewnątrz funkcji logowania i formatowania dla wydajności, a także w niekurencyjnym skanerze leksykalnym, gdzie tymczasowe struktury (przydzielane za pomocą alloca () są tworzone podczas tokenizacji i klasyfikacji, a następnie trwały obiekt (przydzielany za pomocą malloc ()) jest wypełniany przed powrotem funkcji. Zastosowanie alloca () dla mniejszych struktur tymczasowych znacznie zmniejsza fragmentację po przydzieleniu trwałego obiektu.

 0
Author: Daniel Glasser,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-13 14:36:17

Większość odpowiedzi tutaj w dużej mierze pomija punkt: istnieje powód, dla którego używanie _alloca() jest potencjalnie gorsze niż zwykłe przechowywanie dużych obiektów w stosie.

Główna różnica między automatycznym przechowywaniem a _alloca() polega na tym, że ten ostatni cierpi na dodatkowy (poważny) problem: alokowany blok nie jest kontrolowany przez kompilator , więc nie ma możliwości, aby kompilator go zoptymalizował lub poddał recyklingowi.

Porównaj:

while (condition) {
    char buffer[0x100]; // Chill.
    /* ... */
}

Z:

while (condition) {
    char* buffer = _alloca(0x100); // Bad!
    /* ... */
}

Problem z to ostatnie powinno być oczywiste.

 -1
Author: alecov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-28 14:31:41