Борьба с утечками ресурсов и переполняющимися буферами

результат работы программы, определяющий размер блока по указателю


Мы видим, что _msize

ведет себя очень странно и когда не может определить размер блока, возвращает какой-то мусор, никак не сигнализируя об ошибке. Поэтому, выполнять контроль должна вызывающая функция, передавая вызываемой размер буфера как аргумент. Отсюда и появились: char *fgets(char *string, int n, FILE *stream);
char *strncpy(char *strDest, const char *strSource, size_t count) и другие подобные функции. Теоретически, они на 100% застрахованы от переполнения, но вот практически… значение n

приходится рассчитывать вручную, а, значит, существует риск ошибиться! К тому же, если длина строки превышает n, в буфер копируется лишь "огрызок", что само по себе является нехилым источников проблем и вторичных ошибок. Приходится навешивать специальный обработчик, выделяющий дополнительную память и считывающий оставшийся "хвост", что значительно усложняет реализацию, делает код более громоздким и менее наглядным. Обычно стараются выбрать n так, чтобы его значение превышало размер _наибольшей_ строки, выделяя память с запасом и не обращая внимания на то, что большинство строк использует лишь малую часть буфера…

Нет! Память лучше всего выделять динамически, по мере возникновения в ней потребности! В идеале, строка должна представляет собой _список_ (желательно двухсвязный), что не только ускорит операции удаления и вставки подстрок, но и ликвидирует проблему переполнения. О контроле границ заботиться уже необязательно, поскольку память под новые символы выделяется автоматически.

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

struct slist

{

       unsigned char c;

       struct slist *prev;

       struct slist *next;

       struct slist *first;

       struct slist *last;

};



Содержание раздела