Find the bugWhen you can't rely on your own identity
We had a need to generate unique ids for connections in our db. We used the following code:
public class NotificationsClientConnection : IDisposable { private static int _counter = 0; private readonly WebSocket _webSocket; private readonly DocumentDatabase _documentDatabase; private readonly DateTime _startedAt; public NotificationsClientConnection(WebSocket webSocket, DocumentDatabase documentDatabase) { _webSocket = webSocket; _documentDatabase = documentDatabase; _startedAt = SystemTime.UtcNow; } public int Id => Interlocked.Increment(ref _counter); public TimeSpan Age => SystemTime.UtcNow - _startedAt; }
Do you see the bug? It is a subtle one.
When you are ready, peek below.
.
.
.
.
.
.
.
.
.
.
.
.
.
The issue is in the following line:
public int Id => Interlocked.Increment(ref _counter);
The intent was to create a field that would be initialized on startup. Unfortunately, the usage of the lambda symbol "=>" instead of assignment "=" turned that into a computed property, which will return a new value on every call.
More posts in "Find the bug" series:
- (29 Feb 2016) When you can't rely on your own identity
- (05 Jan 2016) The case of the degrading system–Answer
- (04 Jan 2016) The case of the degrading system
- (11 Sep 2015) The concurrent memory buster
- (20 Apr 2011) Why do I get a Null Reference Exception?
- (25 Nov 2010) A broken tree
- (13 Aug 2010) RavenDB HiLo implementation
- (25 Jul 2010) Accidental code reviews
Comments
NotificationsClientConnection will also duplicate Ids per application domain, which may or may not be alright.
But you probably wanted this? :-) public int Id { get; } = Interlocked.Increment(ref _counter);
I do like the {get;} declaration, but the default assignment seems like a bad idea, and so does the lambda.
Doesn't seem that subtle to me, to be honest, especially compared to Age property where it is obvious that it is dynamic.
It's not that subtle, when you are searching for a bug. But it may be a very good example of a typo, which can be easily missed and lead to completely different semantics.
Comment preview