Another bug report

When I was switching my toy project sgio.d to dmd 2.067.1, I came across another compiler error. Cool! I submitted an issue on the bug tracker, and it looks like this particular change was intentional. Regardless if it's a bug or not, I'll describe the syntax that caused the break.

My sgio.d project can send scsi ioctls to native devices on Windows and Linux hosts. Some scsi devices have a "management network address", like iSCSI, and we can get the IP address of the LUNs by sending the device a Management Network Address (MNA) Vital Product Data (VPD) page (0x85). If you're interested look at the SCSI Primary Commands 4 (SPC-4) document, it details the definitions of basic SCSI commands. Or glance at the summary of VPD on Wikipedia. sgio.d will send an ioctl and then unmarshall the response buffer into a usable object.

The contents of a MNA VPD response page is some header information and a list of Network Service Descriptors. The unmarshalling of the MNA VPD is easy but I found that some devices may return a truncated Command Data Block (CDB), so I have a check to ensure that we don't walk off the end of the buffer. We do that by checking that the descriptors offset plus the descriptor's length (plus a 2-byte header) is still within the original buffer.

We know that the MNA VPD response has a list of descriptors and the offset in the buffer for a descriptor will change each iteration. Taking that in mind, the unmarshall with truncated buffer check looks like this (the source):

override protected void unmarshall() {  
   m_network_descriptors_length = bigEndianToNative!ushort(datain[2..4]);
   m_network_descriptors = make!(Array!NetworkServicesDescriptor)();

   size_t offset = 4;
   while (offset < m_network_descriptors_length) {
      if (offset + 4 + bigEndianToNative!ushort(
                cast(ubyte[2]) datain[offset+2..offset+4])
             > datain.length) {
         // truncated buffer
      auto ns_descriptor = new NetworkServicesDescriptor(datain[offset..$]);
      m_network_descriptors ~= ns_descriptor;

      offset += ns_descriptor.network_address_length + 4;

The code is nice and clean but the compiler doesn't like it because the std.bitmap bigEndianToNative function doesn't accept a buffer slice composed of variables. What I mean is the slice allows only literals, like buffer[2..4] and not buffer[offset+2..offset+4].

The workaround is to just manually convert the bytes which is done with (datain[offset+2]<<8 | datain[offset+2+1]) instead of bigEndianToNative!ushort(cast(ubyte[2]) datain[offset+2..offset+4]). It's very convenient that D has a stdlib method that does byte conversions, even if it is just slices with literals. D is a great project!

Powered by Digital Ocean

Click the image for a $10 referral