Ошибка Solaris Bus после копирования выровненных данных в новое местоположение не происходит
Итак, короткая история: моя программа получает буфер необработанных байтов (u_char), который представляет сетевой пакет. Я пытаюсь проанализировать информацию в этом пакете, и я делаю это, используя определенные системой структуры заголовков (ether_header, ip, ip6, tcphdr, udphdr). Я реализовал это как в Linux, так и в AIX, и это сработало, но по какой-то причине я получаю ошибку шины, когда делаю это в Solaris.
То, как я получаю данные, - это просто приведение каждой части буфера к одной из структур и чтение данных. Например, если у меня есть
u_char buffer[] = {...some bytes...};
struct ether_header *ethdr = (struct ether_header *)buffer;
struct ip *iphdr = (struct ip *) (buffer + sizeof(struct ether_header));
etc. etc.
Затем я могу получить информацию, которая мне нужна:
iphdr->ip_v; //to get the version
etc->etc; //to get whatever piece of data I need
Обычно в Linux и AIX это работает нормально (некоторые структуры имеют разные имена в разных системах, но это не главное), но при попытке запустить это в Solaris я получаю сообщение об ошибке шины, когда оно доходит до iphdr->ip_v;
после struct ip *iphdr = (struct ip *) (buffer + sizeof(struct ether_header));
, После некоторого расследования я обнаружил, что это вызвано попыткой доступа к невыровненной памяти. Это имеет смысл, поскольку размер заголовка Ethernet составляет всего 14 байтов, поэтому заголовок IP не выровнен в байтах в массиве.
Я попытался обойти это, скопировав соответствующие фрагменты в отдельный буфер, прежде чем пытаться его прочитать.
memcpy(&buffer_copy, buffer + sizeof(struct ether_header), sizeof(struct ip));
struct ip *iphdr = &buffer_copy;
iphdr->ip_v;
etc.
Это работает, но я не понимаю почему. Почему memcpy не выдает ошибку шины, когда пытается получить доступ к той же области памяти? Мне не нравится решение, которое я придумала, и пытаюсь лучше понять ситуацию, чтобы придумать что-то еще. Может быть, мне не хватает части головоломки?
1 ответ
На оборудовании SPARC у вас есть два варианта:
- Не пишите код, который обращается к памяти способом, который вызывает ошибку шины.
- Скомпилируйте с помощью компиляторов Solaris Studio и используйте
-xmemalign=1i
опция командной строки. Это приведет к тому, что двоичный файл будет работать медленнее двоичного, который предполагает правильно выровненный доступ к памяти.
Также посмотрите этот вопрос.