Skip to content

FluidTemplate.TryParse and FluidTemplateExtensions.Render throw some unexpected exceptions #148

Closed
@Metalnem

Description

@Metalnem

FluidTemplate.TryParse and FluidTemplateExtensions.Render can throw bunch of unexpected exceptions. The ones I've found so far are:

  • ArgumentException
  • ArgumentOutOfRangeException
  • DivideByZeroException
  • NullReferenceException
  • OverflowException

To reproduce all of them, run the following program on .NET Core 2.2 with the latest Fluid beta (Fluid.Core 1.0.0-beta-9588):

using System;
using System.Collections.Generic;

namespace Fluid.Fuzz
{
	public class User
	{
		public string String { get; set; }
		public int Integer { get; set; }
		public List<double> Doubles { get; set; }
	}

	public class Program
	{
		public static void Main(string[] args)
		{
			var model = new User
			{
				String = "ABC",
				Integer = 123,
				Doubles = new List<double> { 1.1, 2.2, 3.3 }
			};

			var templates = new List<string>
			{
				"{{0|remove}}",
				"{{0|modulo}}",
				"{%endfor%}",
				"{%comment%}{%",
				"<p>{{false|divided_by|modulo|urlode}}<<"
			};

			foreach (var template in templates)
			{
				Run(model, template);
			}
		}

		private static void Run(User model, string template)
		{
			try
			{
				if (FluidTemplate.TryParse(template, out var result))
				{
					TemplateContext.GlobalMemberAccessStrategy.Register<User>();
					result.Render(new TemplateContext { Model = model });
				}
			}
			catch (Exception ex)
			{
				Console.WriteLine(ex);
			}
		}
	}
}

It should produce output similar to this:

System.ArgumentException: String cannot be of zero length.
Parameter name: oldValue
   at System.String.Replace(String oldValue, String newValue)
   at Fluid.Filters.StringFilters.Remove(FluidValue input, FilterArguments arguments, TemplateContext context)
   at Fluid.FilterCollection.<>c__DisplayClass1_0.<AddFilter>b__0(FluidValue input, FilterArguments arguments, TemplateContext context)
   at Fluid.Ast.FilterExpression.EvaluateAsync(TemplateContext context)
   at Fluid.Ast.OutputStatement.WriteToAsync(TextWriter writer, TextEncoder encoder, TemplateContext context)
   at Fluid.BaseFluidTemplate`1.RenderAsync(TextWriter writer, TextEncoder encoder, TemplateContext context)
   at Fluid.FluidTemplateExtensions.RenderAsync(IFluidTemplate template, TemplateContext context, TextEncoder encoder)
   at Fluid.FluidTemplateExtensions.Render(IFluidTemplate template, TemplateContext context)
   at Fluid.Fuzz.Program.Run(User model, String template) in /Users/Metalnem/Projects/sharpfuzz-samples/Fluid/Fluid.Fuzz/Program.cs:line 46
System.DivideByZeroException: Attempted to divide by zero.
   at Fluid.Filters.NumberFilters.Modulo(FluidValue input, FilterArguments arguments, TemplateContext context)
   at Fluid.FilterCollection.<>c__DisplayClass1_0.<AddFilter>b__0(FluidValue input, FilterArguments arguments, TemplateContext context)
   at Fluid.Ast.FilterExpression.EvaluateAsync(TemplateContext context)
   at Fluid.Ast.OutputStatement.WriteToAsync(TextWriter writer, TextEncoder encoder, TemplateContext context)
   at Fluid.BaseFluidTemplate`1.RenderAsync(TextWriter writer, TextEncoder encoder, TemplateContext context)
   at Fluid.FluidTemplateExtensions.RenderAsync(IFluidTemplate template, TemplateContext context, TextEncoder encoder)
   at Fluid.FluidTemplateExtensions.Render(IFluidTemplate template, TemplateContext context)
   at Fluid.Fuzz.Program.Run(User model, String template) in /Users/Metalnem/Projects/sharpfuzz-samples/Fluid/Fluid.Fuzz/Program.cs:line 46
System.NullReferenceException: Object reference not set to an instance of an object.
   at Fluid.DefaultFluidParser.BuildForStatement(BlockContext context)
   at Fluid.DefaultFluidParser.BuildTagStatement(ParseTreeNode node)
   at Fluid.DefaultFluidParser.TryParse(String template, Boolean stripEmptyLines, List`1& result, IEnumerable`1& errors)
   at Fluid.BaseFluidTemplate`1.TryParse(String template, Boolean stripEmptyLines, T& result, IEnumerable`1& errors)
   at Fluid.BaseFluidTemplate`1.TryParse(String template, T& result)
   at Fluid.Fuzz.Program.Run(User model, String template) in /Users/Metalnem/Projects/sharpfuzz-samples/Fluid/Fluid.Fuzz/Program.cs:line 43
System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
Parameter name: offset
   at Microsoft.Extensions.Primitives.ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument argument)
   at Microsoft.Extensions.Primitives.StringSegment.Subsegment(Int32 offset, Int32 length)
   at Fluid.DefaultFluidParser.ConsumeTag(StringSegment segment, Int32 start, String endTag, Int32& end)
   at Fluid.DefaultFluidParser.TryParse(String template, Boolean stripEmptyLines, List`1& result, IEnumerable`1& errors)
   at Fluid.BaseFluidTemplate`1.TryParse(String template, Boolean stripEmptyLines, T& result, IEnumerable`1& errors)
   at Fluid.BaseFluidTemplate`1.TryParse(String template, T& result)
   at Fluid.Fuzz.Program.Run(User model, String template) in /Users/Metalnem/Projects/sharpfuzz-samples/Fluid/Fluid.Fuzz/Program.cs:line 43
System.OverflowException: Value was either too large or too small for an Int32.
   at System.Convert.ToInt32(Double value)
   at Fluid.Filters.NumberFilters.Modulo(FluidValue input, FilterArguments arguments, TemplateContext context)
   at Fluid.FilterCollection.<>c__DisplayClass1_0.<AddFilter>b__0(FluidValue input, FilterArguments arguments, TemplateContext context)
   at Fluid.Ast.FilterExpression.EvaluateAsync(TemplateContext context)
   at Fluid.Ast.FilterExpression.EvaluateAsync(TemplateContext context)
   at Fluid.Ast.OutputStatement.WriteToAsync(TextWriter writer, TextEncoder encoder, TemplateContext context)
   at Fluid.BaseFluidTemplate`1.RenderAsync(TextWriter writer, TextEncoder encoder, TemplateContext context)
   at Fluid.FluidTemplateExtensions.RenderAsync(IFluidTemplate template, TemplateContext context, TextEncoder encoder)
   at Fluid.FluidTemplateExtensions.Render(IFluidTemplate template, TemplateContext context)
   at Fluid.Fuzz.Program.Run(User model, String template) in /Users/Metalnem/Projects/sharpfuzz-samples/Fluid/Fluid.Fuzz/Program.cs:line 46

You can find the fuzzing project I'm using here, and some basic Liquid dictionary file here.

The fuzzing project and the dictionary can be greatly improved (for example, by using more Fluid functions, making a more complicated model, or introducing more data types), but I'm leaving that to you if you are interested :)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions