nokola
Topic Author
Posts: 188
Joined: 10 Mar 2015, 05:29

Error importing xaml with single quotes (looked like buffer overflow) in Unity

08 May 2017, 08:09

Edit: updated title to better help others
Tried opening bug but the bug report interface says "you have no permissions to access bug<something>.php> on this server" when I click Submit Report
Note: this bug is blocking our XAML development

Here's the issue:
Buffer overflow in Noesis loading a simple XAML with two rectangles and animations


When I try to import CropFramePhone.xaml file (attached, 45 lines XAML) I get an ArgumentException about "Illegal characters in path in NoesisPostprocessor.cs.
When I changed the code to log the path, I noticed it is a broken string - looks like some XAML overwrote the string null terminating character in memory. See bold section below

1. Create new Unity3d 3D Project
2. Add Noesis, ensure "show preview" is selected in Noesis Settings
3. Copy attached CropFramePhone.xaml to Assets
Expected:
all imports OK
Actual:
ArgumentException: Illegal characters in path.
System.IO.Path.IsPathRooted (System.String path) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.IO/Path.cs:508)
System.IO.Path.InsecureGetFullPath (System.String path) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.IO/Path.cs:357)
System.IO.Path.GetFullPath (System.String path) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.IO/Path.cs:289)
NoesisPostprocessor.NormalizePath (System.String uri) (at Assets/NoesisGUI/Plugins/Editor/NoesisPostprocessor.cs:97)
NoesisPostprocessor.AbsolutePath (System.String parent, System.String uri) (at Assets/NoesisGUI/Plugins/Editor/NoesisPostprocessor.cs:134)
NoesisPostprocessor.ScanFonts (.NoesisXaml xaml, System.String directory, System.String text) (at Assets/NoesisGUI/Plugins/Editor/NoesisPostprocessor.cs:247)
NoesisPostprocessor.ScanDependencies (.NoesisXaml xaml, System.String directory) (at Assets/NoesisGUI/Plugins/Editor/NoesisPostprocessor.cs:297)
NoesisPostprocessor.ImportXaml (.NoesisXaml xaml, System.String directory, System.IO.FileStream file) (at Assets/NoesisGUI/Plugins/Editor/NoesisPostprocessor.cs:308)
NoesisPostprocessor.ImportXaml (System.String filename) (at Assets/NoesisGUI/Plugins/Editor/NoesisPostprocessor.cs:322)
NoesisPostprocessor.OnPostprocessAllAssets (System.String[] importedAssets, System.String[] deletedAssets, System.String[] movedAssets, System.String[] movedFromAssetPaths) (at Assets/NoesisGUI/Plugins/Editor/NoesisPostprocessor.cs:50)
System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Reflection/MonoMethod.cs:222)
Rethrow as TargetInvocationException: Exception has been thrown by the target of an invocation.
System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Reflection/MonoMethod.cs:232)
System.Reflection.MethodBase.Invoke (System.Object obj, System.Object[] parameters) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Reflection/MethodBase.cs:115)
UnityEditor.AssetPostprocessingInternal.PostprocessAllAssets (System.String[] importedAssets, System.String[] addedAssets, System.String[] deletedAssets, System.String[] movedAssets, System.String[] movedFromPathAssets) (at C:/buildslave/unity/build/Editor/Mono/AssetPostprocessor.cs:27)

To debug, after getting the exception in Steps to Reproduce, add the below try..catch in NormalizePath in NoesisPostprocessor.cs around line 93:
    private static string NormalizePath(string uri)
    {
        try
        {
            string full = Path.GetFullPath(uri).Replace('\\', '/');
            return full.Substring(full.IndexOf("Assets/"));
        }
        catch (ArgumentException)
        {
            throw new ArgumentException("Path: *" + uri + "*");
        }
    }
Run again. Reimport the XAML. Notice the path string is not null terminated - some memory was overwritten during import.
ArgumentException: Path: *Assets/

<Rectangle StrokeThickness='0' Height='1' Fill='*

NoesisPostprocessor.NormalizePath (System.String uri) (at Assets/NoesisGUI/Plugins/Editor/NoesisPostprocessor.cs:102)
NoesisPostprocessor.AbsolutePath (System.String parent, System.String uri) (at Assets/NoesisGUI/Plugins/Editor/NoesisPostprocessor.cs:134)
NoesisPostprocessor.ScanFonts (.NoesisXaml xaml, System.String directory, System.String text) (at Assets/NoesisGUI/Plugins/Editor/NoesisPostprocessor.cs:247)
NoesisPostprocessor.ScanDependencies (.NoesisXaml xaml, System.String directory) (at Assets/NoesisGUI/Plugins/Editor/NoesisPostprocessor.cs:297)
NoesisPostprocessor.ImportXaml (.NoesisXaml xaml, System.String directory, System.IO.FileStream file) (at Assets/NoesisGUI/Plugins/Editor/NoesisPostprocessor.cs:308)
NoesisPostprocessor.ImportXaml (System.String filename) (at Assets/NoesisGUI/Plugins/Editor/NoesisPostprocessor.cs:322)
NoesisPostprocessor.OnPostprocessAllAssets (System.String[] importedAssets, System.String[] deletedAssets, System.String[] movedAssets, System.String[] movedFromAssetPaths) (at Assets/NoesisGUI/Plugins/Editor/NoesisPostprocessor.cs:50)
System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Reflection/MonoMethod.cs:222)
Rethrow as TargetInvocationException: Exception has been thrown by the target of an invocation.
System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Reflection/MonoMethod.cs:232)
System.Reflection.MethodBase.Invoke (System.Object obj, System.Object[] parameters) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Reflection/MethodBase.cs:115)
UnityEditor.AssetPostprocessingInternal.PostprocessAllAssets (System.String[] importedAssets, System.String[] addedAssets, System.String[] deletedAssets, System.String[] movedAssets, System.String[] movedFromPathAssets) (at C:/buildslave/unity/build/Editor/Mono/AssetPostprocessor.cs:27)

XAML to repro (name it CropFramePhone.xaml):
<UserControl x:Class="Adorners.Frames.CropFramePhone"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400" 
      xmlns:system="clr-namespace:System;assembly=mscorlib">
	  
	<Grid d:DesignHeight="300" d:DesignWidth="400" UseLayoutRounding="True">
		<Grid.Resources>
			<Storyboard x:Name="animFadeIn">
				<DoubleAnimation To="1" Storyboard.TargetName="gridGuides" Storyboard.TargetProperty="Opacity" BeginTime="0:0:0.3" Duration="0:0:0.5">
					<DoubleAnimation.EasingFunction>
						<CubicEase EasingMode="EaseOut"/>
					</DoubleAnimation.EasingFunction>
				</DoubleAnimation>
			</Storyboard>
			<Storyboard x:Name="animFadeOut">
				<DoubleAnimation To="0" Storyboard.TargetName="gridGuides" Storyboard.TargetProperty="Opacity" Duration="0:0:0.5">
					<DoubleAnimation.EasingFunction>
						<CubicEase EasingMode="EaseOut"/>
					</DoubleAnimation.EasingFunction>
				</DoubleAnimation>
			</Storyboard>
		</Grid.Resources>

		<Grid x:Name="gridGuides" Opacity="0">
			<Grid.RowDefinitions>
				<RowDefinition />
				<RowDefinition Height="1.6180339887*"/>
				<RowDefinition />
			</Grid.RowDefinitions>
			<Grid.ColumnDefinitions>
				<ColumnDefinition />
				<ColumnDefinition Width="1.6180339887*"/>
				<ColumnDefinition />
			</Grid.ColumnDefinitions>
			
			<Rectangle StrokeThickness='0' Height='1' Fill='#60FFFFFF' Grid.ColumnSpan='3' HorizontalAlignment='Stretch' Grid.Row='1' VerticalAlignment='Top' />
			<Rectangle StrokeThickness='0' Height='1' Fill='#60FFFFFF' Grid.ColumnSpan='3' HorizontalAlignment='Stretch' Grid.Row='2' VerticalAlignment='Top' />
		</Grid>
	</Grid>
</UserControl>
Last edited by nokola on 09 May 2017, 02:33, edited 2 times in total.
 
User avatar
sfernandez
Site Admin
Posts: 1912
Joined: 22 Dec 2011, 19:20

Re: Buffer overflow in Unity when loading simple XAML

08 May 2017, 11:08

Hi,

The problem was that our xaml post-processor was not dealing correctly with single quotes.
You can go to Assets/NoesisGUI/Plugins/Editor/NoesisPostprocessor.cs and substitute ScanKeyword() function with the following code:
    private static List<string> ScanKeyword(string text, string keyword)
    {
        List<string> strings = new List<string>();

        int cur = 0;
        int pos;

        while ((pos = text.IndexOf(keyword, cur, StringComparison.OrdinalIgnoreCase)) != -1)
        {
            int start = pos;
            while (start >= 0 && text[start] != '\"' && text[start] != '\'' && text[start] != '>')
            {
                start--;
            }

            int end = pos;
            while (end < text.Length && text[end] != '\"' && text[end] != '\'' && text[end] != '<')
            {
                end++;
            }

            if (start >= 0 && end < text.Length)
            {
                strings.Add(text.Substring(start + 1, end - start - 1));
            }

            cur = pos + keyword.Length;
        }

        return strings;
    }
Let me know if you find any more problems.
 
nokola
Topic Author
Posts: 188
Joined: 10 Mar 2015, 05:29

Re: Buffer overflow in Unity when loading simple XAML

08 May 2017, 17:55

Thanks a lot - that works!
Edit: updated title to better help others. I appreciate the quick response.

Who is online

Users browsing this forum: No registered users and 2 guests