Skip to content

Segfault when binding array parameter via Dapper ICustomQueryParameter #6434

@elsand

Description

@elsand

Full repro

See https://github.com/elsand/npgsql-dapper-segfault/. The relevant code can also be found below.

Summary

A simple Dapper + Npgsql program crashes the process when binding an array parameter via ICustomQueryParameter and running SELECT unnest(@Ids). This happens on macOS (SIGSEGV, exit 139) and Windows (Fatal error. Internal CLR error 0x80131506). The repro targets net9.0 and net10.0 and uses Npgsql 10.0.1 + Dapper 2.1.66.

Crash seems to occur during Dapper parameter setup (before query execution) when NpgsqlParameter is created for an array via ICustomQueryParameter.

Not sure if this belongs here, or in https://github.com/dotnet/runtime, please advice. Assuming it's not Dapper, since that's only managed code (without unsafe/native interop).

Steps

  1. git clone https://github.com/elsand/npgsql-dapper-segfault/
  2. set PG_CONNECTION_STRING to a PostgreSQL instance
  3. dotnet run -f net10.0 (or -f net9.0)

Expected

Query returns the unnest’ed values.

Actual

Process crashes. On macOS it’s a SIGSEGV (exit 139). On Windows, it reports “Fatal error. Internal CLR error. (0x80131506)”.

Running on Mac gives no console output, unless minidumps are enabled:

DOTNET_DbgEnableMiniDump=1 \
DOTNET_DbgMiniDumpType=3 \
DOTNET_DbgMiniDumpName=/tmp/npgsql_segfault_%p.dmp \
PG_CONNECTION_STRING='Host=localhost;Database=postgres;Username=postgres;Password=xxxxxx' \
dotnet run -f net10.0

[createdump] Gathering state for process 51920 
[createdump] Crashing thread 131147a signal 11 (000b)

[createdump] Writing triage minidump to file /tmp/npgsql_segfault_51920.dmp
[createdump] Written 38621464 bytes (2357 pages) to core file
[createdump] Target process is alive
[createdump] Dump successfully written in 197ms

Minidump can be provided upon request.

Running on Windows gives substantially more output:

PS C:\Users\bjorn\Repos\npgsql-dapper-segfault> dotnet run -f net10.0
Fatal error.
Internal CLR error. (0x80131506)
   at Dapper.CommandDefinition.SetupCommand(System.Data.IDbConnection, System.Action`2<System.Data.IDbCommand,System.Object>)
   at Dapper.SqlMapper.TrySetupAsyncCommand(Dapper.CommandDefinition, System.Data.IDbConnection, System.Action`2<System.Data.IDbCommand,System.Object>)
   at Dapper.SqlMapper+<QueryAsync>d__33`1[[System.__Canon, System.Private.CoreLib, Version=10.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].MoveNext()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[[Dapper.SqlMapper+<QueryAsync>d__33`1[[System.__Canon, System.Private.CoreLib, Version=10.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], Dapper, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null]](<QueryAsync>d__33`1<System.__Canon> ByRef)
   at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1[[System.__Canon, System.Private.CoreLib, Version=10.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].Start[[Dapper.SqlMapper+<QueryAsync>d__33`1[[System.__Canon, System.Private.CoreLib, Version=10.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], Dapper, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null]](<QueryAsync>d__33`1<System.__Canon> ByRef)
   at Dapper.SqlMapper.QueryAsync[[System.__Canon, System.Private.CoreLib, Version=10.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]](System.Data.IDbConnection, System.Type, Dapper.CommandDefinition)
   at Dapper.SqlMapper.QueryAsync[[System.__Canon, System.Private.CoreLib, Version=10.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]](System.Data.IDbConnection, Dapper.CommandDefinition)
   at Program+<<Main>$>d__0.MoveNext()
   at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
   at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+AsyncStateMachineBox`1[[System.Threading.Tasks.VoidTaskResult, System.Private.CoreLib, Version=10.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.__Canon, System.Private.CoreLib, Version=10.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].MoveNext(System.Threading.Thread)
   at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(System.Runtime.CompilerServices.IAsyncStateMachineBox, Boolean)
   at System.Threading.Tasks.Task.RunContinuations(System.Object)
   at System.Threading.Tasks.Task`1[[System.Threading.Tasks.VoidTaskResult, System.Private.CoreLib, Version=10.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].TrySetResult(System.Threading.Tasks.VoidTaskResult)
   at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1[[System.Threading.Tasks.VoidTaskResult, System.Private.CoreLib, Version=10.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].SetExistingTaskResult(System.Threading.Tasks.Task`1<System.Threading.Tasks.VoidTaskResult>, System.Threading.Tasks.VoidTaskResult)
   at Npgsql.NpgsqlConnection+<<Open>g__OpenAsync|42_0>d.MoveNext()
(rest of output omitted)

Full output of Windows run

Environment

  • Hardware: Apple M3 Pro / AMD Ryzen 7 3700X
  • OS: macOS 26.2 (Build 25C56) / Windows 11 Pro (Build 26200.7623)
  • PostgreSQL: 16.10
  • SDKs tested: .NET 9.0.310, .NET 10.0.102
  • Packages: Npgsql 10.0.1, Dapper 2.1.66

Relevant code

using System.Data;
using Dapper;
using Npgsql;

await using var connection = new NpgsqlConnection(Environment.GetEnvironmentVariable("PG_CONNECTION_STRING")
    ?? "Host=localhost;Database=postgres;Username=postgres;Password=postgres");

await connection.OpenAsync();

var parameters = new
{
    Ids = new PostgresArray<string>(["a"]) // Also tested with `int` and `Guid` type parameters - same result
};

var command = new CommandDefinition("SELECT unnest(@Ids) AS Value", parameters, cancellationToken: CancellationToken.None);
var rows = await connection.QueryAsync<string>(command); // <--- Segfault happens here

foreach (var value in rows) // <--- This line is never reached
{
    Console.WriteLine(value);
}

internal readonly struct PostgresArray<T>(T[] value) : SqlMapper.ICustomQueryParameter
{
    public void AddParameter(IDbCommand command, string name)
    {
        var param = new NpgsqlParameter(name, value);
        command.Parameters.Add(param);
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions