WTF! MicrosoftAjax.js vs ‘use strict’ vs Firefox vs IE

Hi folks

I fixed a very weird bug today.

Initially the bug was raised that some actions causes JavaScript error in Firefox:

TypeError: access to strict mode caller function is censored

This was not happening in IE or Chrome.

I started to debug and found that the problem is within MicrosoftAjax framework. I am working on a legacy ASP.NET WebForms project which uses and relies on it heavily.

For the blogging purposes I looked for a debug/unminified version of the problematic script and found it here: http://ajax.aspnetcdn.com/ajax/4.5.2/1/MicrosoftAjaxWebForms.Debug.js

I would like to refer to some lines so I uploaded the same file to gist.

The problematic line was https://gist.github.com/mnaoumov/55be04ca588ff22f851f#file-microsoftajaxwebforms-debug-js-L738

while (caller.arguments.callee.caller && --recursionLimit) {

where at some stage caller.arguments.callee variable equals to the function that is defined in some script with

"use strict";

directive

and therefore it prohibited to call its caller

And the reason why this issue occurred in Firefox only is the line https://gist.github.com/mnaoumov/55be04ca588ff22f851f#file-microsoftajaxwebforms-debug-js-L733

var event = window.event;

window.event is undefined in Firefox. This event variable is not really needed. The only place it is used https://gist.github.com/mnaoumov/55be04ca588ff22f851f#file-microsoftajaxwebforms-debug-js-L785 would be called under pretty rare condition according to the code flow.

activeElement = event ? (event.target || event.srcElement) : null;

So in order to fix the problem I think it is pretty safe to fake **window.event** for this function.

So I’ve written a hack

/**
 * This is required to fix a bug in MicrosoftAjaxWebForms.js
 * in Firefox where if window.event is not initialized, it loops stack
 * via arguments.callee.caller chain and breaks because of the
 * "use strict" mode
 */
function hackEventWithinDoPostBack() {
    var originalDoPostBack = window.__doPostBack;

    window.__doPostBack = function hackedDoPostBack() {
        if (!window.event)
            window.event = {};
        return originalDoPostBack.apply(this, arguments);
    };
}

And this worked fine in Firefox. I thought it would work fine in IE and Chrome as well because I am checking for window.event before overriding but it was not!

IE11 started to fail in other places with the following error

Assignment to read-only properties is not allowed in strict mode

That was caused by the

window.event = {};

line written above. I found that window.event still can be undefined but you are not allowed to set it explicitly.

That appeared to be a bit tricky to overcome and eventually I came up with a pretty sophisticated solution

/**
 * This is required to fix a bug in MicrosoftAjaxWebForms.js
 * in Firefox where if window.event is not initialized, it loops stack
 * via arguments.callee.caller chain and breaks because of the
 * "use strict" mode
 *
 * Hacking window.event property is required because it is
 * not settable in Internet Explorer
 */
function hackEventWithinDoPostBack() {
    var originalEventDescriptor = Object.getOwnPropertyDescriptor(Window.prototype, "event");
    var hackEventVariable = false;
    var eventPropertyHolder;
    Object.defineProperty(window, "event", {
        configurable: true,
        get: function get() {
            var result = originalEventDescriptor ? originalEventDescriptor.get.apply(this, arguments) : eventPropertyHolder;
            if (result || !hackEventVariable)
                return result;
            return {};
        },
        set: function set(value) {
            if (originalEventDescriptor)
                originalEventDescriptor.set.apply(this, arguments);
            else
                eventPropertyHolder = value;
        }
    });

    var originalDoPostBack = window.__doPostBack;

    window.__doPostBack = function hackedDoPostBack() {
        hackEventVariable = true;
        originalDoPostBack.apply(this, arguments);
        hackEventVariable = false;
    };
}

This works in IE, Chrome and Firefox.

Such a workaround, isn’t it?!

Stay tuned

Advertisements

About mnaoumov

Senior .NET Developer in Readify
This entry was posted in Uncategorized and tagged , . Bookmark the permalink.

2 Responses to WTF! MicrosoftAjax.js vs ‘use strict’ vs Firefox vs IE

  1. sreenath says:

    where we have to inculde above code and when it will call

  2. Shiva PRasad says:

    Its nice , can you please update for safari . the error in safari
    TypeError: Requested property descriptor of a value that is not an object.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s