Skip to content

Commit

Permalink
FIx SonarSec #155 - handle array creation
Browse files Browse the repository at this point in the history
  • Loading branch information
duncanp-sonar committed Jul 10, 2018
1 parent 6870fa8 commit 041f5cd
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ public static bool IsMethodId(UcfgIdentifier identifier) =>
public static UcfgIdentifier CreateTypeId(INamedTypeSymbol typeSymbol) =>
Create(typeSymbol.ConstructedFrom.ToDisplayString());

public static UcfgIdentifier CreateArrayTypeId(IArrayTypeSymbol arrayTypeSymbol) =>
Create(arrayTypeSymbol.ToDisplayString());

private static UcfgIdentifier Create(string id) =>
id == null ? Unknown : new UcfgIdentifier(id);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ public IEnumerable<Instruction> Create(SyntaxNode syntaxNode)
case ObjectCreationExpressionSyntax objectCreation:
return ProcessObjectCreationExpression(objectCreation);

case ArrayCreationExpressionSyntax arrayCreation:
return ProcessArrayCreationExpression(arrayCreation);

case IdentifierNameSyntax identifierName:
return ProcessIdentifierName(identifierName);

Expand Down Expand Up @@ -141,6 +144,23 @@ private IEnumerable<Instruction> ProcessObjectCreationExpression(ObjectCreationE
new[] { expressionService.GetExpression(objectCreationExpression) }.Concat(arguments).ToArray()));
}

private IEnumerable<Instruction> ProcessArrayCreationExpression(ArrayCreationExpressionSyntax arrayCreationExpression)
{
var arrayTypeSymbol = semanticModel.GetTypeInfo(arrayCreationExpression).Type as IArrayTypeSymbol;
if (arrayTypeSymbol == null)
{
return NoInstructions;
}

// A call that constructs an array should look like:
// Code: var x = new string[42];
// %0 := new string[] // <-- created by this method
// x = __id [ %0 ] // <-- created by the method that handles the assignment

return CreateNewArray(arrayCreationExpression, arrayTypeSymbol,
expressionService.CreateVariable(arrayTypeSymbol));
}

private IEnumerable<Instruction> ProcessGenericName(GenericNameSyntax genericName)
{
var namedTypeSymbol = GetSymbol(genericName) as INamedTypeSymbol;
Expand Down Expand Up @@ -433,6 +453,24 @@ private IEnumerable<Instruction> CreateNewObject(ObjectCreationExpressionSyntax
return new[] { instruction };
}

private IEnumerable<Instruction> CreateNewArray(ArrayCreationExpressionSyntax syntaxNode,
IArrayTypeSymbol arrayTypeSymbol, UcfgExpression callTarget)
{
expressionService.Associate(syntaxNode, callTarget);

var instruction = new Instruction
{
NewObject = new NewObject
{
Location = syntaxNode.GetUcfgLocation(),
Type = UcfgIdentifier.CreateArrayTypeId(arrayTypeSymbol).ToString()
}
};
callTarget.ApplyAsTarget(instruction);

return new[] { instruction };
}

private ISymbol GetSymbol(SyntaxNode syntaxNode) =>
semanticModel.GetSymbolInfo(syntaxNode).Symbol;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@ public static void VerifyInstructions(string codeSnippet, string methodName, boo
.Select(UcfgTestHelper.ToTestString)
.ToList();

// Dump the results to output to make it easier to visually check the results.
// To see the text, select the test in the Test Explorer and click the "Output"
// button in the result window.
System.Console.WriteLine($"Expected:\r\n{string.Join(System.Environment.NewLine, expectedInstructions)}\r\n");
System.Console.WriteLine($"Actual:\r\n{string.Join(System.Environment.NewLine, actualInstructions)}");

actualInstructions.Should().Equal(expectedInstructions);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ public string Bar(string s, Func<string, string> a)
}

[TestMethod]
public void Assignments_Static_Poperty_On_Generic_Class()
public void Assignments_Static_Property_On_Generic_Class()
{
const string code = @"
namespace Namespace
Expand Down Expand Up @@ -669,6 +669,58 @@ public void Foo()
// %8 := Namespace.Class1.Property.set [ %5 %6 ]
}
}
}";
UcfgVerifier.VerifyInstructions(code, "Foo");
}

[TestMethod]
public void ArrayCreation_WithNew()
{
const string code = @"
namespace Namespace
{
public class Class1
{
public void Foo()
{
// Primitive type
var x0 = new string[42]; // %0 := new string[]
// x0 := __id [ %0 ]
// Array of objects
var x1 = new Class1[0]; // %1 := new Namespace.Class1[]
// x1 := __id [ %1 ]
// Multi-rank arrays
var x2 = new int[10,2]; // %2 := new int[*,*]
// x2 := __id [ %2 ]
// Arrau with initializer (initializer is ignored)
var x3 = new string[] { ""aaa"", ""bbb"", ""ccc"" }; // %3 := new string[]
// x3 := __id [ %3 ]
}
}
}";

var x3 = new string[] { "aaa", "bbb", "ccc" };

UcfgVerifier.VerifyInstructions(code, "Foo");
}

[TestMethod] [Ignore] // TODO: this method currently throws a null-ref
public void ArrayCreation_WithCreateInstance()
{
const string code = @"
namespace Namespace
{
public class Class1
{
public void Foo()
{
var a = System.Array.CreateInstance(typeof(string), 10); // %0 = System.Array.CreateInstance(System.Type, int) [ System.Array.CreateInstance ]
// %1 := __id [ %0 ]
}
}
}";
UcfgVerifier.VerifyInstructions(code, "Foo");
}
Expand Down

0 comments on commit 041f5cd

Please sign in to comment.