I seem to have hit the limits of my Pointer-Fu and am appealing for help (or some sort of brain medicine).
A rough outline of the project: An embedded ARM video-encoder board running Linux, using a manufacturer-supplied ill-documented poorly-supported SDK. Among its vast sprawl of code is a huge pile that is generated by gSoap from some WSDL, and it's this that is causing the headache.
In part of a huge data structure auto-generated by gSoap, we have a place to write some data (or, a place to write a pointer to the place we've written some data):
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 */
};
Then we have this code which, in short, should be writing a string to the 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);
The dns_string is what you'd expect - something like "192.168.2.254". It's correctly null-terminated, the value of LARGE_INFO_LENGTH is something big (like 1024) so plenty of room for the string. I changed from strcpy() to strncpy() for safety.
My background is smaller embedded stuff (no OS, no use of malloc()) so I'm having a bit of trouble convincing myself I understand what this code is doing. The code is auto-generated / part of the SDK so it's not my creation and it's not documented / commented.
Here's what I think it's doing:
DNSInformation->DNSManual = ((struct tt__IPAddress *)soap_malloc(soap, sizeof(struct tt__IPAddress)));
Is allocating a lump of RAM, pointed to by DNSManual, where a tt__IPAddress struct will live.
DNSInformation->DNSManual->IPv4Address = (char **)soap_malloc(soap, sizeof(char *));
Is allocating a lump of RAM, pointed to by IPv4Address, where a pointer to a string containing the address will be wrote.
DNSInformation->DNSManual->IPv4Address[0] = (char *)soap_malloc(soap, sizeof(char) * LARGE_INFO_LENGTH);
Now this one throws me a bit, it looks like it's trying to allocate RAM to hold the string which will be pointed to by IPv4Address[0], except that looks to me like they're trying to write a (32-bit) pointer to a char, possibly.
This code has worked previously, however after some changes elsewhere it now segfaults, always at or during the strncpy().
My questions are twofold:
- Can someone help me properly understand what is going on with the mallocs / pointer-fu?
- Any guidance on how to go about tracing / debugging this?
We do not have GDB facility with this setup unfortunately - yes I'm sure it's possible to set it up, but for now let's just assume that's not practical for many lame and tedious reasons.
Currently I have debugging printf's scattered liberally through the code, in fact on every line in this little snippet, and it always stops with a SIGSEGV at the strncpy() line.
Edit to close as WhozCraig has hit the answer:
For reasons best known to itself, gSoap had changed the struct tt__IPAddress, perhaps it had run out of asterisks, but what it had been in previous versions, and what it should be, is this:
struct tt__IPAddress
{
enum tt__IPType Type;
char **IPv4Address; /* note ptr to ptr */
char **IPv6Address;
};