LINUX.ORG.RU

linux, plain C, bounds checking — как?


0

2

Хочется -fbounds-check или что-то аналогичное, да что угодно, для C. Как? Есть http://sourceforge.net/projects/boundschecking — он дата последнего обновления в 2005г. сильно смущает, как и необходимость патчить GCC. Удивительно, но все .gcc современные имеют неработающий ключ -fbounds-check и ничего в документации. Valgrind тоже не в помощь. Статический анализ хорошо, но хотелось бы в динамике. Как?


Ответ на: комментарий от anonymous

Можно конкретизировать? А то напрашиваются другие три буквы скорей.

fk0
() автор топика

Есть еще -fstack-protector, не совсем то, но для стековых массивов поможет.

anonymous
()
Ответ на: комментарий от anonymous

без переписывания исходников - никак.

Исходники, разумеется, есть. Но втыкать ассерты и трястись за то, что в очередном месте забудешь воткнуть... плохой вариант. Других способов я не знаю. Хотелось бы скомпилировать с проверкой границ, позапускать по-разному (пока объём code coverage не удовлетворит) и на этом успокоиться.

fk0
() автор топика

Либо проверка границ, либо сишечка. Выбирать тебе. Третьего не дано, си слишком низкоуровневый для этого.

unC0Rr ★★★★★
()
Ответ на: комментарий от no-such-file

Пример кода, вызывающий редкостные глюки «фиг поймаешь»:

enum e_gevent_notify efilter_type(enum e_gevent event, uintptr_t data) { uint_fast8_t i, b, type; /* этого ассерта не было assert(event!=0); */ i=(uint_fast8_t)(EVENT_FILT_BITS*(event-1))>>3; b=(uint_fast8_t)(EVENT_FILT_BITS*(event-1))&7; type = (CONFIG(events_filt) >> b) & EVENT_FILT_MASK; ...

Вызывается совершенно наивно с event=0 (хотя предполагается, что не должен). Отловить все такие места трудно. Хуже того, в случае сглючивания явно плохих последствий не вызывает, только нехорошие подозрения в адрес совершенно другой части кода.

Поймано было просто потому, что именно на 16-битном микроконтроллере, у которого sizeof(uint_fast8_t)==2 вместо тихого подглючивания громко сваливался (i = 0xfffe в последней строчке) из-за промаха мимо ОЗУ (причём дааалеко не каждый раз). На 8-битных и на IBM-PC незаметно и тихо глючит из-за умения нормально побайтно обращаться с 8-битными данными.

Запилить свой тип нереально ввиду того, что компилятор только plain C only (уже только наличие частичной реализации C99 и некоторых расширений GCC можно считать за великое счастье...)

fk0
() автор топика
Ответ на: комментарий от anonymous

valgrind

valgrind изкоробки не умеет. что-то очень экспериментальное? А как он, собственно, узнает границы массива, если на этапе компиляции на это болт забили? Мне кажется, притянуто за уши.

fk0
() автор топика
Ответ на: комментарий от fk0

valgrind изкоробки не умеет

Не умеет что?

А как он, собственно, узнает границы массива, если на этапе компиляции на это болт забили?

Что ты понимаешь под «болт забили» в контексте выделения памяти под массив? Да ещё и этап компиляции зачем-то за уши притянул.

anonymous
()
Ответ на: комментарий от anonymous

Не умеет что?

Проверять границы массовов на стеке.

anonymous
()
Ответ на: комментарий от anonymous

Что ты понимаешь под «болт забили» в контексте выделения памяти под массив?

Абисняю.

struct s_xxx { члены...; члены...; массив[X]; члены...; члены...; };

v= malloc(struct s_xxx); .... n = v->массив[Y], где Y > X.

valgrind не поможет при попадании в другого члена, например, вместо массив[].

fk0
() автор топика
Ответ на: комментарий от anonymous

может просто не стоит писать такой говнокод?

Вот я и ищу способ оперативного выявления говнокода. Просто не писать «на авось»?

fk0
() автор топика

Ты не понимаешь, что такое Си, походу.

В Си нет никаких «массивов», есть только куски памяти и указатели на куски памяти. А еще машинные слова разных разновидностей, и структуры из машинных слов. Всё.

У чего проверять границы? Максимум у чего можно проверить в контексте Си, в рантайме - так это у страниц виртуальной памяти. И вот когда ты лезет в страницу, которая тебе не выделена, ты получаешь сегфолт. Это все, что можно в Си.

С бидона поди начинал изучение программирования?
А надо было с SICP. В 5й главе сразу бы стало понятно что такое Си.

anonymous
()
Ответ на: комментарий от anonymous

Это все, что можно в Си.

В Си можно проверять что индекс не выходит за пределы при каждом обращении к массиву. На уровне компилятора это можно даже автоматизировать.

А надо было с SICP

Если бы ты его читал, ты бы знал такое слово «абстракция» и не делал бы таких заявлений:

В Си нет никаких «массивов»

anonymous
()
Ответ на: комментарий от anonymous

Это вы не понимаете реалии практического программирования.

На уровне языка массивы есть и, см. выше по теме — есть даже патч gcc с их проверкой. У чего проверять. У индекса массива в момент обращения. У процессоров i80286 и старше специальная инструкция есть даже. Turbo-pascal помнится проверял.

Изучение программирования начинал с ассемблера по книжке где опкоды и мнемоники приведены были, а толковое описание — нет... И не зависимо от того чем является C — выбора нет. Да, фанатам LISPa я видел какую зряплату предалгают в GB (меньше чем в РФ за C/C++). В РФ никакой не предложат. За C хоть платят что-то. Ага? А то я больше TCL предпочитаю или Perl.

fk0
() автор топика
Ответ на: комментарий от fk0

попробуй mudflap+valgrind. Тока у меня пару лет назад mudflap сильно глючил, пришлось отказаться.

true_admin ★★★★★
()
Ответ на: комментарий от fk0

clang же обладает статическим анализатором. Или тут так подло получается, что из-за malloc() оно как бы слишком динамически для clang, а из-за [X] в структуре слишком статически для valgrind?

Кстати, вы проверяли про valgrind? Как-то раньше не задумывался о возможности такого поведения и повсюду, где malloc/new полагался на него.

gag ★★★★★
()
Ответ на: комментарий от fk0

-fstack-protector-all меняет поведение проги по ссылке:

#include <stdio.h>

int main()
{
    int a[1024];
    int b[1024];

    int *i;
    unsigned int count = 0;

    count = 0;
    for (i = &a[0]  ; i < &a[1024] ; i++) {
        *i = 0;
        ++count;
    }
    printf("count=%d\n", count); // 1024

    count = 0;
    for (i = &a[0]  ; i < &b[1024] ; i++) {
        *i = 0;
        ++count;
    }
    printf("count=%d\n", count);
    //    0
    // 2048 with -fstack-protector-all

    // example from http://gcc.gnu.org/wiki/Mudflap_Pointer_Debugging#Known_Shortcomings
    count = 0;
    for (i = &b[0]  ; i < &a[1024] ; i++) {
        *i = 0;
        ++count;
    }
    printf("count=%d\n", count);
    // 2048
    //    0 with -fstack-protector-all

    return 0;
}

gag ★★★★★
()
Ответ на: комментарий от anonymous

В Си нет никаких «массивов», есть только куски памяти и указатели на куски памяти.

...а у кусков памяти есть размер

tailgunner ★★★★★
()
Ответ на: комментарий от dikiy

enjoy your C.

C очень хорош для своей ниши. Ничего лучшего еще не придумали (хотя на лисп машинах будет конечно рулить сам лисп).

gensym ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.