{"record":{"id":"e96d2b23ee515ad1","repo":"dotnet/reactive","slug":"refcountdisposable-can-t-handle-more-than-2147483647","errorCode":null,"errorMessage":"RefCountDisposable can't handle more than 2147483647 disposables","messagePattern":"RefCountDisposable can't handle more than 2147483647 disposables","errorType":"exception","errorClass":"OverflowException","httpStatus":null,"severity":"error","filePath":"Rx.NET/Source/src/System.Reactive/Disposables/RefCountDisposable.cs","lineNumber":78,"sourceCode":"            var cnt = Volatile.Read(ref _count);\n\n            for (; ; )\n            {\n                // If bit 31 is set and the active count is zero, don't create an inner\n                if (cnt == int.MinValue)\n                {\n                    if (_throwWhenDisposed)\n                    {\n                        throw new ObjectDisposedException(\"RefCountDisposable\");\n                    }\n\n                    return Disposable.Empty;\n                }\n\n                // Should not overflow the bits 0..30\n                if ((cnt & 0x7FFFFFFF) == int.MaxValue)\n                {\n                    throw new OverflowException($\"RefCountDisposable can't handle more than {int.MaxValue} disposables\");\n                }\n\n                // Increment the active count by one, works because the increment\n                // won't affect bit 31\n                var u = Interlocked.CompareExchange(ref _count, cnt + 1, cnt);\n                if (u == cnt)\n                {\n                    return new InnerDisposable(this);\n                }\n                cnt = u;\n            }\n        }\n\n        /// <summary>\n        /// Disposes the underlying disposable only when all dependent disposables have been disposed.\n        /// </summary>\n        public void Dispose()\n        {","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/Rx.NET/Source/src/System.Reactive/Disposables/RefCountDisposable.cs#L60-L96","documentation":"RefCountDisposable packs an active-child counter into bits 0..30 of an int (bit 31 is the disposed flag), so it can hand out at most int.MaxValue inner disposables. GetDisposable throws OverflowException when 2147483647 inner disposables are already outstanding.","triggerScenarios":"Calling GetDisposable() 2,147,483,648 times on a single RefCountDisposable without any of the returned inner disposables being disposed — usually only via a stress/leak loop.","commonSituations":"Unbounded subscription/lease creation in a hot loop where inner disposables are never disposed, effectively a leak that exhausts the 31-bit counter; extremely rare outside synthetic benchmarks.","solutions":["Dispose inner disposables returned by GetDisposable as soon as they are no longer needed.","Track outstanding leases with a bounded cap or semaphore to prevent runaway acquisition.","If legitimately unbounded, replace with a custom counting scheme using a long counter or SplitDispose-free design."],"exampleFix":"// before\nwhile (running) leases.Add(refCount.GetDisposable()); // never released\n// after\nwhile (running)\n{\n    var d = refCount.GetDisposable();\n    try { /* work */ }\n    finally { d.Dispose(); }\n}","handlingStrategy":"validation","validationCode":"// Cap outstanding leases\nif (Interlocked.Increment(ref outstanding) > MaxLeases)\n    throw new InvalidOperationException(\"Too many outstanding inner disposables\");\nvar d = refCount.GetDisposable();","typeGuard":null,"tryCatchPattern":"try { var d = refCount.GetDisposable(); }\ncatch (OverflowException) { /* back off, force disposal of outstanding leases */ }","preventionTips":["Always dispose inner disposables promptly (using/finally).","Bound the number of concurrent leases with a semaphore or counter.","Monitor outstanding-lease counts in production to detect leaks before overflow."],"tags":["overflow","resource-leak","disposables","system-reactive"],"backgroundTag":"value-out-of-range","analyzedSha":"94b5d5ab912789f5abe9a72138a25bbd716fe59c","analyzedAt":"2026-09-15T02:26:24.759Z","contentChangedAt":"2026-09-15T02:26:24.759Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}