3

I was tinkering with IP packet 'parsers' when I noticed something odd.

When it came to parsing the IP addresses, in C#

private uint srcAddress; 
// stuff
srcAddress = (uint)(binaryReader.ReadInt32());

does the trick, so you'd think this VB.Net equivallent

Private srcAddress As UInteger
'' stuff
srcAddress = CUInt(binaryReader.ReadInt32())

would do the trick too. It doesn't. This :

srcAddress = reader.ReadUInt32()

however will.

Took some time to discover, but what have I dicovered -- if anything ? Why is this ?

user247702
  • 23,641
  • 15
  • 110
  • 157
esjr
  • 186
  • 3
  • 9
  • 3
    Why are you using `ReadInt32()` in the first place when you're expecting a `uint`? – user247702 Jun 07 '14 at 15:33
  • Are you giving the same input to your C# code as your VB code? It's possible you might be getting lucky with C# value having it's MSB set to zero hence there being no difference between signed and unsigned ints. Can you post the two outputs, correct and incorrect (from VB)? If possible in hex. – bytefire Jun 07 '14 at 15:34
  • In VB, you either get an arithmetic overflow or an IP address that's 'just' wrong. As, to why : most C# examples I found do it that way and at 1st I 'blindly' translated, you are right, and I did change that, but still why the difference ? – esjr Jun 07 '14 at 15:36
  • `srcAddress = DirectCast(binaryReader.ReadInt32,UInt32)` – Ulugbek Umirov Jun 07 '14 at 15:41
  • I tried DirectCast and CType(..,UInt32), same results : overflow, weird IP or invalid. – esjr Jun 07 '14 at 15:43
  • @esjr Sample input and generated output/exception? – Ulugbek Umirov Jun 07 '14 at 15:45
  • The exceptions : arithmetic overflow when the read occurs, invalid newAddress when turning srcAddress [as signed Integer] into New IPAddress or 157.55.236.139 [MSN] coming out as 99.200.19.116. Depending on the method of casting, the thing is using ReadUInt32 in VB.Net does the trick, what's with ReadInt32 in .Net ? – esjr Jun 07 '14 at 15:54
  • The thing is in C# ReadInt32 and the casting works. In VB ReadInt32, using various casting methods, ends in tears. ReadUInt32 does work. – esjr Jun 07 '14 at 16:04
  • FYI : the 'final' line in VB.Net : srcAddress = New IPAddress(BitConverter.ToUInt32(ipv4Packet, 12)) – esjr Jun 07 '14 at 16:41

1 Answers1

5

VB.NET, by default, does something that C# doesn't do by default. It always check for numerical overflow. And that will trigger in your code, IP addresses whose last bit is 1 instead of 0 will produce a negative number and that cannot be converted to UInteger. A data type that can only store positive 32-bit numbers.

C# has this option too, you'd have to explicitly use the checked keyword in your code. Or use the same option that VB.NET projects have turned on by default: Project + Properties, Build tab, Advanced, tick the "Check for arithmetic overflow/underflow" checkbox. The same option in VB.NET project is named "Remove integer overflow checks", off by default.

Do note how these defaults affected the syntax of the languages as well. In C# you have to write a cast to convert a value to an incompatible value type. Not necessary in VB.NET, the runtime check keeps you out of trouble. It is very bad kind of trouble to have, overflow can produce drastically bad results. Not in your case, that happens, an IP address really is an unsigned number.

Do keep the other quirk about IP-addresses in mind, sockets were first invented on Unix machines that were powered by LSD and big-endian processors. You must generally use IPAddress.NetworkToHostOrder() to get the address in the proper order. Which only has overloads that take a signed integer type as the argument. So using ReadInt32() is actually correct, assuming it is an IPv4 address, you pass that directly to NetworkToHostOrder(). No fear of overflow.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536