Jak sprawdzić czy adrres należy do sterty?

0

Witam,
Mam dany wskaźnik i potrzebuję sprawdzić czy ten wskaźnik wskazuje na adres należący do sterty. Innymi słowy muszę napisać funkcję, która zwróci true jeżeli wskaźnik jest właściwym adresem na stercie i zwróci false w przeciwnym wypadku. Funkcja nie musi być przenośna - docelowy system to Linux ale rozwiązaniami na inne systemy również nie pogardzę :)

0

hym

wydaje mi sie, ze stos jest jednolitym, alignowanym blokiem pamieci.
jesli tak jest, to -

  • odczytac z binarki rozmiar stosu
  • stworzyc zmienna int tab[0]; czy cokowiek - bedzie ona na stosie
  • pobrac jej adres
  • wyzerowac mlodsze boty adresu zgodnie z rozmiarem stosu
  • et voil'a, masz adres bazowy stosu, acz glowe dam ze da sie jakos to prosciej osiagnac :)
  • majac go, porownaj PTR z adresem bazowym stosu. jesli PTR jest poza (po) czubkiem stosu lub dalej niz stacksize (przed) od czubka stosu, to znaczy ze NIE jest na stosie

teraz tylko pozostaje wykluczyc

  • obszary systemowe
  • obszary kodu
  • shmem/mapfile/...

ooo sluchaj, mam genialna w swej prostocie metode
wywolaj na tym delete/free -- jak nie bedzie sigsegv, znaczy sie, sterta ]:>

a tak na serio.. poza przedlubaniem sie przez bebechy malloc/new/free/delete, nie mam pomyslu..

0
quetzalcoatl napisał(a)

ooo sluchaj, mam genialna w swej prostocie metode
wywolaj na tym delete/free -- jak nie bedzie sigsegv, znaczy sie, sterta ]:>

są jeszcze zmienne globalne, które dadzą ten sam efekt.
ja bym zrobił zgodnie z pierwotnym pomysłem, zapamiętał dno stosu, a potem testował czy adres jest w odpowiednim zakresie. Czyli coś w tym stylu:

class isItOnStack
{
   static void* stackBottom; // zapamiętać dno stosu za pomocą jakiegoś obiektu automatycznego

public:
   isItOnStack(int dumy);
   static bool test(void* pinter);
};

void* isItOnStack::stackBottom = 0;
isItOnStack::isItOnStack(int dumy)
{
     stackBottom = &dumy;
}

bool isItOnStack::test(void* pointer)
{
    return pointer<=stackBottom && pointer > &pointer; // w x86 stos adres maleje wraz ze wzrostem stosu, dla innych procesorów może być konieczny jakiś #ifdef SYMBOL
}

static isItOnStack initializer(0);

Nie testowałem, nie jestem pewien czy to zadziała, sam spróbuj.

Swoją drogą mam ważnie, że coś masz źle zaprojektowane. Napisz po co to potrzebujesz to może znajdziemy ci jakieś lepsze rozwiązanie. Np można tak skontrować klasę w ten sposób, by nie dało się jej obiektu stworzyć poza stertą.

0

btw. nie napisalem tego wprost, ale testowanie czy-NIE-jest-na-stosie != czy-jest-na-stercie, a autor pyta o to drugie..

są jeszcze zmienne globalne, które dadzą ten sam efekt

i wiele innych rzeczy tez. z delete/free to byl zart, myslalem ze oczywisty:)

Swoją drogą mam ważnie, że coś masz źle zaprojektowane. Napisz po (..)

tez tak sadze.. bardzo nietypowa rzecz chcesz sprawdzic

0

Przymierzam się do napisania garbage collectora dla c++ i zbieram informację. Chcę użyć algorytmu mark-and-sweep i generalnie w tym algorytmie muszę przejrzeć adresy wszelkich wskaźników, czy przypadkiem nie wskazują na obszar sterty (conservative gc).
Z tego co piszecie to raczej ciężka sprawa, więc pomyślałem, że zrobię sobie swoją "wirtualną" stertę (zaalokowany blok pamięci), w której będę przeprowadzał alokację.

0

Czyli nie powinno być problemu. Masz jakaś klasę bazową, która ma licznik referencji. Przeciążasz operator new dla tej klasy bazowej i w tym operatorze zapamiętujesz listę wskaźników do wszystkich tworzonych obiektów. W operatorze new sprawdzasz czy nie ma problemu z alokowaniem pamięci, jeśli jest, to sprawdzasz w swojej liście czy masz jakieś obiekty do usunięcia (licznik referencji osiągnął limit) i je usuwasz. Nie jest konieczne żadne sprawdzanie, gdzie obiekt został stworzony.

0

Na pewno jest mi potrzebna informacja, jaki obiekt, jakie inne obiekty zaalokował - tak żebym mógł później odtworzyć graf alokacji. Do tego zwykłe przeciążenie new chyba nie wystarczy?

0

Masz racje to nie wystarczy, ale ten problem nie ma nic wspólnego z wiedzą, gdzie dany obiekt istnieje, a tak jak przeciążysz operator new to masz już listę obiektów na stercie. Graf alokacji to już zupełnie inna bardziej skomplikowana bajka.

0

Ok, w takim razie listę zaalokowanych obiektów już mam. I teraz znowu pytanie, czy przypadkiem funkcja, która sprawdzała by czy dany wskaźnik jednak nie była by przydatna. Żeby zbudować taki graf referencji muszę przejść się po zaalokowanej pamięci dla wszystkich obiektów i sprawdzać każdą wartość w pamięci czy przypadkiem nie jest wskaźnikiem na stertę. Mógłbym wziąć najmniejszy i największy adres ze wszystkich obiektów na mojej liście i sprawdzać czy dana wartość mieści się między tym zakresem. Brzmi sensownie, tylko czy na pewno zadziała?

0
rnd napisał(a)

po zaalokowanej pamięci dla wszystkich obiektów i sprawdzać każdą wartość w pamięci czy przypadkiem nie jest wskaźnikiem na stertę

ujmujac trywialnie: zastanawiales sie jak odroznisz przypadkowe dane liczbowe od wlasciwych wskaznikow? a mniej trywialnie: jak zapewnisz zeby kod po automatycznej optymalizacji nadal spelnial zasady ktorych sadzisz ze C++ sie trzyma?:)

0

Popatrz sobie jak to zrobili panowie Boehm, Demers i Weiser w swoim odśmiecaczu: http://www.hpl.hp.com/personal/Hans_Boehm/gc/. Powinny tam gdzieś być źródełka.

0

ujmujac trywialnie: zastanawiales sie jak odroznisz przypadkowe dane liczbowe od wlasciwych wskaznikow? a mniej trywialnie

Jeżeli chodzi o pierwsze pytanie to odpowiedź jest prosta: ze 100% pewnością nie odróżnie. Taką heurystyką działającą w w sporej ilości przypadków jest właśnie sprawdzania czy dana wartość trafia w zakres sterty. Po to z resztą mi właśnie było te sprawdzenie jaki jest zakres zaalokowanej sterty. Dodatkowo do każdego zaalokowanego obiektu będe dołączał swoją sygnaturkę tak, więc szansa na pomyłkę dalej maleje.

jak zapewnisz zeby kod po automatycznej optymalizacji nadal spelnial zasady ktorych sadzisz ze C++ sie trzyma?:)

Właśnie się zastanawiałem czy na pewno moje rozumowanie jest poprawne w bardziej egzotycznych przypadkach. A możesz powiedzieć jakich dziwnych optymalizacji używa C++, które mogły by mi zepsuć mój pomysł? Założenie jakie robię to, że obszar stery jest liniowy: czyli jeżeli mam wskaźnik o najmniejszej wartości adresu i największej wartości adresu to bez segfaulta mogę się odwołać do obszaru pomiędzy tymi dwoma wskaźnikami. Tego najbardziej nie jestem pewien.

0

Aby w sposób konserwatywny, sprawdzić czy dany obszar pamięci jest wskazywany z poziomu programu, musisz przeskanować: stos, stertę oraz rejestry procesora.

Dokładnie tak działa odśmiecacz Boehm GC, stosując konserwatywne odśmiecanie. Niestety, ten typ odśmiecania jest niedokładny i powoduje wycieki pamięci.

Jeżeli chcesz wiedzieć z jakich obszarów sterty korzysta program, najlepiej przeciążyć globalne operatory new oraz delete i zapamiętywać położenie aktywnych obszarów.

Jeżeli chciałbyś poznać adres stosu, to powinieneś skorzystać z funkcji systemowej która takie informacje zwraca. W Windows położenie stosu można odczytać tak:

MEMORY_BASIC_INFORMATION mbi;
int a; // zmienna lokalna, przechowywana na stosie
::VirtualQuery(&a, &mbi, sizeof(mbi));

size_t begin = reinterpret_cast<size_t>(mbi.AllocationBase);
size_t end = reinterpret_cast<size_t>(mbi.BaseAddress) + mbi.RegionSize;

Do funkcji systemowej przekazuje się adres, który mieści się w zakresie poszukiwanego obszaru (w tym przypadku stosu).

Trzeba jeszcze pamiętać, że każdy wątek ma własny stos.

Powyższą funkcję systemową wykorzystałem we własnym odśmiecaczu dla języka C++: http://sourceforge.net/projects/sgcl/
Jest to precyzyjny, współbieżny system odśmiecania, oparty na algorytmie Mark & Sweep.

Gdybyś dowiedział się, jaką funkcją systemową można pod Linuksem odczytać lokalizację stosu, to podziel się ta informacją - chętnie skorzystam. Niestety mój odśmiecacz działa tylko na Windows, bo nie udało mi się znaleźć odpowiednika funkcji VirtualQuery na Linuksie.</url>

0

Dzięki za linka.
Na Linuksie do pobierania adresu stosu służy funkcja:
pthread_attr_getstack - potrzebuje ona struktury pthread_attr, którą z kolei można pobrać funkcją: pthread_getattr_np
To nie jest funkcja standardu POSIX, zanjduje się w bibliotece glibc. Na to wygląda, że używając tylko funkcji POSIXa nie da się pobrać informacji o wątku.
Tak więc w teorii pobieranie adresu i rozmiaru stosu w głównym wątku teoretycznie wygląda tak:

    pthread_attr_t attr;
    pthread_t self;
    void* addr = 0;
    size_t size = 0;

    self = pthread_self();
    pthread_getattr_np(self, &attr);
    pthread_attr_getstack(attr, &addr, &size);

Niestety funkcja pthread_getattr_np ma buga i zwraca błędne informacje dla głównego wątku (dla innych wątków działa ok). No i teraz szukam jak to obejść. Przeglądałem źródła programu pmap i tam adres stosu jest po prostu odczytywany z katalogu /proc/pid. Takie rozwiązanie nie wydaje mi się zbytnio przenośne. Znalazłem jeszcze takiego linka: http://www.mail-archive.com/[email protected]/msg01646.html . Tutaj ktoś korzysta z biblioteki guile, ale jeszcze nie przeglądałem kodu tej biblioteki. Jak dowiem się czegoś jescze to dam znać.

0

tutaj akurat jestem juz kompletnie zielony, ale moze to nie bug, tylko to, ze glowny watek procesu nie byl otwierany funkcjami z pthread.. /proc/pid wydaje mi sie mimo wszystko dosc przenosne pomiedzy linuksami - w sensie, na kazdym linuksie w proc'u znajdziesz informacje o aktualnych procesach, genrowane przez jadro, wiec w ramach tej samej klasy/wersji kernela te informajce powinny tam siedziec wszedzie..

co do wspomnianych optymalizacji - generalnie nie chodzi o mape pamieci procesu, to powiedzmy gwarantuje system, ale o to, jak zoptymalizowany program korzysta z rejestrow.. nie opowiem Ci na ten temat za wiele, sprobuj sie dostac do deus'a, usadzil mnie kiedys w tej kwestii jak probowalem sam podobny GC napisac.

0

Znalazłem w końcu trochę czasu i sprawdziłem jak to robi GC pana Boehma. Adres jest zczytywany z /proc/self/stat . Jak dla mnie 1:0 dla Api Windowsa ;P

0
MarekR22 napisał(a)

można tak skontrować klasę w ten sposób, by nie dało się jej obiektu stworzyć poza stertą.

Czy możesz napisać jak to zrobić?</quote>

0
pppo napisał(a)
MarekR22 napisał(a)

można tak skontrować klasę w ten sposób, by nie dało się jej obiektu stworzyć poza stertą.

Czy możesz napisać jak to zrobić?
</quote>Prywatny (ew. chroniony) konstruktor + statyczna metoda tworząca obiekt?

1 użytkowników online, w tym zalogowanych: 0, gości: 1