Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/FlatSharp/TypeModel/StructTypeModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,9 @@ public override void Validate()
this.inlineSize += length;
}

// FlatBuffers spec requires the size to be a multiple of the alignment (equivalent to flatc PadLastField).
this.inlineSize += SerializationHelpers.GetAlignmentError(this.inlineSize, this.maxAlignment);

foreach (StructMemberModel member in this.memberTypes)
{
ITypeModel memberModel = member.ItemTypeModel;
Expand Down
5 changes: 4 additions & 1 deletion src/FlatSharp/TypeModel/ValueStructTypeModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ public override CodeGeneratedMethod CreateSerializeMethodBody(SerializationCodeG
{
body = $@"
{slice}

{StrykerSuppressor.SuppressNextLine("boolean")}
if ({StrykerSuppressor.BitConverterTypeName}.IsLittleEndian)
{{
Expand Down Expand Up @@ -308,6 +308,9 @@ public override void Initialize()
this.inlineSize += propertyModel.PhysicalLayout[0].InlineSize;
}

// FlatBuffers spec requires the size to be a multiple of the alignment (equivalent to flatc PadLastField).
this.inlineSize += SerializationHelpers.GetAlignmentError(this.inlineSize, this.maxAlignment);

this.isExternal = this.ClrType.GetCustomAttribute<ExternalDefinitionAttribute>() is not null;
this.CanMarshalOnSerialize = false;
this.CanMarshalOnParse = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Nullable>annotations</Nullable>
<DocumentationFile>$(OutputPath)$(AssemblyName).xml</DocumentationFile>
<NoWarn>CS1591</NoWarn>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<RunAnalyzersDuringLiveAnalysis>False</RunAnalyzersDuringLiveAnalysis>
<EnableNETAnalyzers>True</EnableNETAnalyzers>
<AnalysisLevel>latest</AnalysisLevel>
Expand Down
34 changes: 22 additions & 12 deletions src/Tests/FlatSharpEndToEndTests/ValueStructs/ValueStructTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public void WriteThrough_ValueStruct_InTable()
[TestMethod]
public void Basics()
{
Assert.AreEqual(36, Unsafe.SizeOf<ValueStruct>());
Assert.AreEqual(40, Unsafe.SizeOf<ValueStruct>());
}

[TestMethod]
Expand Down Expand Up @@ -189,8 +189,13 @@ public void ValueStructs_UnityNative_WellAligned_Serialize(FlatBufferDeserializa
}
}

/// <summary>
/// PoorlyAligned's fields end at 5, but its size is padded up to 8 to match its alignment, so
/// elements can be laid out sequentially and the unsafe span path applies.
/// </summary>
[TestMethod]
public void ValueStructs_UnityNative_PoorlyAligned_Serialize()
[DynamicData(nameof(DynamicDataHelper.DeserializationModes), typeof(DynamicDataHelper))]
public void ValueStructs_UnityNative_PoorlyAligned_Serialize(FlatBufferDeserializationOption option)
{
int count = 10;

Expand All @@ -200,8 +205,15 @@ public void ValueStructs_UnityNative_PoorlyAligned_Serialize()
PoorlyAligned = new(Enumerable.Range(0, count).Select(x => new PoorlyAligned { X = x, Y = 1, }).ToArray(), default),
};

var ex = Assert.ThrowsException<InvalidOperationException>(() => source.AllocateAndSerialize());
Assert.AreEqual("Type 'FlatSharpEndToEndTests.ValueStructs.PoorlyAligned' does not support Unsafe Span operations because the size (5) is not a multiple of the alignment (4).", ex.Message);
byte[] data = source.AllocateAndSerialize();

var parsed = UnityVectors_List.Serializer.Parse(data, option);

for (int i = 0; i < count; ++i)
{
Assert.AreEqual(source.PoorlyAligned.Value[i].X, parsed.PoorlyAligned[i].X);
Assert.AreEqual(source.PoorlyAligned.Value[i].Y, parsed.PoorlyAligned[i].Y);
}
}

[TestMethod]
Expand Down Expand Up @@ -251,15 +263,13 @@ public void ValueStructs_UnityNative_PoorlyAligned_Parse(FlatBufferDeserializati
GCHandle handle = GCHandle.Alloc(data);
try
{
var ex = Assert.ThrowsException<InvalidOperationException>(() =>
{
var parsed = UnityVectors_Native.Serializer.Parse(new MemoryInputBuffer(data, true), option);
float f = parsed.PoorlyAligned.Value[0].X;
});
var parsed = UnityVectors_Native.Serializer.Parse(new MemoryInputBuffer(data, true), option);

Assert.AreEqual(
"Type 'FlatSharpEndToEndTests.ValueStructs.PoorlyAligned' does not support Unsafe Span operations because the size (5) is not a multiple of the alignment (4).",
ex.Message);
for (int i = 0; i < count; ++i)
{
Assert.AreEqual(source.PoorlyAligned[i].X, parsed.PoorlyAligned.Value[i].X);
Assert.AreEqual(source.PoorlyAligned[i].Y, parsed.PoorlyAligned.Value[i].Y);
}
}
finally
{
Expand Down
2 changes: 1 addition & 1 deletion src/Tests/Stryker/CodeGen/CodeGen.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<RootNamespace>FlatSharpStrykerTests</RootNamespace>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Nullable>annotations</Nullable>
<NoWarn>CS1591</NoWarn>
<NoWarn>$(NoWarn);CS1591</NoWarn>
</PropertyGroup>

<ItemGroup>
Expand Down
6 changes: 3 additions & 3 deletions src/Tests/Stryker/CodeGen/Schema.fbs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ enum Fruit : int
Pear
}

/// Poorly Aligned. Total Size = 10, Alignment = 4
/// Poorly Aligned. Fields end at 10, Total Size = 12, Alignment = 4
struct ValueStruct (fs_valueStruct)
{
/// Position 0, Length 4, Alignment 4
Expand All @@ -29,7 +29,7 @@ struct ValueStruct (fs_valueStruct)
c : [ short : 2 ] (fs_unsafeStructVector);
}

/// Poorly aligned. Total Size == 26, Alignemnt = 8
/// Poorly aligned. Fields end at 28, Total Size == 32, Alignemnt = 8
struct RefStruct
{
/// Position 0, Length 8, Alignment 8, WriteThrough = true
Expand All @@ -44,7 +44,7 @@ struct RefStruct
/// Position 14, length 2, Alignment 1, WriteThrough = false
d : [ byte : 2 ];

/// Position 16, Length 10, Alignment 4, WriteThrough = false
/// Position 16, Length 12, Alignment 4, WriteThrough = false
e : ValueStruct;
}

Expand Down
2 changes: 1 addition & 1 deletion src/Tests/Stryker/Tests/FullTreeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public void GetMaxSize()
Root root = this.CreateRoot();
int maxSize = Root.Serializer.GetMaxSize(root);

Assert.AreEqual(898, maxSize);
Assert.AreEqual(914, maxSize);
}

[TestMethod]
Expand Down
11 changes: 7 additions & 4 deletions src/Tests/Stryker/Tests/StructFieldTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,15 @@ public void ValueStructTableField(FlatBufferDeserializationOption option)
4, 0, // offset of field 0
0, 0, // padding

242, 255, 255, 255, // soffset to vtable
240, 255, 255, 255, // soffset to vtable
4, 0, 0, 0, // valuestruct.a
3, 0, // valuestruct.b, padding
1, 0, // valuestruct.c[0]
2, 0, // valuestruct.c[1]
0, 0, // valuestruct trailing padding

8, 0, // vtable length
14, 0, // table length
16, 0, // table length
0, 0, // field 0 (not present)
4, 0, // field 1
};
Expand Down Expand Up @@ -280,7 +281,7 @@ private static Root CreateRootReferenceStruct(out RefStruct rs, out ValueStruct
4, 0, // offset of field 0
0, 0, // padding

226, 255, 255, 255, // soffset to vtable
220, 255, 255, 255, // soffset to vtable

12, 0, 0, 0, // refStruct.A (ulong)
0, 0, 0, 0,
Expand All @@ -290,9 +291,11 @@ private static Root CreateRootReferenceStruct(out RefStruct rs, out ValueStruct
3, 0, // valuestruct.b, padding
1, 0, // valuestruct.c[0]
2, 0, // valuestruct.c[1]
0, 0, // valuestruct trailing padding
0, 0, 0, 0, // refStruct trailing padding

6, 0, // vtable length
30, 0, // table length
36, 0, // table length
4, 0, // field 0
};

Expand Down
2 changes: 1 addition & 1 deletion src/Tests/Stryker/Tests/StrykerTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<AssemblyName>FlatSharpStrykerTests</AssemblyName>
<RootNamespace>FlatSharpStrykerTests</RootNamespace>
<Nullable>annotations</Nullable>
<NoWarn>CS1591</NoWarn>
<NoWarn>$(NoWarn);CS1591</NoWarn>
</PropertyGroup>

<ItemGroup>
Expand Down
4 changes: 3 additions & 1 deletion src/Tests/Stryker/Tests/UnionFieldTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,8 @@ private Root CreateRoot_RefStructMember(out byte[] expectedData)
0, 0, // D[0,1]
0, 0, 0, 0, // ValueStruct (default)
0, 0, 0, 0,
0, 0
0, 0, 0, 0, // ValueStruct trailing padding
0, 0, 0, 0 // RefStruct trailing padding
};

return root;
Expand Down Expand Up @@ -396,6 +397,7 @@ private Root CreateRoot_ValueStructMember(out byte[] expectedData)
4, 0,
1, 0,
2, 0,
0, 0, // ValueStruct trailing padding
};

return root;
Expand Down
3 changes: 2 additions & 1 deletion src/Tests/Stryker/Tests/UnionVectorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ private Root CreateRoot(out byte[] expectedData)
16, 0, 0, 0,
40, 0, 0, 0,
52, 0, 0, 0,
76, 0, 0, 0,
80, 0, 0, 0,

244, 255, 255, 255, // key soffset to vtable
0, 0, 0, 0, // apple
Expand All @@ -306,6 +306,7 @@ private Root CreateRoot(out byte[] expectedData)
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,

1, 0, 0, 0, // string
B('c'), 0
Expand Down
Loading