Как предотвратить переполнение буфера/переполнение массива?

Недавно я писал код для пользовательского протокола последовательной связи. Что я сделал, так это то, что я использовал часть (8/16 бит) полученных данных, чтобы указать, насколько велик размер кадра. Основываясь на этих данных, я ожидаю, что что никаких данных не последует. Я использую Crc, чтобы принять или отклонить кадр. Но я не смогу включить данные длины кадра в Crc, так как на принимающей стороне я должен знать, сколько данных ожидать, до обработки кадра.

Проблема, с которой я столкнулся, заключается в том, что иногда эти данные о длине кадра повреждаются, и это обманывает получателя, заставляя его получать такое количество байтов, тогда как размер принимающего массива намного меньше этого. Это повреждает множество критических системных переменных, присутствующих в последовательных ячейках памяти.

Как предотвратить переполнение буфера? Мои мысли по этому поводу 1) Отклонить данные framelength, если они выходят за пределы определенного значения. 2) используйте тип данных, который ограничивает максимальное количество. Подобно использованию короткого замыкания, которое ограничивает область индекса массива 256 ячейками памяти и создает буфер размером 280 байт. 3) выделить память в отдельном месте, чтобы она не влияла на критические системные переменные.

Одна вещь, которую я использовал для предотвращения застревания в цикле приема, — это использование тайм-аута. Но я упустил из виду эту сторону вопроса. Мне кажется, что у меня много времени, чтобы подтвердить и воспроизвести проблему, поскольку, таким образом, код является частью более крупного системного кода, а я здесь не эксперт.

Как вообще безопасно справляться с такими проблемами?

Также: какие общие соображения или стандартные методы следует соблюдать при использовании массива, чтобы предотвратить его переполнение?


person seetharaman    schedule 09.04.2016    source источник
comment
Простите меня, если я неправильно использовал некоторые термины.   -  person seetharaman    schedule 09.04.2016
comment
Я бы сказал 2) правильный ответ. (Хотя short составляет 2 байта, а вам нужно однобайтовое значение.)   -  person user3386109    schedule 09.04.2016
comment
Я не понимаю, как повреждение данных о длине кадра может обмануть приемник и привести к переполнению буфера. Конечно, приемник считывает именно то количество байтов, которое ему было сказано ожидать (или пытается это сделать), и в его силах убедиться, что у него есть достаточный буфер для этого, даже если размер полученного кадра неверен.   -  person John Bollinger    schedule 09.04.2016
comment
Отправьте длину буфера дважды (возможно, инвертировав второй раз). Если совпадает, то все в порядке.   -  person Weather Vane    schedule 09.04.2016
comment
Вы можете улучшить обнаружение ошибок, выбрав последовательный протокол, который включает биты четности.   -  person John Bollinger    schedule 09.04.2016
comment
@JohnBollinger Я получаю данные о длине кадра и продолжаю получать данные, пока не будут получены байты данных, равные данным о длине кадра.   -  person seetharaman    schedule 09.04.2016
comment
@user3386109 user3386109 да, но у меня вопрос, это лучший способ сделать это?   -  person seetharaman    schedule 09.04.2016
comment
@WeatherVane да, я мог бы попробовать это .. FEC (упреждающее исправление ошибок)   -  person seetharaman    schedule 09.04.2016
comment
Парность @JohnBollinger может обнаруживать только однобитовые ошибки. Вероятно, то, что сказал WeatherVane, может сработать.   -  person seetharaman    schedule 09.04.2016
comment
Это простое решение. Другим решением является отправка заголовка фиксированного размера, который сам имеет CRC или своего рода прямое исправление ошибок.   -  person user3386109    schedule 09.04.2016
comment
Я говорю, что даже если клиент получает поврежденную длину кадра, нет никаких причин, по которым это должно обмануть клиента и привести к переполнению буфера. Клиент знает, насколько велик его буфер, и он имеет полный контроль над тем, сколько байтов он где хранит.   -  person John Bollinger    schedule 09.04.2016
comment
@JohnBollinger да, совершенно верно, я просто проглядел это в первый раз. Теперь думаю, как сделать лучше, но при этом сохранить код в безопасности.   -  person seetharaman    schedule 09.04.2016
comment
Если это проблема, и вы часто сталкиваетесь с повреждением данных, также выполните проверку четности. Пояс и подтяжки.   -  person Weather Vane    schedule 09.04.2016
comment
В любом случае не существует стопроцентно надежного механизма обнаружения ошибок. Все это вопрос больших накладных расходов - как с точки зрения данных, так и с точки зрения вычислений - вы хотите инвестировать в обнаружение ошибок, и насколько маловероятно вы хотите, чтобы данные были повреждены таким образом, что их нельзя обнаружить.   -  person John Bollinger    schedule 09.04.2016
comment
Если длина повреждена, вы понятия не имеете, что еще могло быть повреждено, поэтому вам, вероятно, следует отбросить весь кадр, если его длина превышает ожидаемую. Если когда-либо была повреждена только длина, вам, возможно, следует сначала решить эту проблему, потому что это звучит как ошибка программного обеспечения, а не окружающей среды. Механизмы обнаружения ошибок должны быть предназначены для исключительных случаев (внешние помехи), а не для устранения плохо спроектированного или реализованного соединения, которое по своей сути ненадежно - для этого вам нужна более сложная система обнаружения/исправления ошибок.   -  person Clifford    schedule 10.04.2016


Ответы (2)


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

Вы должны выяснить, что именно лучше всего подходит для вашей системы. Например, если вы никогда не ожидаете, что сообщение будет больше 256, то, объявив размер вашего буфера как 0xFF, а индекс вашего буфера как uint8_t, вы никогда не сможете превысить его, вставляя по одному байту за раз, поскольку индекс будет никогда не достигает 256 и переполняется обратно в 0. Недостатком этого, конечно, является то, что если это происходит, вы перезаписываете некоторые из полученных данных, но проверка crc должна выявить ошибку в большинстве случаев.

Еще одна вещь, которую вы можете сделать, это сравнить длину данных с максимальным буфером и не сохранять сообщение, если оно превышает ваш буфер. Таким образом, вы полностью отклоняете любые сообщения, длина данных которых слишком велика и полученные, но не сохраняете поступающие данные. Очевидно, что если длина данных часто повреждается, у вас будет много проблем с этим.

Честно говоря, лучший способ — переосмыслить собственный протокол последовательной связи. Не похоже, что он очень хорошо справляется с ошибками, с которыми вы сталкиваетесь. Вы можете иметь синхронизированные байты в начале и конце вашего сообщения, чтобы просто убедиться, что вы действительно получаете хорошие данные, и CRC всего сообщения без проблем, и определить максимальные размеры пакетов данных, которые будут передаваться по сети, и сигнализировать, сколько пакетов должно быть отправлено. быть полученным. Если протокол связи не очень хорош, вам придется переосмыслить его снизу вверх.

person Dom    schedule 09.04.2016
comment
Я попробую использовать unit8. Я уже использую байты синхронизации в начале кадра. Только после того, как я обнаружу байты синхронизации, я получу данные о размере кадра. Похоже, что повреждение данных происходит в случайных байтах в кадре, а с другими байтами все в порядке. - person seetharaman; 13.04.2016

во-первых, проверьте наличие ошибок кадрирования, проверьте наличие ошибок четности

во-вторых, проверьте величину размера данных. если слишком большой или слишком маленький, отклонить весь блок данных

person user3629249    schedule 10.04.2016
comment
Я использую заголовок для определения начала кадра и позиционирования битов. Что касается пары, я не использую UART, поэтому расчет в SW будет накладным. Проверка размера кадра и отклонение могут сработать. - person seetharaman; 13.04.2016