Bug diving in JavaScript

I was looking into ways to minify a JavaScript app .... Minifying is when you compress the actual source code, to create a smaller download bundle. I'm generally against minifying, because it obfucates the source code, making it harder to see what the code does. But having a small download size is important for this app.

This lead me to the Google Closure compiler.
The closure compiler is both a compiler and minifier, it analyzes the source code and show warnings and errors, it can for example be set to show errors whenever it detects an undeclared variable.
I was a bit surprised by the amount of errors (undefined variables) it did find in my code. A few where false-positives, but the majority actual errors.

I don't want to have errors in my code so I set out to fix them.
Fixing one of the bugs however created an error! Can you spot the bug in the code below ?

The code above calculates the last index of a text row, by taking the start-index of the row below it and subtracting the length of the line-break and indentation-characters.
The closure compiler said variable length was undefined.
I was a bit puzzled why this even worked. But I had a lot to do. So I made a note to investigate later, then made the naive fix by changing file.lineBreak-length to file.lineBreak.length (dot instead of minus sign).

The next day when working on another issue, and got an error because of the code I "fixed" above.

Investigating the bug

I began by writing a test, to confirm that the test actually detects the bug before fixing it. This is called regression testing, and effectively prevents the same bug from comming back at ya.

So I made sure the test failed, then "fixed" the error by reverting the "bug fix", and lo and behold the test passed.
So what the heck is happening?

REPL

I started up a JavaScript REPL to test some theories. A REPL (Read–eval–print loop) is basically a command prompt where you enter code, and the REPF evaluates it on the fly ...

I tried 1-undefined, but that evaluated to NaN (JavaScript's "not a number" object).
This means that the variable length the closure compiler said wasn't defined, actually is a variable, a global variable, defined somewhere ...

"foo"-1 (string minus one) also evaluates to NaN ...
Why doesn't file.lineBreak-length become NaN!?

"\n"-1 (string with new-line-character minus one) evaluates to -1 (minus one)!!

So the line-break characters "\n" minus length (which have value zero) ... becomes zero.
So the proper fix was to remove the line-break-character's length from the equation.

Global variables are bad

But what about that length variable? I don't want global variables in my code. Most of the time global variables exist because someone has forgot to put var in-front of the assignment. And it usually means there's a error in the code.

I searched for length in my code, which unfortunately is a very common word in JavaScript.
I went through hundreds of places where length was assigned, but all of them was local variables ...
Did I miss something ?
I searched for ways to detect global variable declaration's, maybe it can be done in chrome-dev-tools ? But found nothing.
Just as I had asked for suggestions on IRC it came to me:
Maybe length is a global variable built into browsers!?

I opened a new browser tab and tried www.google.com. Opened the dev tools (F12 or Control + Shift + I), went to the console and typed in "length" in the REPL and it evaluated to 2.
I though maybe Google had a bunch of global variables, so I opened about/blank (a blank web page), and length still existed as a global variable!

It turns out the global variable length is the number of iframes on the page!
And my page/app has 0 iframes, so "\n"-length becomes 0.


Written by Mars 22, 2019.


Follow me via RSS:   RSS https://zäta.com/rss_en.xml (copy to feed-reader)
or Github:   Github https://github.com/Z3TA