Closed
Description
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
Labels
No labels