Указатель частично подделан, зачем это и как отлаживать? - PullRequest
0 голосов
/ 28 ноября 2018

Мне поручили разработать сервер чата, который написан на C, потому что разработчик ушел, и я немного знаю C.

Я столкнулся с ошибкой в ​​эти недели и боролся с ней почти 2недель.Я даже не могу сейчас спать, пожалуйста, не удаляйте и, пожалуйста, помогите.

Сервер чата использует цикл обработки событий, каждый раз, когда приходит запрос, он создает структуру command вместе с некоторыми другими структурами.

Структура command имеет вид

struct {
  struct {
    char *message;
    int length;
  } response;
  long count;
  int status;
} command;

Иногда указатель message частично подделан, обычному указателю нравится 0x00003fffxxxxxxxx, например, двоичный файл:

0000 0000 0000 0000 0110 1111 1111 1111 BBBBBBBBBBBBBBBB  (pointerA)

и поврежденный указатель всегда

0000 0000 0000 0000 0000 0000 0000 0001 BBBBBBBBBBBBBBBB  (pointerB)

младшие 33 бита указателя всегда одинаковы, а старшие 31 бит всегда установлены на 0.

Так что если messageАргумент указатель указывает на указатель B, и если я изменяю старшие 31 бит на 0110 1111 1111 1111, поэтому я получаю указатель B, если я печатаю содержимое pointerB в gdb, содержимое будет правильным.

Это происходит только при некоторой нагрузке и происходит случайно.Как я могу отладить это?

1 Ответ

0 голосов
/ 28 ноября 2018

Поскольку вы работаете в Linux и, по-видимому, x86_64, вашим первым шагом должно быть восстановление вашего двоичного файла с помощью Address Sanitizer (gcc -fsanitize=address ...).

В отличие (ужерекомендуется) Valgrind, Address Sanitizer перехватывает переполнения в глобальных и стековых переменных (в дополнение к куче).Это также значительно быстрее.

Это происходит только при некоторой нагрузке и происходит случайным образом.

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

Если вы не можете найти ошибку с sanitizer, другой подходэто найти все места, где struct command находится free d, и заменить их на:

memset(p, 0xCD, sizeof(*p));
free(p);

Это должно значительно упростить воспроизведение ошибки и сузить ее (если мое предположение о его природеправильно).

...