Acknowledged

bug: System.println and static inlined strings in the simulator cause the wrong string to be used

The following code ran on any device with at least CIQ 3.4.0 that supports toasts (i.e: fr955) in the simulator (either 7.4.3 or 8.0.0-Beta) will incorrectly display "other" instead of the expected "toast".

System.println("toast");
if (WatchUi has :showToast) {
    WatchUi.showToast("toast", null);
}
System.println("other");

I'm not 100% sure whether the bug is in println or maybe showToast or how the simulator implements some string functions or if it's a bug in the compiler, but the above few lines clearly reproduce it. I created a new Watch App with the Monkey C extension, and put the above code somewhere.

Note that the text logged is correct, only in the toast it's incorrect.

  • I see a similar problem in Windows, except instead of displaying a random string literal from the app, the toast displays the "question-mark-in-diamond" character which is displayed when a given character isn't available in the current font. As far as I know, I don't have any strings in my app that consist of a single special character (e.g. non-ASCII).

    The problem follows the same pattern in Windows as it does in Mac:

    - passing a string variable as the first arg to showToast() works

    - passing a string literal, literal resource ID or resource ID variable to showToast() fails

  • > - compiler sees "toast" string literal in multiple places and puts 1 string constant to the data and uses a reference to it in all places.

    While it's possible that the compiler folds duplicate string literals as you described, I don't think that has anything to do with the problem. I tested differently from you:

    - I tested with a string literal that is different from any other string literal in the app, and the problem occurs

    - I tested with a literal resource ID, and the problem occurs

    - I tested with a resource ID variable, and the problem occurs

    The only way I was able to make it work correctly in the simulator was to use a string variable.

  • My theory is something like this happens (based on my example, but of course if we collect more examples then it can be fine tuned):

    - compiler sees "toast" string literal in multiple places and puts 1 string constant to the data and uses a reference to it in all places.

    - somewhere the simulator has a bug that causes it to change the string in some static pointer because it assumes that the execution is done on 1 thread, ... so in my example some pointer points to the "toast" string and then the 2nd println updates this pointer (or rather copies "other" to some buffer that is used by it?) 

    - the toast is not displayed at the time showToast is called but some time later probably after onUpdate

    - but the bug causes the buffer to where the string passed and for the meantime kept in showToast to be changed to "other"

    Again I don't really know what happens or how, and have 0 insight to the simulator's code so it's just guessing.

  • I did find one case where showToast() does display the correct text. If you pass in a string variable as the 1st arg (as opposed to a string literal or a resource ID), the correct text is displayed in the simulator.

    In the simulator:

    // 1) this works
    var x = "hello";
    WatchUi.showToast(x, null);

    // 2) this does not work
    WatchUi.showToast("hello", null);
    // 3) this does not work
    var x = Rez.Strings.AppName;
    WatchUi.showToast(x, null);

    // 4) this does not work
    WatchUi.showToast(Rez.Strings.AppName, null);

    The above results were obtained in the simulator.

    On a real device (fr955), I only tried 4) (passing in a literal resource ID), and it worked properly.

  • btw the app type I used for testing is a complex data field. I'm gonna guess that it doesn't matter what the app type is, as long as it supports showToast().