views:

687

answers:

3

Hello, I'm developing an application that needs to interact over FTP. For this communication I am currently using C++, Visual Studio and Poco on Windows.

The following line results in a bad_alloc exception...

ftp = new FTPClientSession("127.0.0.1", 21);

So I went down and tried initializing a StreamSocket first, also fails...

StreamSocket ss = new SocketAddress("127.0.0.1", 21);

When going even further down, and it seems the bad_alloc is coming from:

IPAddress * ip = new IPAddress("127.0.0.1");

That constructor contains: (I see in the debugger that _pImpl isn't initialised)

IPAddress::IPAddress(const std::string& addr)
{
_pImpl = IPv4AddressImpl::parse(addr);

if (!_pImpl) throw InvalidAddressException(addr);
}

IPv4AddressImpl::parse contains:

static IPv4AddressImpl* parse(const std::string& addr)
{
if (addr.empty()) return 0;  
#if defined(_WIN32) 
 struct in_addr ia;
 ia.s_addr = inet_addr(addr.c_str());
 if (ia.s_addr == INADDR_NONE && addr != "255.255.255.255")
  return 0;
 else
  return new IPv4AddressImpl(&ia);
#else
#if __GNUC__ < 3
 struct in_addr ia;
 ia.s_addr = inet_addr(addr.c_str());
 if (ia.s_addr == INADDR_NONE && addr != "255.255.255.255")
  return 0;
 else
  return new IPv4AddressImpl(&ia);
#else
 struct in_addr ia;
 if (inet_aton(addr.c_str(), &ia))
  return new IPv4AddressImpl(&ia);
 else
  return 0;
#endif
#endif
}

The following code with inet_addr from Winsock2.h (ws2_32.lib) results in "SOMETHING ELSE".

unsigned long ulAddr = INADDR_NONE;
ulAddr = inet_addr("91.183.48.210");
if (ulAddr == INADDR_NONE)
    msg("NONE");
else
    msg("SOMETHING ELSE");

I don't see what is going wrong here... Is there a way to debug this further or does someone know what goes wrong?

A: 

It looks like the only possible cause is the call to

inet_addr

on the line

ia.s_addr = inet_addr(addr.c_str());

returns INADDR_NONE which causes 0/NULL to be returned, causing the exception to be thrown.

Can you call inet_addr("127.0.0.1") and see what the results are? If the results are INADDR_NONE, then you'll need to find a good address to inet_addr that makes your system happy.

Here is a link to inet_addr in the MSDN documentation.

Observation You are calling the constructor

 IPAddress("127.0.0.1");

with a const char*, but the constructor takes a const references

 IPAddress::IPAddress(const std::string& str);

is the compiler smart enough to create that temporary? I tried it out with VS 2003, and it seems to be ok. I suspect that the language should be smart enough to handle this, but I thought I'd point it out.

Doug T.
That was my first thought but inet_addr is a very simple function and should have no trouble with "127.0.0.1".
paxdiablo
WinSock2.h, ws2_32.lib, inet_addr indeed results in a good address.
TomWij
Regarding the conversion to a reference, yes the compiler is smart enough - this is a very common idiom in C++.
anon
+1  A: 

I'm no rocket scientist but it looks like you'll have to step into IPv4AddressImpl() with ia.s_addr populated with a pointer to the string "127.0.0.1".

Just out of interest, do you get the error when you use your real IP address instead of the loopback.

And, do you have an FTP server running on that machine?

And, are you absolutely certain the string is "127.0.0.1"?

Update:

There's only really three things that can cause the exception.

  • addr.empty() is true, unlikely if addr is "127.0.0.1".
  • is.s_addr is INADDR_NONE, again unlikely since inet_addr() should have no trouble with 127.0.0.1 (as you've tested).
  • the constructor for IPv4AddressImpl() returns NULL (or throws the bad_alloc exception itself).

That last one seems the most likely, what happens when you write your own code to do it?

struct in_addr ia;
ia.s_addr = inet_addr("127.0.0.1");
IPv4Address *x = new IPv4AddressImpl(&ia);

In addition, if you breakpoint on the "if (!_pImpl) throw..." line and examine _pImpl:

  • zero means the ::parse returned NULL and it's the IPAddress() constructor throwing bad_alloc.
  • non-zero means ::parse itself threw an exception which could only be from the IPv4AddressImpl() constructor.

You may have to step into that to debug further.

paxdiablo
Because these are compiled libraries I can't step into the code. Whatever IP I try (over the internet, a domain name or local), they all result in the same. And yes, there is a FTP server running on both my PC and the server over the internet. This actually doesnt' mather for IPAddress.
TomWij
No, the FTP server was a long shot. But if you can view the source, why can you not recompile in debug mode to step into it?
paxdiablo
Hmm, when using the debug mode libraries and dlls it is suddenly working, check my answer to the post.
TomWij
A: 

Okay, I linked PocoFoundationd.lib and PocoNetd.lib; also provided PocoFoundationd.dll and PocoNetd.dll to the executable. Suddenly the exception doesn't appear anymore...

Can anyone explain me why this is so that I can learn from it?

TomWij
Did you have all those libs and dlls linked in before (the non-debug versions of course)? If so, it may be that there's something in the debug versions that's required when you're building a debug build. No idea really, it depends on the bods that wrote Poco.
paxdiablo
Well, I think that for a Debug project you need everything configured as Debug and for a Release project you need everything configured as Release. The problem here was a mix of both. (Multi-threaded DLL Debug with Release Libs and Release DLLs)
TomWij
Anyway, great to have STL, Wx, Boost and Poco available to me at all time. Might want to look into Qt, Soci and Loki too, but well, that's when I need them or read up about them somewhere. Handy to have a large set of useful classes within reach. This was actually the reason why I switched to C#... (Well, sometimes I must code in C++)
TomWij