Shortnote

 Oh no, not this shit again! The following section is motivated by a few requests that we have received to demonstrate what the main portability problems are between Linden's implementation of LSL and OpenSim's implementation of LSL.

OpenSim, on the other hand, went a different way. Instead of fixing bugs and focusing on implementing Linden's specification, it has turned into a larger codebase where the developers dump new features that themselves may contain other, new and interesting bugs.

Aside from physics that are completely unusable on OpenSim (which sort of takes the fun away from a Virtual World), OpenSim suffers from low-level implementation bugs that have never been addressed (for years) and we believe that they will not be fixed too soonly.

Score

Second Life OpenSim
7 6

Sensor Events

SecondLife OpenSim Discovered
Broken Working 22nd of August 2013

The following code scans for agents within a 10m range:

default {
    state_entry() {
        llSensor("", "", AGENT, 10, TWO_PI, 1);
    }
    sensor(integer num) {
        llSensorRemove();
        llOwnerSay((string)llDetectedKey(0));
    }
}

The documentation says that the llSensor call should trigger the sensor event handler and detect all primitives and agents within range. However, the code above does not seem to work, the culprit being llSensorRemove which has no purpose, nor defined meaning, within the sensor event handler.

Improper Scoping in Nested Blocks

SecondLife OpenSim Discovered
Working Broken cca. 2012
default {
    state_entry() {
        if(1) { // any block: while, for, etc.
            integer i = 2;
        }
        integer i = 3;
    }
}

In the Linden implementation of LSL, variables are bound to the scope that they are declared in. In the OpenSim version, this bails out with an error saying that the second declaration of the variable i will give a different meaning to the variable i. This is most likely because of OpenSim's closeness to C#, for example:

using System; namespace Test { class Test { public static void Main() {
      if(1) {
        integer i = 1;
      }
      integer i = 2;
      Console.WriteLine("Hello");
} } }

Returns the same error as the LSL snippet above. This applies to overloading event handler variables as well.

Empty List

SecondLife OpenSim Discovered
Working Broken cca. 2011

As one of the first discoveries of Wizardry and Steamworks, mentioned on the LSL FUSS page on using the empty list in a conditional, the following snippet:

default {
    state_entry() {
        list a = [ 1, 2, 3, 4 ];
        do {
            a = llDeleteSubList(a, 0, 0);
        } while(a);
        llOwnerSay("list a, contains: " + (string)llGetListLength(a) + " elements");
    }
}

fails to compile on OpenSim1).

So does:

default {
    state_entry() {
        list a = [];
        if(a) {
            llOwnerSay("not empty");
            return;
        }
        llOwnerSay("empty");
    }
}

which bails out claiming that the list a cannot be converted to bool (C# again), although there is no boolean datatype in LSL.

Assignment in Function Calls

SecondLife OpenSim Discovered
Working Broken 22nd of August 2013
default {
    state_entry() {
        string flag;
        llOwnerSay(flag = "Hello");
    }
}

they all fail to compile on OpenSim… This makes tricks, such as using llSensorRepeat as a second timer impossible.

Overflows

SecondLife OpenSim Discovered
Working2) Broken3) 22nd of August 2013

In Linden's implementation, the stack and the heap are coalesced together with the code into one big pile of goo. OpenSim however, seems to separate the two, such that:

float recurse(float a) {
    return recurse(llPow(a, 3.402823466E+38));
}
 
default {
    state_entry() {
        recurse(2);
    }
}

bails out with a stack overflow error - note that this is not a stack/heap overflow, perhaps indicating that they are not coalesced in OpenSim as they are on Second Life.

On the other hand:

default {
    state_entry() {
        float a = 3.402823466E+38;
        do {
            a = llPow(a, 3.402823466E+38);
        } while(1);
    }
}

lags the server very badly, sometimes ending up [making the script engine give up] in errors such as:

(0): Couldn't find assembly 'OpenSim.Region.ScriptEngine.Shared, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'

which just indicates that DoS attacks based on resource exhaustion are possible (perhaps using multiple threads / scripts). This also seemed to be the main attack pattern for Jaine Mariolack mentioned on several websites.

Event Handlers

SecondLife OpenSim Discovered
Interesting Interesting 23nd of August 2013

Event handlers seem to be under different scoping rules than other blocks. This seems to be both true for SecondLife and for OpenSim.

For example, the following snippet:

changed(integer change) {
  if(change & CHANGED_INVENTORY || change & CHANGED_OWNER) llResetScript();
}

does compile.

On the other hand, the following example, does not:

changed(integer change) if(change & CHANGED_INVENTORY || change & CHANGED_OWNER) llResetScript();

This is most likely because event handlers have dynamic scoping and are evaluated at runtime. This is different from other type of blocks that are evaluated at compile-time.

Notecard Handling

SecondLife OpenSim Discovered
Broken Working cca. 2012

In SecondLife, when creating a blank notecard called News and dropping it into the inventory of an object, the following script:

default {
    state_entry() {
        llGetNotecardLine("News", 0);
    }
 
    changed(integer change) {
        if(change & CHANGED_INVENTORY) llResetScript();
    }
 
    dataserver(key id, string data) { }
}

throws an error claiming that it could not find the notecard. However, if the notecard created in the inventory contains at least a character, the script is able to find it. The same does not apply to llGiveInventory that correctly hands out the News notecard.

Slow Event Handlers

SecondLife OpenSim Discovered
Working Broken cca. 2011

OpenSim seems to be slow to process event handlers, for example if we take the bistable color primitive script and compare the speed it takes to switch from one color to the other on both SecondLife and OpenSim, you will notice that the OpenSim version is much slower.

This just demonstrates the inefficiency of the OpenSim code and we believe that terraforming is yet another instance of the same problem - perhaps a threading problem?

The problem is fixed by Wizardry and Steamworks as a patch to OpenSim.

Event Handlers Limits

SecondLife OpenSim Discovered
Working Broken cca. 2011

OpenSim allows users to control the behavior of event handlers. There are two settings in the configuration file that allows to tweak event handlers:

  • the number of events that will be queued to be processed by an event handler (MaxScriptEventQueue).
  • the maximal amount of time that an event handler can run (EventLimit).

The following code illustrates the behavior by assigning a large (yet within bounds) number to an integer and then counting down and moving the prim between two coordinates. The time is not even printed out and the script just dies after EventLimit seconds.

default {
    state_entry() {
        llGetAndResetTime();
        integer i = 2147483648;
        do {
            llSetPos(<135.811096, 133.027771, 23.292763>);
            llSetPos(<135.811096, 132.216675, 23.292763>);
            llOwnerSay((string)i);
        } while(--i>-1);
        llOwnerSay((string)llGetAndResetTime());
    }
}

This unlike Linden's Second Life and, security aside, there is absolutely no reason for these settings to exist because they break compatibility with Linden's implementation. For example, objects that are meant to generate geometric dispositions such as the planar tile generator or jewelry generators will break unless they use asynchronous event handlers such as timer.

Elementary Physics Engine Inconsistencies

SecondLife OpenSim Discovered
Working Broken cca. 2011

Simplest forms of physics tests, such as dropping the script bellow and assuming that both OpenSim and SecondLife use 9.81m/s as gravity:

default {
    state_entry() {
        llSetStatus(STATUS_PHYSICS, TRUE);
        llSetForce(<0,0,9.81> * llGetMass(), TRUE);
    }
}

will indicate that OpenSim's implementation is broken and that the script makes the primitive that it is placed in rise rather than keeping it motionless - even further attempts to hold it in-place by editing the object will still make the object rise.

On SecondLife however, the two calls do not seem to be atomic, which make building certain simulations such as the Great Wanderer difficult.

That is because by dropping the script above into a primitive, or just restarting the script will turn physics on, at which point the primitive receives a downward acceleration and by the time the counter-force (using llSetForce) kicks in, the object already has a downward motion. The only way around this problem, is to either:

  • hack the script so that impulses stabilize the object somehow4).
  • turn physics on manually (by editing the object and holding it in place) and only then resetting the script.
  • using prim parameters to set the gravity (ratio?) to zero.

A more sensible solution would be to make those two functions atomic - in order to prevent the race condition.

Non-responsive Primitives

SecondLife OpenSim Discovered
Broken Not sighted cca. 2011

Sometimes reproduced by:

  1. Creating a primitive.
  2. Creating a script inside that primitive.
  3. Editing the script so that it contains errors.
  4. Recompiling the script a few times.
  5. Repeat at (1) several times.

This is a long-time standing Second Life bug that seems to plague scripted objects. For no reason that is easy to determine, after a certain number of cycles, the primitives seems to remain unresponsive so that even if the script is recompiled, deleted or substituted for something else, the primitive simply does not perform the actions in the script.

The only solution, is to create a new primitive and copy the script over and to dispose of the "broken" primitive.

Splitting Strings To Lists

SecondLife OpenSim Discovered
Broken Working 18th of October 2013

The following code:

default
{
    state_entry()
    {
        string sa = "12999";
        list la = llParseString2List(sa, [], ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]);
        llOwnerSay("la: " + llDumpList2String(la, ","));
 
        string sb = "abzzz";
        list lb = llParseString2List(sb, [], ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]);
        llOwnerSay("lb: " + llDumpList2String(lb, ","));
    }
}

produces the output:

[16:52] Primitive: la: 1,2,9,9,9
[16:52] Primitive: lb: a,b,z,z,z

on OpenSim, and on Second Life, the output is the following:

[16:50] Object: la: 1,2,999
[16:50] Object: lb: a,b,zzz

which would indicate that the Second Life LSL implementation of llParseString2List is broken. If the list is shortened, such as:

list lb = llParseString2List(sb, [], ["a", "b", "z"]);

we get the correct result a,b,z,z,z on both OpenSim and Second Life.

List Length

SecondLife OpenSim Discovered
Broken Working 20th of October 2013

Given the following code:

default
{
    state_entry()
    {
        list a = [ 1, 2, 3 ];
        integer k = (a!=[]);
 
        llOwnerSay((string)k);
    }
}

the reasoning is that the integer k will be set to the truth value of (a!=[]) (since this is not an object-oriented language with references, the meaning of a!=[] is the list a is not empty). So the expected outcome of the program would be that k=1. This works fine on OpenSim but in SecondLife, the code returns the length of list a - which is absolutely nonsense.

As a counter-example, the previous reasoning holds for the following snippet:

default
{
    state_entry()
    {
        integer k = 3 > 1;
 
        llOwnerSay((string)k);
    }
}

which means that the integer k will be set to the truth value of 3>1. In this case, the expected outcome k=1 can be observed on both OpenSim and Second Life.

llCSV2List and llList2CSV

SecondLife OpenSim Discovered
Broken Broken N/A by design
llList2CSV([ "a", "b" ]);

is functionally equivalent to:

llDumpList2String([ "a", "b" ], ", ");

Similarly:

llCSV2List("a, b");

is functionally equivalent to:

llParseString2List("a, b", [ ", " ], []);

which is absolute nonsense by any CSV standard (ie: RFC 4180) and makes llList2CSV and llCSV2List redundant.

A list such as [ "something, something", "is broken" ] will not survive a llList2CSV / llCSV2List roundtrip.

Wizardry and Steamworks have an implementation of an RFC 4180 compliant set of CSV functions.

llEscapeURL and llUnescapeURL

SecondLife OpenSim Discovered
Broken Broken N/A by design

The functions llEscapeURL and llUnescapeURL are, in fact, URI escape functions instead of URL escape functions as their name would erroneously imply.

The misleading nomenclature leads to issues perceived in other languages as well such as PHP or, lately, node.js.

Furthermore, since these functions are bound to be used given llHTTPRequest or http_request / http_response, neither llEscapeURL nor llUnescapeURL do not provide an application/x-www-form-urlencoded encoding. In other words, llEscapeURL and llUnescapeURL cannot be used to POST form data.

Wizardry and Steamworks has created a set of LSL functions that perform application/x-www-form-urlencoded encoding and decoding.

1)
and the reason why we avoid this beauty in scripts
2)
The proper way for these issues to be handled would be to interrupt the script before it can cause damage. A measure that SecondLife takes.
3)
OpenSim uses watchdogs to interrupt the scripts, but that does not seem to work too well.
4)
and this is why the Great Wanderer dicks around with llSetStatus

fuss/lsl/bugs.txt · Last modified: 2019/10/01 10:10 by office

Access website using Tor Access website using i2p


For the copyright, license, warranty and privacy terms for the usage of this website please see the license, privacy and plagiarism pages.