Кажется, я достиг предела своего Пойнтер-Фу и обращаюсь за помощью (или к какому-то лекарству для мозга).
Приблизительный план проекта: встроенная плата видеокодировщика ARM под управлением Linux с использованием поставляемого производителем плохо документированного и плохо поддерживаемого SDK. Среди его обширного разбросанного кода есть огромная куча, созданная gSoap из какого-то WSDL, и именно это вызывает головную боль.
В части огромной структуры данных, автоматически сгенерированной gSoap, у нас есть место для записи некоторых данных (или место для записи указателя на место, где мы записали некоторые данные):
struct tt__IPAddress
{
enum tt__IPType Type; /* required element of type tt:IPType */
char *IPv4Address; /* optional element of type tt:IPv4Address */
char *IPv6Address; /* optional element of type tt:IPv6Address */
};
Затем у нас есть этот код, который, короче говоря, должен записывать строку в IPv4Address:
DNSInformation->DNSManual = ((struct tt__IPAddress *)soap_malloc(soap, sizeof(struct tt__IPAddress)));
DNSInformation->DNSManual->IPv4Address = (char **)soap_malloc(soap, sizeof(char *));
DNSInformation->DNSManual->IPv4Address[0] = (char *)soap_malloc(soap, sizeof(char) * LARGE_INFO_LENGTH);
// Code crashes at this next line:
strncpy(*DNSInformation->DNSManual->IPv4Address, dns_string, LARGE_INFO_LENGTH-1);
Строка dns — это то, что вы ожидаете — что-то вроде «192.168.2.254». Он правильно завершается нулем, значение LARGE_INFO_LENGTH является чем-то большим (например, 1024), поэтому для строки достаточно места. Я перешел с strcpy() на strncpy() для безопасности.
В моем опыте встроенные программы меньшего размера (без ОС, без использования malloc()), поэтому мне трудно убедить себя, что я понимаю, что делает этот код. Код генерируется автоматически / является частью SDK, поэтому это не мое творение, и он не документирован / не прокомментирован.
Вот что я думаю, что это делает:
DNSInformation->DNSManual = ((struct tt__IPAddress *)soap_malloc(soap, sizeof(struct tt__IPAddress)));
Выделяет кусок ОЗУ, на который указывает DNSManual, где будет жить структура tt__IPAddress.
DNSInformation->DNSManual->IPv4Address = (char **)soap_malloc(soap, sizeof(char *));
Выделяет кусок оперативной памяти, на который указывает IPv4Address, куда будет записан указатель на строку, содержащую адрес.
DNSInformation->DNSManual->IPv4Address[0] = (char *)soap_malloc(soap, sizeof(char) * LARGE_INFO_LENGTH);
Теперь это меня немного смущает, похоже, что он пытается выделить ОЗУ для хранения строки, на которую будет указывать IPv4Address[0], за исключением того, что мне кажется, что они пытаются написать (32-битный) указатель на обуглку, возможно.
Этот код работал раньше, однако после некоторых изменений в других местах он теперь дает сбои, всегда во время или во время выполнения strncpy().
У меня два вопроса:
- Может ли кто-нибудь помочь мне правильно понять, что происходит с mallocs/pointer-fu?
- Любое руководство о том, как это отследить/отладить?
К сожалению, у нас нет средства GDB с этой настройкой - да, я уверен, что это возможно настроить, но пока давайте просто предположим, что это нецелесообразно по многим хромым и утомительным причинам.
В настоящее время у меня есть отладочные printf, разбросанные по коду, фактически в каждой строке этого маленького фрагмента, и он всегда останавливается с SIGSEGV в строке strncpy().
Изменить, чтобы закрыть, поскольку WhozCraig нажал ответ:
По причинам, наиболее известным самому себе, gSoap изменил структуру tt__IPAddress, возможно, в ней закончились звездочки, но то, что было в предыдущих версиях и каким оно должно было быть, это:
struct tt__IPAddress
{
enum tt__IPType Type;
char **IPv4Address; /* note ptr to ptr */
char **IPv6Address;
};
malloc()
. - person   schedule 27.08.2013char**
, либо более поздний код не должен выполнять выделениеsizeof(char)
и должен рассматривать поле как указатель на строку, а не указатель на таблицу указателей. - person Nicholas Wilson   schedule 27.08.2013DNSInformation
иDNSManual
конструкции? - person Uchia Itachi   schedule 27.08.2013