Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
e4ba0e3
Bound decoder work to prevent a pointer fan-out denial of service
oschwald Aug 25, 2026
061a3cb
Bound decoder payload to prevent an amplification denial of service
oschwald Sep 5, 2026
790cfa0
Report out-of-bounds data-section reads as a database error
oschwald Sep 4, 2026
38d5e23
Bound netstandard2.0 buffer reads to the database length
oschwald Sep 4, 2026
975dab6
Charge followed pointers once and test resource-limit boundaries
oschwald Sep 4, 2026
6746edd
Test payload limits through memory loading and enumeration
oschwald Sep 4, 2026
fa6b4c2
Test that decode limits reject oversized headers before reading
oschwald Sep 4, 2026
ac0cc6d
Test pointer-chain depth and integer payload charging
oschwald Sep 4, 2026
8ed36d6
Clarify pointer-target payload accounting
oschwald Sep 4, 2026
1beee94
Correct the depth boundary and test inherited pointer depth
oschwald Sep 4, 2026
403ecb3
Test container-depth and integer-payload boundaries
oschwald Sep 4, 2026
0ac19c9
Test that repeated and concurrent lookups get separate budgets
oschwald Sep 4, 2026
03f176d
Test 512-container decoding with different stack sizes
oschwald Sep 4, 2026
1d76141
Test repeated follows of a shared pointer chain
oschwald Sep 4, 2026
ad847f9
Document why CheckContainer's subtraction cannot overflow
oschwald Sep 4, 2026
ff76604
Build the decoder's type-mismatch message out of line
oschwald Sep 4, 2026
b479813
Forward command-line options to benchmarks
oschwald Sep 8, 2026
036bbaf
Separate scalar decode dispatch
oschwald Sep 8, 2026
48be56d
Follow map-key pointers without recursive calls
oschwald Sep 8, 2026
0c39ae5
Avoid boxed capacities in reflection collection factories
oschwald Sep 8, 2026
9f6bec8
Reject oversized uint32, uint64, and uint128 encodings
oschwald Sep 8, 2026
bb8ee93
Decode pointer control bits before expanding value sizes
oschwald Sep 8, 2026
a4691cc
Format release notes
oschwald Sep 10, 2026
7e897d2
Reject pointers to pointers during decoding
oschwald Sep 10, 2026
53fbfa3
Test buffer bounds through each read path and Reader
oschwald Sep 10, 2026
55d1b76
Test lookup recovery and map value boundaries
oschwald Sep 10, 2026
78d70ee
Verify dictionary factories preserve requested capacity
oschwald Sep 10, 2026
d069622
Clarify decoder limits and testing guidance
oschwald Sep 10, 2026
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
8 changes: 4 additions & 4 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@ dotnet build MaxMind.Db.sln

```bash
# Run all tests
dotnet test MaxMind.Db.Test/MaxMind.Db.Test.csproj
dotnet test --project MaxMind.Db.Test/MaxMind.Db.Test.csproj

# Run specific test class
dotnet test --filter "FullyQualifiedName~ReaderTest"
dotnet test --filter "FullyQualifiedName~DecoderTest"
dotnet test --project MaxMind.Db.Test/MaxMind.Db.Test.csproj -- --filter-class "*ReaderTest"
dotnet test --project MaxMind.Db.Test/MaxMind.Db.Test.csproj -- --filter-class "*DecoderTest"

# Run specific test method
dotnet test --filter "FullyQualifiedName~ReaderTest.TestMany"
dotnet test --project MaxMind.Db.Test/MaxMind.Db.Test.csproj -- --filter-method "*ReaderTest.TestPointerHeavyValueCountDecodes"
```

### Running Benchmarks
Expand Down
2 changes: 1 addition & 1 deletion MaxMind.Db.Benchmark/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
using System.Linq;
using System.Net;

BenchmarkRunner.Run<CityBenchmark>();
BenchmarkRunner.Run<CityBenchmark>(args: args);

[MemoryDiagnoser]
public class CityBenchmark
Expand Down
68 changes: 68 additions & 0 deletions MaxMind.Db.Test/CollectionActivatorTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using System.Collections.Generic;
using Xunit;

namespace MaxMind.Db.Test
{
public static class CollectionActivatorTest
{
[Fact]
public static void ListFactoryUsesRequestedCapacity()
{
var factory = new ListActivatorCreator().GetActivator(typeof(ICollection<long>));
var list = Assert.IsType<List<long>>(factory(123));
Assert.Empty(list);
Assert.Equal(123, list.Capacity);
}

[Fact]
public static void ListFactoryPreservesCustomDefaultConstructor()
{
var factory = new ListActivatorCreator().GetActivator(typeof(DefaultList<long>));
var list = Assert.IsType<DefaultList<long>>(factory(123));
Assert.True(list.WasConstructed);
Assert.Equal(0, list.Capacity);
}

[Fact]
public static void DictionaryFactoryCreatesRequestedInterface()
{
var factory = new DictionaryActivatorCreator().GetActivator(typeof(IDictionary<string, long>));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This reaches the dictionary capacity branch of CreateCapacityActivator but only asserts Empty plus an add/read round-trip, so a regression selecting Dictionary's parameterless constructor would pass. The list equivalent above does assert capacity.

EnsureCapacity(0) returns 131 for the current factory and 0 for a parameterless one, so Assert.True(dictionary.EnsureCapacity(0) >= 123) closes it on every test TFM.

馃 Comment by Claude (Claude Code) on behalf of Will.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added EnsureCapacity(0) >= 123 in 78d70ee on .NET 8 and later. net481 does not expose that API, so it keeps the existing empty and add/read checks.

Codex, responding on Greg鈥檚 behalf.

var dictionary = Assert.IsType<Dictionary<string, long>>(factory(123));
Assert.Empty(dictionary);
#if NET8_0_OR_GREATER
Assert.True(dictionary.EnsureCapacity(0) >= 123);
#endif
dictionary.Add("value", 7);
Assert.Equal(7, dictionary["value"]);
}

[Fact]
public static void DictionaryFactoryPreservesCustomDefaultConstructor()
{
var factory = new DictionaryActivatorCreator().GetActivator(typeof(DefaultDictionary<string, long>));
var dictionary = Assert.IsType<DefaultDictionary<string, long>>(factory(123));
Assert.True(dictionary.WasConstructed);
Assert.Empty(dictionary);
}

private sealed class DefaultList<T> : List<T>
{
public DefaultList()
{
WasConstructed = true;
}

public bool WasConstructed { get; }
}

private sealed class DefaultDictionary<TKey, TValue> : Dictionary<TKey, TValue> where TKey : notnull
{
public DefaultDictionary()
{
WasConstructed = true;
}

public bool WasConstructed { get; }
}
}
}
Loading
Loading