Hide Document Parts:
Images
   Digital Media
Forms
QR Code
Output Options:
Print Document
Download PDF
Article
Comments

Solving bugs I didn’t know I had!

This has been a very eventful week and a very successful one as far as my programming career goes. Besides the post I put up a few days ago, Knowing when it’s time to toss code out!, I also stumbled on to a bug that turned out not to be a bug and figured I should share.

So the background of this post in true TL;DR fashion: JavaScript has a bug that returns OBJECT when checking the type of something that is NULL. For the full explanation of this and to get caught up to speed on what I’m talking about so far you should read Dr. Axel Rauschmayer’s post The history of “typeof null”.

What happened this week though when I stumbled on this tidbit of knowledge is I panicked! First, I wrote a custom function that I have been using pretty heavily called empty that replies on checking a variables type and second, I had started writing a strip tag (html entity stripper) that was going to rely on checking types. Since the strip tag function was nowhere near completion my main concern really was my empty function biting me with a zero day or some other crippling bug. At the time I’m writing this post (June 2017) the Hive LMS project is really nowhere near a stage that this should concern me with zero days and crippling bugs but as I learned in Knowing when it’s time to toss code out!, fixing mistakes and rewriting code can cost you a lot of time and time is something I don’t have a lot of at the moment.

Jumping back in the story for just a second I had at this point read Eric Corry’s The madness of parsing real world JavaScript Regexps and checked out Mathias Bynens’ Robust HTML entity encoder/decoder AKA he, for use in my string tags function; which by the way I think I’m going to call sanitize but that’s another story altogether.

As I started to dig into the code and see how I could potentially catch this type bug it hit me: I opted not to use JavaScript’s built-in type checker in the first place. This decision mostly was because I never used it before and felt I wanted a more controlled approach that I understood. This led me to using the following function I found on Stack Overflow somewhere; quite possibly was in someones comment:

/**
* @author Stack Overflow Community
* @return string Return the type (name) of what was sent in; result is in uppercase.
*/
function typeOf(unknown){
    return ({}).toString.call(unknown).match(/\s([^\]]+)/)[1].toUpperCase();
}

This little gem gets the variables type by looking at it as a string and not relying on the built in typeof that checks the bits. This means when something is null the function literally sees and returns the string null converted to uppercase with toUpperCase to make things easier to see in the code.

A Simple Change

This then meant I only needed to add one line of code to my empty function to catch this bug. You can see the change on line 55 in the code below and a comment I added on line 54 explaining what is happening:

/**
* Check if a string, number, array, or object is empty.
* NOTE: This correctly handles the built-in typeOf null equals object bug because I use
* a custom typeOf function. This is what I'm refering to: http://2ality.com/2013/10/typeof-null.html
* @author Stack Overflow Community
* @author Christopher Keers <cdkeers@caboodle.tech>
* @return boolean True if empty, null, 0, false, or of length 0 otherwise false is returned.
*/
function empty(unknown){
    /** Don't waste time. */
    if (unknown==null || unknown=='undefined'){ return true; }
    /**
    * Fast way to get variables datatype. Original code: https://stackoverflow.com/a/7390612/3193156
    * Altered with Lily Finley's RegEx in the comments.
    */
    var type = typeOf(unknown);
    switch (type){
        case 'ARRAY':
            /** If the array is 0 it's empty. */
            if(unknown.length<1){ return true; }
            /** See if there is anything saved inside. */
            var tmp;
            for (var index in unknown) {
                tmp = typeOf(unknown[index]);
                if(tmp=='ARRAY' || tmp=='OBJECT'){
                    if(!empty(unknown[index])){ return false; }
                } else {
                    if(unknown[index].length>0){ return false; }
                }
            }
            return true;
            break;
        case 'NUMBER':
            if(unknown<0 || unknown>0){ return false; }
            return true;
            break;
        case 'OBJECT':
            /**
            * Original Code: https://stackoverflow.com/a/4994244/3193156
            */
            /** Assume if it has a length property with a non-zero value that that property is correct. */
            if (unknown.length > 0){ return false; }
            if (unknown.length === 0){ return true; }
            /**
            * Otherwise, does it have any properties of its own?
            * This doesn't handle toString and valueOf enumeration bugs in IE < 9
            */
            for (var key in unknown) {
                if (hasOwnProperty.call(unknown, key)){ return false; }
            }
            return true;
            break;
        case 'STRING':
            /** Catch null that was cast as a string. */
            if(unknown.toLowerCase()=='null'){ return true; }
            /** Check that a empty string or number is not sneaking by. */
            if(unknown.length>0&&parseInt(unknown)!=0){ return false; }
            return true;
            break;
        case 'UNDEFINED':
        default:
            return true;
    }
}

So there you have it! I solved a bug I thought I had by avoiding the bug unknowingly in the first place.

Comments are currently disabled. Please check back later.
Close
Categories