From 08c76989a719803e4cb7c5391bc864046bba31f2 Mon Sep 17 00:00:00 2001 From: Charles Krinke Date: Mon, 23 Feb 2009 02:43:51 +0000 Subject: Mantis#3187. Thank you kindly, DoranZemlja for a patch that: Adds a warning for an LSL construct that exploits a popular list memory saving hack. --- .../ScriptEngine/DotNetEngine/ScriptManager.cs | 37 +++++++++++ .../Region/ScriptEngine/Interfaces/ICompiler.cs | 1 + .../Shared/CodeTools/CSCodeGenerator.cs | 77 ++++++++++++++++++++++ .../ScriptEngine/Shared/CodeTools/Compiler.cs | 21 ++++++ .../Shared/CodeTools/ICodeConverter.cs | 1 + OpenSim/Region/ScriptEngine/XEngine/XEngine.cs | 32 +++++++++ 6 files changed, 169 insertions(+) diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs index 4ede7f1..32eb200 100644 --- a/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs +++ b/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs @@ -218,6 +218,43 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine localID, itemID, "on_rez", new DetectParams[0], new object[] { new LSL_Types.LSLInteger(startParam) }); } + + string[] warnings = LSLCompiler.GetWarnings(); + + if (warnings != null && warnings.Length != 0) + { + if (presence != null && (!postOnRez)) + presence.ControllingClient.SendAgentAlertMessage( + "Script saved with warnings, check debug window!", + false); + + foreach (string warning in warnings) + { + try + { + // DISPLAY WARNING INWORLD + string text = "Warning:\n" + warning; + if (text.Length > 1100) + text = text.Substring(0, 1099); + + World.SimChat(Utils.StringToBytes(text), + ChatTypeEnum.DebugChannel, 2147483647, + m_host.AbsolutePosition, m_host.Name, m_host.UUID, + false); + } + catch (Exception e2) // LEGIT: User Scripting + { + m_log.Error("[" + + m_scriptEngine.ScriptEngineName + + "]: Error displaying warning in-world: " + + e2.ToString()); + m_log.Error("[" + + m_scriptEngine.ScriptEngineName + "]: " + + "Warning:\r\n" + + warning); + } + } + } } catch (Exception e) // LEGIT: User Scripting { diff --git a/OpenSim/Region/ScriptEngine/Interfaces/ICompiler.cs b/OpenSim/Region/ScriptEngine/Interfaces/ICompiler.cs index 6273da9..d11abbc 100644 --- a/OpenSim/Region/ScriptEngine/Interfaces/ICompiler.cs +++ b/OpenSim/Region/ScriptEngine/Interfaces/ICompiler.cs @@ -34,6 +34,7 @@ namespace OpenSim.Region.ScriptEngine.Interfaces public interface ICompiler { string PerformScriptCompile(string source, string asset); + string[] GetWarnings(); Dictionary, KeyValuePair> LineMap(); } diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs index 71e88e3..880ba4a 100644 --- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs @@ -40,6 +40,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools private int m_braceCount; // for indentation private int m_CSharpLine; // the current line of generated C# code private int m_CSharpCol; // the current column of generated C# code + private List m_warnings = new List(); /// /// Creates an 'empty' CSCodeGenerator instance. @@ -153,6 +154,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools } /// + /// Get the set of warnings generated during compilation. + /// + /// + public string[] GetWarnings() + { + return m_warnings.ToArray(); + } + + private void AddWarning(string warning) + { + if (!m_warnings.Contains(warning)) + { + m_warnings.Add(warning); + } + } + + /// /// Recursively called to generate each type of node. Will generate this /// node, then all it's children. /// @@ -446,6 +464,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools { string retstr = String.Empty; + List identifiers = new List(); + checkForMultipleAssignments(identifiers, a); + retstr += GenerateNode((SYMBOL) a.kids.Pop()); retstr += Generate(String.Format(" {0} ", a.AssignmentType), a); foreach (SYMBOL kid in a.kids) @@ -454,6 +475,62 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools return retstr; } + // This code checks for LSL of the following forms, and generates a + // warning if it finds them. + // + // list l = [ "foo" ]; + // l = (l=[]) + l + ["bar"]; + // (produces l=["foo","bar"] in SL but l=["bar"] in OS) + // + // integer i; + // integer j; + // i = (j = 3) + (j = 4) + (j = 5); + // (produces j=3 in SL but j=5 in OS) + // + // Without this check, that code passes compilation, but does not do what + // the end user expects, because LSL in SL evaluates right to left instead + // of left to right. + // + // The theory here is that producing an error and alerting the end user that + // something needs to change is better than silently generating incorrect code. + private void checkForMultipleAssignments(List identifiers, SYMBOL s) + { + if (s is Assignment) + { + Assignment a = (Assignment)s; + string newident = null; + + if (a.kids[0] is Declaration) + { + newident = ((Declaration)a.kids[0]).Id; + } + else if (a.kids[0] is IDENT) + { + newident = ((IDENT)a.kids[0]).yytext; + } + else if (a.kids[0] is IdentDotExpression) + { + newident = ((IdentDotExpression)a.kids[0]).Name; // +"." + ((IdentDotExpression)a.kids[0]).Member; + } + else + { + AddWarning(String.Format("Multiple assignments checker internal error '{0}' at line {1} column {2}.", a.kids[0].GetType(), ((SYMBOL)a.kids[0]).Line - 1, ((SYMBOL)a.kids[0]).Position)); + } + + if (identifiers.Contains(newident)) + { + AddWarning(String.Format("Multiple assignments to '{0}' at line {1} column {2}; results may differ between LSL and OSSL.", newident, ((SYMBOL)a.kids[0]).Line - 1, ((SYMBOL)a.kids[0]).Position)); + } + identifiers.Add(newident); + } + + int index; + for (index = 0; index < s.kids.Count; index++) + { + checkForMultipleAssignments(identifiers, (SYMBOL) s.kids[index]); + } + } + /// /// Generates the code for a ReturnStatement node. /// diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs index 03b2ab3..59d862d 100644 --- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs @@ -76,6 +76,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools private Dictionary, KeyValuePair> m_positionMap; private ICodeConverter LSL_Converter; + private List m_warnings = new List(); + // private object m_syncy = new object(); private static CSharpCodeProvider CScodeProvider = new CSharpCodeProvider(); @@ -336,6 +338,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools LSL_Converter = (ICodeConverter)new CSCodeGenerator(); compileScript = LSL_Converter.Convert(Script); + // copy converter warnings into our warnings. + foreach(string warning in LSL_Converter.GetWarnings()) + { + AddWarning(warning); + } + m_positionMap = ((CSCodeGenerator) LSL_Converter).PositionMap; } @@ -373,6 +381,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools return CompileFromDotNetText(compileScript, l, asset); } + public string[] GetWarnings() + { + return m_warnings.ToArray(); + } + + private void AddWarning(string warning) + { + if (!m_warnings.Contains(warning)) + { + m_warnings.Add(warning); + } + } + private static string CreateJSCompilerScript(string compileScript) { compileScript = String.Empty + diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/ICodeConverter.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/ICodeConverter.cs index 28e42da..917000e 100644 --- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/ICodeConverter.cs +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/ICodeConverter.cs @@ -33,5 +33,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools public interface ICodeConverter { string Convert(string script); + string[] GetWarnings(); } } diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index 75d0bec..40a6dd1 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs @@ -516,6 +516,38 @@ namespace OpenSim.Region.ScriptEngine.XEngine m_AddingAssemblies[assembly]++; } } + + string[] warnings = m_Compiler.GetWarnings(); + + if (warnings != null && warnings.Length != 0) + { + if (presence != null && (!postOnRez)) + presence.ControllingClient.SendAgentAlertMessage("Script saved with warnings, check debug window!", false); + + foreach (string warning in warnings) + { + try + { + // DISPLAY WARNING INWORLD + string text = "Warning:\n" + warning; + if (text.Length > 1000) + text = text.Substring(0, 1000); + World.SimChat(Utils.StringToBytes(text), + ChatTypeEnum.DebugChannel, 2147483647, + part.AbsolutePosition, + part.Name, part.UUID, false); + } + catch (Exception e2) // LEGIT: User Scripting + { + m_log.Error("[XEngine]: " + + "Error displaying warning in-world: " + + e2.ToString()); + m_log.Error("[XEngine]: " + + "Warning:\r\n" + + warning); + } + } + } } catch (Exception e) { -- cgit v1.1