LINUX.ORG.RU

[C] Возвращаемый адрес структуры изменяется

 


0

1

Есть такой быдлокод

commandlet* cmdlet_search(char* command)
{
  DEBUG("cmdlet_search(): finding \"%s\"\n", command);
  int i;
  for(i = 0; cmdlist[i] != 0; i++)
    {
      if(!strcmp(command, cmdlist[i]->cmd))
	{
	  DEBUG("cmdlet_search(): found! (-> %s at %p on %p)\n", cmdlist[i]->cmd, &cmdlist[i]->cmd, cmdlist[i]);
	  return cmdlist[i];
	}
    }
  DEBUG("cmdlet_search(): not found!\n");
  return 0;
}

int cmd_shell(char *cmdshell) //NOTE: 1 - commandlet not found
{
  //void* (*callback)();
  int flag;
  commandlet* cmdl = 0;
  flag = extractcmd(cmdshell);
  cmdl = cmdlet_search(cmdshell);
  if(cmdl == 0)
    return 1;
  DEBUG("cmdl is %p now\n", cmdl);
  DEBUG("Running command from %s\n", cmdl->cmd);
  if(!flag)
    cmdl->callback();
  else
    cmdl->callback(&cmdshell[strlen(cmdshell)+1]);
  debug_cmds_bt();
  return 0;
}

После ввода команды в программе должен вызываться cmd_shell(«имя_команды»), который должен вызвать cmdlet_search, который ищет структуру, где есть введённая команда и указатель на функцию для вызова. Предположим, нужно найти команду принт

Shell> print hello
cmdlet_search(): finding "print"
cmdlet_search(): found! (-> print at 0x804c1a100 on 0x804c1a100)
cmdl is 0x4c1a100 now
zsh: segmentation fault (core dumped)

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



Последнее исправление: wasd (всего исправлений: 1)

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

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file
int cmd_shell(char *cmdshell) //NOTE: 1 - commandlet not found
{
  //void* (*callback)();
  int flag;
  commandlet* cmdl = (commandlet*)0;
  flag = extractcmd(cmdshell);
  cmdl = cmdlet_search(cmdshell);
  if((commandlet*)cmdl == (commandlet*)0)
    return 1;
  DEBUG("cmdl is %p now\n", (commandlet*)cmdl);
  DEBUG("Running command from %s\n", cmdl->cmd);
  if(!flag)
    cmdl->callback();
  else
    cmdl->callback(&cmdshell[strlen(cmdshell)+1]);
  debug_cmds_bt();
  return 0;
}

Сделал так - без изменений.

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

Подозреваю, часть указателей смотрит у тебя в невалидную область стека. Иначе объяснить такие глюки трудно.

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

что именно мне смотреть? адрес? он выводится тот же самый, что и в выводе дебага.

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

Хм, память под место, куда показывает указатель, выделялось с помощью calloc в функции, вызываемой из либы, которую я подгрузил с помощью dlopen. Что мне проверить, чтобы убедиться что оно смотрит не туда, и как это фиксить? Алсо, почему часть адреса просто отрезается?

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

Алсо, почему часть адреса просто отрезается?

Часть стека, которая используется для хранения указателя, изменяется какими-то еще данными. Но вот какими? Не достаточно данных для анализа.

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

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

Хм, покурю чуть позже. Спасибо за вариант.

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

Странные у вас глюки однако. Посмотри этот файл в ассемблерном виде, что-ли, где там компилятор обрезалку втыкает.

no-such-file ★★★★★
()

Пособирал код на других компах — на некоторых работает нормально. Архитектуры и оси - фря и линукс, amd64/i686

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

а покаже-ка код DEBUG, если приложение однопоточное, там по первому взгляду больше некому гадить в память.

MKuznetsov ★★★★★
()

Ищи ошибку, видать твой cmdlist указывает куда-то за пределы твоей таблицы. То что оно иногда срабатывает где-то - просто визение. Не нужны тут никакие валгринды, нужно просто вдумчиво посидеть в gdb.

grouzen ★★
()

попробуйте поиграть с модификаторами. У меня были подобные глюки для переменных.

XVilka ★★★★★
()

| 0x804c1a100
| 0x4c1a100

Где-то адрес обрезается до 4х байт. Код ведь компилируется под amd64, так?

Пальцем в небо: указатель где-то может передаваться в функцию, которая не объявленна - и молча обрезаться до int.
Например: для cmdlet_search DEBUG() или printf() объявленна, а для cmd_shell() - нет.

user_2190
()
commandlet* cmdlet_search(char* command)
{
  //...
  return &cmdlist[i];
  //...
}

Оно?

capricorn20
()

DEBUG(«cmdlet_search(): found! (-> %s at %p on %p)\n», cmdlist->cmd, &cmdlist->cmd, cmdlist);

изменить на

DEBUG(«cmdlet_search(): found! (-> %s at %p on %p)\n», cmdlist->cmd, (void *)&cmdlist->cmd, (void *)cmdlist);

и везде, где %p передавать исключительно (void *).

man printf

p The void * pointer argument is printed in hexadecimal (as if by %#x or %#lx).

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

Где-то адрес обрезается до 4х байт. Код ведь компилируется под amd64, так?

Ага, под amd64

Пальцем в небо: указатель где-то может передаваться в функцию, которая не объявленна - и молча обрезаться до int.

Например: для cmdlet_search DEBUG() или printf() объявленна, а для cmd_shell() - нет.

Мой друг прошелся по коду когда было нечего делать, везде поприводил к commandlet*, пофиксил разные предупреждения компилятора, связанные с указателями и стало работать как надо. Код конкретно этих функций не менялся.

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