8

In a naive reference-counting smart pointer implementation, the reference-counter could overflow. How is this overflow avoided or handled in C++ standard library implementations?

curiousguy
  • 8,038
  • 2
  • 40
  • 58
sergej
  • 17,147
  • 6
  • 52
  • 89
  • 8
    I'm not sure you could overflow the reference count. If they used `size_t` then they should not be able to allocate enough pointers to overflow that. – NathanOliver May 22 '17 at 14:43
  • 4
    `std::shared_ptr`'s function to return the reference counter [returns a `long`](http://en.cppreference.com/w/cpp/memory/shared_ptr/use_count), so I guess that is the "soft" limit. – Rakete1111 May 22 '17 at 14:45
  • 2
    You could always read the code. – Donnie May 22 '17 at 14:48
  • 8
    That's a real concern. If you generate a new reference every nanosecond, you would overflow a 64-bit count in less than 600 years. – stark May 22 '17 at 14:51
  • 4
    @stark and your pointers would consume more memory than can be addressed by a 64 bit pointer :) – eerorika May 22 '17 at 14:52
  • If you could overflow it, it would be undefined behavior on account of signed overflow. It's handled by assuming there won't be more than `std::numeric_limits::max` references (at least that's what libstdc++ does). – AndyG May 22 '17 at 14:55
  • 4
    @stark [`long` is not 64-bit on all platforms](https://software.intel.com/en-us/articles/size-of-long-integer-type-on-different-architecture-and-os), even if you compile for 64-bit. – zett42 May 22 '17 at 14:58
  • @stark: Also "less than 300 years" is a tighter bound [source](https://wandbox.org/permlink/vd2LZv96mR69uT1f). Edit: You must have assumed unsigned, which is a false assumption. – AndyG May 22 '17 at 15:03
  • 6
    If your program overflows a reference counter, you probably deserve it. – n. m. could be an AI May 22 '17 at 15:19
  • related: a WG issue [directly referenced implementing shared_ptr using reflinking](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2434) when changing the wording for use_count. I'm unsure that the resolved issue implies that it is still valid to implement it as such. Theoretically, such an implementation wouldn't overflow. – Rusty Shackleford May 23 '17 at 01:14
  • 1
    @Donnie "_You could always read the code_" You can always assume the original poster wants an answer that is not tied a particular version of a particular compiler. – curiousguy Jun 01 '17 at 16:52
  • @curiousguy - Well, if it's not in the standard (it's not), then the only answer is one that is tied to a particular compiler or implementation. I may have came across as snitty, but it seems a lot of people don't realize that the standard library is at hand and readable. – Donnie Jun 02 '17 at 22:13

1 Answers1

6

Snippets from stdlibc++ headers:

typedef int _Atomic_word;

class _Sp_counted_base
    /*snip*/
    _Atomic_word  _M_use_count;
    /*snip*/
    _M_weak_add_ref()
    { __gnu_cxx::__atomic_add_dispatch(&_M_weak_count, 1); }

/*snip*/
__atomic_add_dispatch(/*snip*/)
{
    /*snip*/
    __atomic_add_single(/*snip*/);
    /*snip*/
}

__atomic_add_single(/*snip*/)
{ *__mem += __val; }

Conclusion: This particular implementation "handles" reference-counter overflow by ignoring the possibility.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • It is surprising that they use an `int` but I is hard, for me at least, to envision a use case for 32767 pointers to the same thing. – NathanOliver May 22 '17 at 15:12
  • 2
    In general yes, but what if an attacker manages to produce some malicious input that causes the program to create them? – Bob Jansen May 22 '17 at 15:24
  • 6
    @BobJansen that could be bad. Another conclusion: You should not let user input directly affect the number of shared pointers without a bound. In fact, I would extend this to anything that allocates memory (or other resources). – eerorika May 22 '17 at 15:29
  • 2
    I just had a look at the MSVC++2017 implementation of `std::shared_ptr`. They call [`_InterlockedIncrement()`](https://learn.microsoft.com/en-us/cpp/intrinsics/interlockedincrement-intrinsic-functions) which overflows aswell. – zett42 May 22 '17 at 19:02