2013-10-22 13 views
5

Przechodzę przez książkę K & R i odpowiedź na jedno z ćwiczeń mnie niepokoi.Przepełnienie tablicy bloków znaków, dobra praktyka?

W podręczniku rozwiązań, ćwiczenia 1-22 deklaruje tablicę char:

#define MAXCOL 10 
char line[MAXCOL]; 

więc moje zrozumienie, że w C tablice przejść od 0 ... n-1. W takim przypadku powyższa deklaracja powinna przydzielić pamięć dla tablicy znaków o długości 10 zaczynającej się od 0 i kończącej się na 9. Więcej do linii punktowej [10] jest poza granicami według mojego zrozumienia? Funkcja w programie próbki jest następnie przekazywany do wartości całkowitą POS jest równe 10, a następujące porównanie odbywa:

int findblnk(int pos) { 
while(pos > 0 && line[pos] != ' ') 
     --pos; 
    if (pos == 0)     //no blanks in line ? 
     return MAXCOL; 
    else      //at least one blank 
     return pos+1;    //position after blank 
} 

Jeśli pos jest 10 i przewód [] jedynie o długości 10, wówczas nie jest linia [pos] poza granicami tablicy?

Czy można porównywać w ten sposób w C, czy może to potencjalnie prowadzić do błędu segmentacji? Jestem pewien, że podręcznik do rozwiązywania problemów jest słuszny, tylko mnie to zdezorientowało. Również w razie potrzeby mogę opublikować cały program. Dzięki!

Dzięki za szybkie i bardzo pomocne odpowiedzi, myślę, że jest to z pewnością błąd. Nazywa się przez następujący oddział:

else if (++pos >= MAXCOL) { 
      pos = findblnk(pos); 
      printl(pos); 
      pos = newpos(pos); 
     } 

MAXCOL jest zdefiniowany jako 10, jak podano powyżej. Tak więc dla tego oddziału findblnk (pos) pos zostałaby zaliczona jako minimum 10.

Czy uważasz, że instrukcja rozwiązania dla K & R jest warta przejścia lub jest znana z przykładów z błędnym kodem?

+1

Należy zauważyć, że adres 'pos [10]' ma gwarantowaną wartość OK (będzie on ważny, a jeden bajt poza 'pos [9]'). Próba dostępu do wartości w 'pos [10]', albo do odczytu lub zapisu, jest niezdefiniowanym zachowaniem. Wszystko może się zdarzyć, gdy wywołasz niezdefiniowane zachowanie, w tym "wydaje się działać" lub "awaria komputera" lub ... –

Odpowiedz

2

Jest nigdy, kiedykolwiek porządku oblężone granice tablicy w C (lub dowolnego języka naprawdę).

Jeśli 10 zostało przekazanych do tej funkcji, to z pewnością jest to błąd. Chociaż istnieją lepsze sposoby robienia tego, funkcja ta powinna przynajmniej sprawdzić, czy pos znajduje się w granicach line przed próbą użycia go jako indeksu.

3

Jeśli pos jest rzeczywiście 10 wtedy byłoby poza granicami dostępu i uzyskiwania dostępu do tablicy poza boiskiem jest undefined behavior a więc wszystko może się zdarzyć nawet program, który wydaje się działać prawidłowo w momencie, wyniki są niewiarygodne. Projekt normy C99 Annex J.2niezdefiniowane zachowanie zawiera następujące pocisku:

indeks tablicy znajduje się poza zasięgiem, nawet jeśli obiekt jest najwyraźniej dostępny z danej indeksu (jak w lwartości ekspresji w [1] [7] ze względu na deklarację int a [4] [5]) (6.5.6).

nie mam kopię K & R poręczny ale errata nie wymienia nic dla tego problemu. Domyślam się, że warunkiem jest < zamiast >=.

2

Powyższy kod jest w porządku tak długo, jak pos == 9, gdy jest przekazywany do tej funkcji.Jeśli pos ==10 po przejściu, a następnie jego niezdefiniowane zachowanie i .. masz rację, należy tego unikać.

Jednak może to świadczyć o usterce segmentacji lub nie.

1

my_type buffer[SOME_CONSTANT_NAME]; prawie zawsze jest błędem.

Kod taki jak ten, który podajesz w pytaniu, jest źródłem większości problemów związanych z bezpieczeństwem: kiedy przepełnienie bufora wywołuje niezdefiniowane zachowanie, a niezdefiniowane zachowanie (jeśli nie powoduje bezpośrednio awarii programu) może być często wykorzystywane przez napastników do wykonywania własnego kodu w ramach procesu.

Moja rada to trzymać się z dala od wszystkich ustalonych rozmiarów buforów i albo użyć C++ 's std::vector<> lub dynamicznie przydzielić wystarczającą ilość pamięci do dopasowania. Standard Posix 2008 sprawia, że ​​jest to całkiem łatwe nawet w wersji C dzięki funkcji asprintf() i znajomym.

Powiązane problemy