2008-10-15 18 views
6

Lubię mieć ostrzeżenie za darmo dla VS.NET i GCC, i lubię mieć mój 64-bitowy kod gotowy.Przepełnienia w addendach size_t

Dzisiaj napisałem mały moduł, który zajmuje się buforami pamięci i zapewnia dostęp do danych za pośrednictwem interfejsu stylu plików (np. Można czytać bajty, pisać bajty, szukać itd.).

Jako typ danych dla bieżącej pozycji odczytu i rozmiaru użyłem size_t, ponieważ wydaje się to najbardziej naturalnym wyborem. Rozumiem ostrzeżenia i powinno działać również w wersji 64-bitowej.

wszelki wypadek: Moja struktura wygląda następująco:

typedef struct 
{ 
    unsigned char * m_Data; 
    size_t   m_CurrentReadPosition; 
    size_t   m_DataSize; 
} MyMemoryFile; 

uzyskiwany znak size_t wydaje się nie być zdefiniowane w praktyce. Poszukiwania kodu Google udowodniły to.

Teraz mam dylemat: chcę sprawdzić dodatki z size_t za przepełnienia, ponieważ mam do czynienia z danymi dostarczonymi przez użytkownika, a biblioteki osób trzecich będą używać mojego kodu. Jednak w przypadku testu przepełnienia muszę znać znak. Wprowadza ogromną różnicę w implementacji.

Więc - jak do cholery powinienem napisać taki kod w sposób niezależny od platformy i kompilatora?

Czy mogę sprawdzić podpisanie size_t podczas uruchamiania lub kompilacji? To rozwiązałoby mój problem. A może size_t nie był najlepszym pomysłem.

Wszelkie pomysły?

EDIT: Szukam rozwiązania dla języka C!

+0

jakiej wersji gcc używasz? Wygląda na to, że zrobili size_t unsigned w wersjach po i włączając w to 2.4 –

+0

Wersje, z którymi mam do czynienia, są wszędzie. Zajmuję się programowaniem wbudowanym i czasami muszę używać wersji kompilatora z epoki kamienia. –

+0

"Znaki" to zwykłe słowo. – Lassi

Odpowiedz

11

W odniesieniu do tego, czy size 't jest podpisany lub niepodpisane i GCC (ze starego podręcznika GCC - Nie jestem pewien, czy to wciąż istnieje):

Istnieje potencjalny problem z size_t typu i wersje GCC przed do wydania 2.4. ANSI C wymaga, aby size_t był zawsze typu bez znaku. Dla zgodności z plików nagłówkowych istniejących systemów, GCC określa size_t w stddef.h być dowolnego typu definiuje go systemu sys/types.h do być. Większość systemów uniksowych definiujących w sys/types.h jest typem podpisu. Niektóre kody w bibliotece zależą od tego, czy jest to niepodpisany typ size_t i nie będą działać poprawnie, jeśli są podpisane.

Kod biblioteki GNU C, który oczekuje, że size_t będzie niepodpisany, jest poprawny. Definicja jako podpisanego typu size_t jest niepoprawna. Planujemy, że w wersji 2.4 GCC zawsze definiuje size_t jako typ niepodpisany, a skrypt 'fixincludes' masuje system systemu , co nie powoduje konfliktu z tym systemem.

W międzyczasie obejścia tego problemu mówiąc GCC wyraźnie do użyć typu unsigned dla size_t gdy kompilacji biblioteki GNU C. "configure" automatycznie wykryje, jakiego typu GCC używa dla size_t, aby ustawić, jeśli jest to konieczne, aby go zastąpić.

Jeśli chcesz podpisaną wersję size_t użytku ptrdiff_t lub na niektórych systemach jest typedef dla ssize_t.

+1

wow! wielkie dzięki za kopanie historia problemu. –

+2

Musiałem to zrobić dla własnej ciekawości - trudno mi było uwierzyć, że GCC lekceważy całkiem podstawową część standardu bez przyzwoitego wyjaśnienia. –

4

size_t powinien być niepodpisany.

Jest zwykle definiowany jako bez znaku.

Nigdy nie widziałem, żeby było inaczej. ssize_t jest jego podpisanym odpowiednikiem.

EDYTOWANIE: GCC definiuje go jako podpisany w pewnych okolicznościach. kompilacja w trybie ASNI C lub std-99 powinna wymusić jej niepodpisanie.

+0

GCC definiuje size_t jako podpisane :( –

+0

Nie jest podpisane długie 32 bity w oknach 64-bitowych? Nie jest dobrym założeniem dla size_t. – ejgottl

+0

g ++ 4.2.3 definiuje to jako unsigned .. – ejgottl

0

Użyj safeint. Jest to klasa zaprojektowana przez Michaela Howarda i wydana jako open source firmy Microsoft. Został zaprojektowany do pracy z liczbami całkowitymi, w których przepełnienie jest identyfikowane jako ryzyko. Wszystkie przepełnienia są konwertowane na wyjątki i obsługiwane. Klasa została zaprojektowana tak, aby ułatwić prawidłowe użytkowanie.

Na przykład:

char CouldBlowUp(char a, char b, char c) 
{ 
    SafeInt<char> sa(a), sb(b), sc(c); 

    try 
    { 
    return (sa * sb + sc).Value(); 
    } 
    catch(SafeIntException err) 
    { 
     ComplainLoudly(err.m_code); 
    } 

    return 0; 
} 

także safeint służy wiele wewnętrznie w firmie Microsoft w produktach takich jak Office.

Ref: link text

+0

Nie mogę używać SaveInt, jestem C-only, a afaik saveint nie rozwiązuje problemu sign-ness, a także ponieważ przyjmuje założenia domyślne z msvc. –

+0

Dobrze, pytanie było początkowo oznaczone jako C++.Zobacz moją drugą odpowiedź dla biblioteki w języku C. –

+0

Tak - wiem, przepraszam, edytowałem pytanie, aby upewnić się, że nie wprowadzam w błąd ktoś inny –

0

Nie jestem pewien, czy rozumiem pytanie dokładnie, ale może można zrobić coś takiego:

temp = value_to_be_added_to; 

value_to_be_added_to += value_to_add; 

if (temp > value_to_be_added_to) 
{ 
    overflow... 
} 

ponieważ będzie zawijać z powrotem do niższych wartości, można łatwo sprawdzić jeśli się przepełnił.

+0

Co jeśli wartość_do_add jest ujemna? –

+0

Sprawdź, czy nie. –

2

Dla języka C użyj IntSafe. Również wydany przez Microsoft (nie mylić z biblioteką C++ SafeInt). IntSafe to zestaw wywołań funkcji języka C, które mogą wykonywać matematykę i wykonywać konwersje bezpiecznie. updated URL for intsafe functions

4

size_t jest całkowitym typem bez znaku, zgodnie ze standardami C++ C. Każda implementacja, która ma podpisaną size_t, jest poważnie niezgodna i prawdopodobnie ma również inne problemy z przenośnością. Gwarantuje to zawijanie się po przepełnieniu, co oznacza, że ​​można napisać testy, takie jak if (a + b < a), aby znaleźć przepełnienie.

size_t to doskonały typ do wszystkiego, co dotyczy pamięci. Robisz to dobrze.