diff --git a/native-schema-registry/csharp/AWSGsrSerDe/AWSGsrSerDe.Tests/GlueSchemaRegistrySerDeTests.cs b/native-schema-registry/csharp/AWSGsrSerDe/AWSGsrSerDe.Tests/GlueSchemaRegistrySerDeTests.cs index fc016c2e..6744e8ee 100644 --- a/native-schema-registry/csharp/AWSGsrSerDe/AWSGsrSerDe.Tests/GlueSchemaRegistrySerDeTests.cs +++ b/native-schema-registry/csharp/AWSGsrSerDe/AWSGsrSerDe.Tests/GlueSchemaRegistrySerDeTests.cs @@ -191,6 +191,46 @@ public void Exceptions_Are_Thrown_By_DeSerializer() // } // } + /// + /// Test Serializer disposal when the object is uninitialized but finalizer still runs + /// This is not the exact usage scenario but simulates the case when unknown garbage collection race condition + /// causes the finalizer to run when the serializer object is null + /// + [Test] + public void SerializerConstructorDoubleFinalizerTest() + { + // Create uninitialized object to simulate failed constructor leaving _serializer null + var serializer = (GlueSchemaRegistrySerializer)System.Runtime.Serialization.FormatterServices + .GetUninitializedObject(typeof(GlueSchemaRegistrySerializer)); + + // Manually trigger finalizer on this uninitialized object + var finalize = typeof(GlueSchemaRegistrySerializer).GetMethod("Finalize", + System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + finalize?.Invoke(serializer, null); + + Assert.Pass("Disposal failure handled gracefully"); + } + + /// + /// Test Deserializer disposal when the object is uninitialized but finalizer still runs + /// This is not the exact usage scenario but simulates the case when unknown garbage collection race condition + /// causes the finalizer to run when the deserializer object is null + /// + [Test] + public void DeserializerConstructorDoubleFinalizerTest() + { + // Create uninitialized object to simulate failed constructor leaving _deserializer null + var deserializer = (GlueSchemaRegistryDeserializer)System.Runtime.Serialization.FormatterServices + .GetUninitializedObject(typeof(GlueSchemaRegistryDeserializer)); + + // Manually trigger finalizer on this uninitialized object + var finalize = typeof(GlueSchemaRegistryDeserializer).GetMethod("Finalize", + System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + finalize?.Invoke(deserializer, null); + + Assert.Pass("Disposal failure handled gracefully"); + } + private static GenericRecord GetTestAvroRecord() { var recordSchema = Schema.Parse(TestAvroSchema); diff --git a/native-schema-registry/csharp/AWSGsrSerDe/AWSGsrSerDe/GlueSchemaRegistryDeserializer.cs b/native-schema-registry/csharp/AWSGsrSerDe/AWSGsrSerDe/GlueSchemaRegistryDeserializer.cs index 4f15f31a..55a44d20 100644 --- a/native-schema-registry/csharp/AWSGsrSerDe/AWSGsrSerDe/GlueSchemaRegistryDeserializer.cs +++ b/native-schema-registry/csharp/AWSGsrSerDe/AWSGsrSerDe/GlueSchemaRegistryDeserializer.cs @@ -144,7 +144,7 @@ private static void Validate(byte[] encoded) private void ReleaseUnmanagedResources() { - _deserializer.Dispose(); + _deserializer?.Dispose(); } private void Dispose(bool disposing) diff --git a/native-schema-registry/csharp/AWSGsrSerDe/AWSGsrSerDe/GlueSchemaRegistrySerializer.cs b/native-schema-registry/csharp/AWSGsrSerDe/AWSGsrSerDe/GlueSchemaRegistrySerializer.cs index 934ba56b..f794c6fc 100644 --- a/native-schema-registry/csharp/AWSGsrSerDe/AWSGsrSerDe/GlueSchemaRegistrySerializer.cs +++ b/native-schema-registry/csharp/AWSGsrSerDe/AWSGsrSerDe/GlueSchemaRegistrySerializer.cs @@ -114,7 +114,7 @@ private static void Validate(GlueSchemaRegistrySchema schema, byte[] bytes) private void ReleaseUnmanagedResources() { - _serializer.Dispose(); + _serializer?.Dispose(); } private void Dispose(bool disposing)