[CSHARP-4853] "Thread static buffer is already in use." error after bad utf8 string write. Created: 21/Nov/23  Updated: 04/Dec/23  Resolved: 29/Nov/23

Status: Closed
Project: C# Driver
Component/s: None
Affects Version/s: None
Fix Version/s: 2.23.0

Type: Bug Priority: Unknown
Reporter: Andrea Balducci Assignee: Adelin Mbida Owona
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Attachments: PNG File image-2023-11-21-16-00-07-204.png     PNG File image-2023-11-21-17-44-10-396.png    
Issue Links:
Duplicate
is duplicated by CSHARP-4855 Writing invalid UTF8 string (without ... Closed
Documentation Changes: Not Needed
Documentation Changes Summary:

1. What would you like to communicate to the user about this feature?
2. Would you like the user to see examples of the syntax and/or executable code and its output?
3. Which versions of the driver/connector does this apply to?


 Description   

Summary

After an error with invalid unicode strings the thread is unable to perform operations on MongoDB.

Please provide the version of the driver. If applicable, please provide the MongoDB server version and topology (standalone, replica set, or sharded cluster).

MongoDB C# 2.10

How to Reproduce

Will PR on github.

  [Fact]
  public void GetBytesUsingThreadStaticBuffer_should_leave_the_thread_operational()
 

{       var invalidUtf8String = "🔥".Substring(0, 1);       var exception = Record.Exception(() => EncodingHelper.GetBytesUsingThreadStaticBuffer(Utf8Encodings.Strict, invalidUtf8String));       var e = exception.Should().BeOfType<EncoderFallbackException>().Subject;       using var segment = EncodingHelper.GetBytesUsingThreadStaticBuffer(Utf8Encodings.Strict, "Thread static buffer should not be in use");       segment.Segment.Array.Length.Should().Be(256);   }

Additional Background

  1. Call to rent buffer with invalid utf8 string
  2. encoding.GetBytes throws (using strict encoder)
  3. disposable is not created, thread static attributes holing buffer
  4. every subsequent call in this thread throws



 Comments   
Comment by Githook User [ 29/Nov/23 ]

Author:

{'name': 'Adelin Owona', 'email': '51498470+adelinowona@users.noreply.github.com', 'username': 'adelinowona'}

Message: CSHARP-4853: "Thread static buffer is already in use." error after bad utf8 string write. (#1219)
Branch: master
https://github.com/mongodb/mongo-csharp-driver/commit/225ac8b7dc9042268f37e061990a26d9c3285b11

Comment by Gian Maria Ricci [ 21/Nov/23 ]

Actually the version where we have found the bug is the 2.21.0, but we are able to reproduce the very same behaviour on the latest version. The problem arise because we saved in a string property of an object an invalid unicode sequence, because .NET substring operator does not takes into account surrogate characters. 

The problem is the ThreadStaticBuffer class, it is really a danger, because if some code ask for RentBuffer and does not dispose the returned object, the entire thread is corrupted. This forces to completely restart the process. We luckly got this in a demo server and not in a customer production server, but the logic is really too dangerous to be left in production.

What this pieces of code does is, you got a RentedBuffer, if you forget to dispose, every query that pass in this thread will be doomed to fail. This problem was already signaled by https://jira.mongodb.org/browse/CSHARP-4159

In my opinion the RentBuffer function must be changed, because diagnosing such error in a live server is a living hell, because you start having random failure in your access to the database. 

In my opinion if the __isBufferRented variable is true, it means that some code in this thread did not disposed the RentedBuffer, it is enough to log an error, and to cleanup __isBufferRented and put the __buffer to null so the routine will create a new buffer.

Also the class has this comment

    /// <summary>
    /// Represents a class that provides reusable buffer per thread.
    /// Use this technique ONLY when:
    ///     1. Buffer is not shared across multiple threads.
    ///     2. No nested methods invocations use the same buffer.
    /// Advised to limit the usage scope to a single method.
    /// </summary>

 

While the code in GetBytesUsingThreadStaticBuffer completely violates rule 1, it ask for the buffer, it DOES NOT WRAP in using and then pass inside another IDisposable, letting some code to be execute completely violating the contract, where any error will render the whole process unusable. A complete disaster in production environment.

Gian Maria.

 

 

Comment by Andrea Balducci [ 21/Nov/23 ]

PR https://github.com/mongodb/mongo-csharp-driver/pull/1217

Comment by PM Bot [ 21/Nov/23 ]

Hi mtb.snowboard@gmail.com, thank you for reporting this issue! The team will look into it and get back to you soon.

Generated at Wed Feb 07 21:49:34 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.