Today, a link that could crash Google Chrome hit the news. And here it is. If that was
a real link, and you moused over it or clicked it, Chrome would instantly crash. At least,
as I record this, if you're watching this off in the future, it's probably fixed. To
understand why, we need to learn about how computers store text.
As you probably know, computers store letters and words -- the term is strings of characters
-- as ones and zeros. But the metaphors you see on screen, of files and folders all neatly
organised or, in programming languages, the idea of individual variables stored separately
in memory, those metaphors hide what's actually going on -- which is that down at the metal,
or at the silicon, it really is just ones and zeros, with everything just stuffed next
to each other. How does a computer know where to start and stop reading in that jumble of binary?
Finding the right string and starting to read it is pretty easy, there's an index of memory
locations somewhere. Most programmers never actually have to deal with this, it's all
abstracted away for you by the language you choose, but at some point, the computer has
to say: right, you see this bit of memory, right here. That is, let's say, the web page
the user wants to see next. Start reading that here.
But remember: the memory it's reading is just a huge, nearly-endless string of ones and
zeros. If "start here" is all the information the computer's got when it tries to read it
back, then it doesn't know how long that string is. It'll quite happily keep reading and reading
and reading unless it knows that length. And there are a couple of approaches on how to
solve that.
First, you could store the length of the string with the string. Generally at the start. So
the computer gets pointed to the location, and the first thing it reads is something
that says, right, you are looking for 14 characters. And then it reads out the 14 characters, and
everyone's happy.
And that's the modern way of doing things, now we've got plenty of memory, but there's
a catch: if you're storing longer strings, longer than a couple of sentences, you're
also going to need more than one byte to store the length of the string -- and you're going
to need to do that for every string, no matter how short or long it is. It's not that space-efficient.
I mean, I'm simplifying, there are other ways of handling that, but anyway -- there are
still a lot of implementations that use the older, dirtier version: which is to stick
a NULL character on the end of your string.
A NULL is a byte that is completely zeroed. Eight binary zeros in a row. We're not talking
about actually trying to type the number 0 here, that's got its own code, this is a special,
separate character just called NULL. So this is called a null-terminated string, the computer
just starts reading the string where it's told to, and when it gets to a NULL, when
it sees eight binary zeros in a row, it goes, ah! The string's over. Brilliant. Which means
you don't need all this fuss about storing the length. Now, there is a whole load of
computer science lectures on which technique is more efficient for which operation, and
why you might want to store the length or you might not: all you need to know right
now is, both of those techniques are still in use.
Which brings me back to this URL.
First of all, those percentage signs. In a URL, that percentage sign means an encoded
character. You can't put certain punctuation marks in a URL because they have special meanings:
a hash sign, for example, means "go to this point on the web page", so if you actually
need to use a hash sign in the filename, in the URL, you have to encode it. And you encode
it as its representation here on this chart, which goes way back to the 1980s. But the
important part is: percent sign, then two letters or numbers means "convert this to
something else".
Right. So let's run that on this URL. We've got two areas that match: percent three zero,
here and here. And if we look that up on the chart: that gets decoded to... the number
zero. Not a NULL, just literally, as if you typed the number zero.
So far, so innocent. Except there's still a percent sign left, so if we run that decoder
again on the result, now we're trying to decode percent zero zero. Which gets decoded: to
NUL.
So originally, I thought, okay, it's returning a string of a different length than it expected,
or something like that, it's putting a NULL where it shouldn't be, but no: it's more subtle
than that. Chrome is taking the full URL, decoding it once -- which is still sort-of
valid, 'cos that NUL is escaped -- marking it as being guaranteed A-OK, safe to use,
then sending it off to the next bit of code. That function then decodes it again, notices
that NUL, and says hey, that's not a valid character. We can't have that. So it marks
the URL as invalid...
...but the earlier code doesn't care, it already knows it's good, so it just passes it onwards,
a guaranteed-safe URL that isn't. At which point Chrome goes "something has gone terribly
wrong here" and crash--
[Translating this video? Add your name here if you'd like credit!]