Warum bricht eine Safari-Seite das iOS-Rendering?

79

Ich weiß, dass der Titel nicht so erklärend ist, aber hier ist die Geschichte: Ich entwickle ein Browsergame, hauptsächlich unter Verwendung von JavaScript und der Mapbox-Bibliothek.

Auf Desktop, Android und iOS funktioniert alles gut, aber unter iOS tritt ein Problem auf: Nachdem das Spiel einige Minuten lang ausgeführt wurde, weist das Telefon plötzlich grafische Artefakte auf und zeigt den größten Teil des verschlüsselten Textes an.

Hier sind einige Fotos, wie das Telefon aussieht: Geben Sie hier die Bildbeschreibung ein Geben Sie hier die Bildbeschreibung ein Geben Sie hier die Bildbeschreibung ein

Meine Frage ist: Was genau in meinem Code kann dies verursachen? Ein Speicherverlust? ( LE : Es stellte sich heraus, dass es sich tatsächlich um einen Speicherverlust handelt.)
Die eigentliche Frage lautet: Wie kommt es, dass Sie fast das gesamte Telefon durch einfaches Durchsuchen einer Webseite blockieren können? Sollte Safari dies nicht stoppen oder zumindest das iOS?

Dies ist bei diesem bestimmten Gerät kein Problem, da dieses Problem auf verschiedenen iPhone-Geräten reproduziert werden kann. (Ich bin mir bei verschiedenen iOS-Versionen nicht so sicher).

Wie ich den Fehler reproduzieren kann:

  1. Öffne das Spiel (in Safari).
  2. 3-4 Minuten laufen lassen.
  3. Schieben Sie das Benachrichtigungscenter nach unten und alles wird verrückt.
    Ich habe ein YouTube-Video hinzugefügt, das zeigt, wie ich den Fehler reproduzieren kann (auf meinem iPhone 5C).
    Es scheint, dass das Problem zuerst im Benachrichtigungscenter auftritt (wenn Sie das Menü von oben nach unten wischen). Derzeit
    scheint dieses Problem nur unter iPhone 5CiOS 9.2.1 (13D15) aufzutreten. Es tritt auch in der neuen iOS 9.3-Version auf.

Um dieses Problem zu beheben , muss ich:

  1. Schließen Sie die Safari-Anwendung (in der die Registerkarte "Spiel" geöffnet ist).
  2. Sperren Sie das Telefon. Nach dem Entsperren ist alles wieder normal.

Einige Details zum Spiel selbst:

  1. Das Spiel zeigt eine Mapbox-Karte und einige Einheiten darüber (Markierungen).
  2. Ein Node.js-Server läuft mit 1 Tick / Sekunde und nach jedem Tick wird der aktualisierte Spielstatus über Socket.io an den Browser gesendet.
  3. Jedes Mal, wenn der Browser den Spielstatus erhält, werden die Markierungen entsprechend aktualisiert.
  4. * Das Spiel aktualisiert möglicherweise auch Markierungen, wenn Sie hinein- oder herauszoomen oder wenn Sie sie auswählen.

EDIT2: Speicherverlust festgestellt (wie erwartet). Nach der Behebung dieses Lecks (auf undefined_icon prüfen ) tritt das Problem nicht mehr auf. Dies bedeutet, dass irgendwo in dieser Richtung der Safari / iOS-Fehler ausgelöst wird.

Hier ist, was genau jeder Tick für jede Einheit genannt wurde, die gruppiert wurde (versteckt und mit anderen in einem MarkerCluster gruppiert wurde):

    var $icon = $(marker._icon); // marker._icon is undefined because of the clustering

    $icon.html('');

    $icon.append($('<img class="markerIcon" src="' + options.iconUrl + '" />'));

    var iconX = 10;
    var iconY = -10;
    var iconOffset = 0;

    for(var v in this.icons) {
        this.icons[v].css('z-index', + $icon.css('z-index') + 1);
        this.icons[v].css('transform', 'translate3d(' + iconX + 'px,' 
                                + (iconY + iconOffset) + 'px,' + '0px)');
        iconOffset += 20;

        this.icons[v].appendTo($icon);
    }

    // Fire rate icons
    this.attackRateCircle = $('<div class="circle"></div>');
    this.attackRateCircle.circleProgress({
        value: 0,
        size: 16,
        fill: { color: "#b5deff" },
        emptyFill: 'rgba(0, 0, 0, 0.5)',
        startAngle:  -Math.PI / 2,
        thickness: 4,
        animation: false,
    });
    this.attackRateCircle.hide();

    // Create and display the healthbar
    this.healthBar = $('<div>').addClass('healthBar ');
    this.healthBar.css('z-index', $icon.css('z-index'));
    this.healthBarFill = $('<span class="fill">');
    this.healthBar.append(this.healthBarFill);

    $icon.append(this.healthBar);
    $icon.append(this.attackRateCircle);

Und das ist das iconsArray:

this.icons = {
    attack_order: $('<img src="img/attack.png" class="status_icon">'),
    attack: $('<img src="img/damage.png" class="status_icon icon_damage">'),
    hit: $('<img src="img/hit.png" class="status_icon icon_hit">'),
};

circleProgressDer Anruf erfolgt aus dieser Bibliothek: https://github.com/kottenator/jquery-circle-progress

DEMO

Ja, ich konnte eine jsFiddle erstellen, die den Fehler reproduziert: https://jsfiddle.net/cte55cz7/14/ Auf Safari auf dem iPhone 5C öffnen und einige Minuten warten. Auf iPhone 6 und iPad mini stürzt die Seite ab (wie erwartet aufgrund des Speicherverlusts)

Hier ist der gleiche Code in einem HasteBin für alle, die ihn nicht ausführen möchten.

XCS
quelle
2
PS: Gepostet auf SO, nachdem für das Posten der Frage am gestimmt wurde SuperUser. Ich hoffe, dass dies der richtige Ort ist, um diese Frage zu stellen.
XCS
2
@wottle Ich habe auf meinem iPhone 5C und eine andere Person (auf einem anderen Kontinent: D) ​​auf einem anderen iPhone getestet, aber ich denke, sein Modell ist auch 5C (und er war derjenige, der mir tatsächlich von diesen Artefakten erzählt hat). Ich werde morgen auf einem iPhone 6 und iPad mini testen.
XCS
2
Wird auf meinem iPhone 6 nicht reproduziert. Es könnte ein Fehler in CG sein. Können Sie alle ios-Versionsinformationen zusammen mit den Hardware-Informationen veröffentlichen?
Fresheyeball
2
Beeindruckend! Und ich dachte, der Bildschirm, der unter Windows 10 Mobile reißt, sei schlecht ...
BoltClock
6
A) Ich bin nicht mal sauer. Das ist erstaunlich. B) Ich frage mich, ob dies tatsächlich als Exploit verwendet werden kann, da Sie eindeutig auf Speicher zugreifen, den Sie nicht können sollten, und C) ich finde es interessant, dass sich immer alles nach links neigt. Das deutet darauf hin, dass Sie aus irgendeinem Grund entweder die Tonhöhen (auch als Schritte bezeichnet) einiger Texturen erhöhen oder die Tonhöhenlogik der GPU ändern. Auf jeden Fall ein Safari / iOS / Firmware-Fehler.
0x24a537r9

Antworten:

1

Dieser Speicherverlust ist wahrscheinlich darauf zurückzuführen, wie die JS Engine von 'WebKit' funktioniert [safari webkit-javascript llvm]

und sieht wirklich so aus, als wäre es ein Pufferüberlauf im virtuellen Speicher, der sich direkt auf den verbleibenden Arbeitsspeicher auswirkt (gemeinsam genutzt und auch von iOS zum Speichern grafischer Elemente der Benutzeroberfläche verwendet).

Relativ zum Code: "[...] jQuery-Speicherlecks zu finden ist einfach. Überprüfen Sie die Größe von $ .cache. Wenn es zu groß ist, überprüfen Sie es und sehen Sie, welche Einträge bleiben und warum. [...]" ( http://javascript.info/tutorial/memory-leaks )

Lassen Sie mich erwarten, dass es relativ zu dieser for-Schleife ist :

for(var v in this.icons) {
    this.icons[v].css('z-index', + $icon.css('z-index') + 1);
    this.icons[v].css('transform', 'translate3d(' + iconX + 'px,' 
                            + (iconY + iconOffset) + 'px,' + '0px)');
    iconOffset += 20;

    this.icons[v].appendTo($icon);
}

Angenommen, die Überprüfung ist abgeschlossen, und wenn Sie die Einträge gefunden haben, möchten Sie die Daten möglicherweise manuell mit removeData () bereinigen, oder Sie verwenden zuerst $ elem.detach () und setzen dann $ (elem) .remove () in setTimeout.

Ein STEFANI
quelle