Ten years ago, James was working for a small company that made electronic components. That company got eaten by Initech, who wanted to connect all those smart electronic devices to their own products. This meant that the two companies had to agree on what that communication protocol would look like. More than that, this was on the critical path to completing the merger- Initech wouldn't go through with the purchase if they couldn't integrate with the systems they were purchasing.
Negotiations were difficult. A lot of the challenge came from Initech's side, because they wanted to make the protocol a "do everything" system for managing data, which just wasn't something the embedded components were designed for. Over the course of many months, a design document gradually took shape.
Since the messages passing through the protocol might be arbitrary lengths, one of the key decision points was "how do we determine the length of the message?" James's team advocated for a byte length in the header, but Initech protested: "We might not know the length of the message until after we've sent it."
They couldn't explain how that could be- the protocol didn't support streaming- but Initech wasn't having any of it. The obvious other solution was to just simply ensure that the message ended with a null byte- a \0
.
Everyone went off to work on their implementations, and for a few months, everything seemed like it was going smooth. James and his team whipped up some testing tools, implemented the protocol, sent test messages, and everything worked great. Then it came time to integrate with Initech's implementation.
And everything broke.
Specifically, it looked like Initech had failed to actually terminate their messages.
"See, there's no termination character," James said, highlighting the hex dump which ended with 0x30
. Every message ended with 0x30
.
"I don't know what you're showing me," the Initech developer said, "because here's how I send the message." The dev highlighted the relevant section of code.
buffer[idx] = '0';
return buffer;
"See? The last index is always set to a zero."
"That's… the character zero."
"It's a zero."
Cue the round of blamestorming. Initech's side pointed to the specification which said the last byte had to be a zero, and that they had successfully made the last byte a zero. Therefore James's team was wrong. James countered that bytes were traditionally numeric values, and they were using a character value, to which Initech countered: the specification doesn't say that explicitly.
As this was happening during a protracted purchasing process, which meant a third party arbitrator got involved. Arbitration found that zero was a zero, and it was James's team who would have to change their code: they had to accept (and send) messages that all terminated with 0x30
.
There was just one problem with that: the message body might legitimately contain a 0x30
. This meant that they wouldn't know for sure if they'd parsed the whole message. Someone on James's team threw together a hack that kept reading for 0x30
s until they hit an arbitrary size threshold that was roughly where they expected messages to be. Most messages were that size or smaller, and for the rare message that was actually longer, well- they just failed to parse it fully. This was rare enough that no one ever raised a stink about it.
James's team was compliant. Initech was happy their new acquisition could go through. And ten years later, that hack remains in place, and the protocol still tries to terminate with 0x30
.