3

I'm using N3797 working draft.

Section 5.7/1 says:

[...] For addition, either both operands shall have arithmetic or unscoped enumeration type, or one operand shall be a pointer to a completely-defined object type and the other shall have integral or unscoped enumeration type.

Ok. But consider the rule from the section 3.7.4.3/3:

— the result of an additive or bitwise operation, one of whose operands is an integer representation of a safely-derived pointer value P, if that result converted by reinterpret_cast<void*> would compare equal to a safely-derived pointer computable from reinterpret_cast<void*>(P).

That is, we cannot apply pointer arithmetic to a pointer to void. Could you possibly provide an example reflecting the rule from 3.7.4.3?

The similiar question doesn't provide a suitable example, because the pointer to void arithmetic appers here.

Community
  • 1
  • 1
  • What do you mean with "provide an example reflecting the rule"? You want a code example that follows the rule? – Ferdinand Beyer Aug 09 '14 at 08:13
  • @FerdinandBeyer Yes, I do. I would look at an additive operation, correspoding that rule. –  Aug 09 '14 at 08:14
  • @FerdinandBeyer The rule looks a bit unclear for me... –  Aug 09 '14 at 08:15
  • 2
    @perreal The example provided in the topic that you cited is **not standartized**. Standard precludes pointer arithmetic with a pointer to void. –  Aug 09 '14 at 08:20
  • @perreal Please, read my post more attentively. I've cited a corresponding reference :). –  Aug 09 '14 at 08:22
  • this might be relevant: http://stackoverflow.com/q/25174236/390913 – perreal Aug 09 '14 at 08:23
  • @perreal No, it doesn't. It's because a pointer to void arithmetic, as I've already said :). –  Aug 09 '14 at 08:27
  • 2
    To be honest, this particular section of the standard is probably among the least useful, since no currently available compiler that I know of actually implements strict pointer safety. I wouldn't be surprised if the wording has issues, since no implementer is actually forced to grapple with the wording of that section. Possibly the word "computable" includes applying "well-defined pointer conversion"s (4th bullet point in p2) and performing well-defined pointer arithmetic on the result. – T.C. Aug 09 '14 at 08:34
  • @T.C. That is, g++, in particular, doesn't imlpement that safety pointer feature? –  Aug 09 '14 at 08:40
  • @T.C. Could you explain purpose of that feature? –  Aug 09 '14 at 08:41
  • 1
    @DmitryFucintv Neither g++ nor clang++ implements it. – T.C. Aug 09 '14 at 08:42
  • The primary purpose of this feature is to allow implementations to introduce a garbage collector, by permitting it to make UB things like obfuscating a pointer value with bitwise XOR and recovering and using the pointer later, which would be safe in non-garbage-collected systems, but can cause the pointed-to object to be collected in a garbage-collected system. See [this question](http://stackoverflow.com/questions/15157591/c11-garbage-collector-why-and-hows) for the details. – T.C. Aug 09 '14 at 08:48

2 Answers2

3

All that 3.7.4.3/3 is saying is that if you have an "integer representation of a safely derived pointer", and do math with it, the result is only a valid "integer representation of a safely derived pointer" if you could have come to the same result with pointer arithmetic and casting alone.

Although you are not allowed to do arithmetic operations on void* directy, there are various other ways of obtaining a valid pointer from void*. Although I'm too lazy to back every step with quotes from the standard, the following example should be valid:

double arr[10];
double* P = &arr[0]; // safely derived pointer
intptr_t N = reinterpret_cast<intptr_t>(P); // valid integer repr

void* V = reinterpret_cast<void*>(P);

// Compute &a[1] from V
void* V2 = reinterpret_cast<void*>(
    static_cast<char*>(V) + sizeof(double));

// Do the same with N
intptr_t N2 = N + sizeof(double);

assert(reinterpret_cast<void*>(N2) == V2);
  • V2 is a safely-derived pointer computable from reinterpret_cast<void*>(P)
  • N2 is the result of an additive or bitwise operation, one of whose operands (N) is an integer representation of a safely-derived pointer value P

Since V2 and N2 compare equal, N2 is a an "integer representation of a safely derived pointer" as well.

Ferdinand Beyer
  • 64,979
  • 15
  • 154
  • 145
  • This is guaranteed to be true by the Standard. That's literally how sizeof() is specified. – Puppy Aug 09 '14 at 08:55
  • `sizeof(char)` is defined to be 1. See section 5.3.3: "sizeof(char), sizeof(signed char) and sizeof(unsigned char) are 1" – Ferdinand Beyer Aug 09 '14 at 08:55
  • One could compute `V2 = cast(cast(V) + 1)` as well. – Ferdinand Beyer Aug 09 '14 at 09:11
  • -1, equality of values has nothing to do with safe derivation. – Potatoswatter Aug 09 '14 at 22:53
  • @Potatoswatter What? Did you even read the OP's quote from the standard? Equality is a required condition for the integer representation of a safely derived pointer: "(...) if that result converted by `reinterpret_cast` *would compare equal to* a safely-derived pointer computable from `reinterpret_cast(P)`" (3.7.4.3/3). This is the essence of this question. – Ferdinand Beyer Aug 10 '14 at 07:02
0

A garbage-collecting implementation needs to track pointers. In practice this has often been done by using the memory map as a key, so any pointer-sized words in memory within a certain numeric range are treated as bona fide pointers, and as such prevent garbage collection of an allocation block including the given address-value. This strategy is imprecise and C++ aims to do better, yet also supporting existing GC programs.

Contrary to your intuition, the bullet does effectively enable "pointer arithmetic on void*." An integer (std::intptr_t) obtained from a pointer by reinterpret_cast must also be tracked as a pointer, and the object continues to affect garbage collection as such even if it is modified by addition or bitwise operations.

std::uintptr_t handle1 = reinterpret_cast< std::uintptr_t >( new foo );
std::uintptr_t handle2 = reinterpret_cast< std::uintptr_t >( new foo );
// handle1 and handle2 won't be collected, despite no pointer-type references.

std::uintptr_t diff = handle2 - handle1; // not a pointer

std::uintptr_t sum = handle1 + diff; // sum refers to handle2
handle2 = 0; // Invalidate original reference to handle2

// At this point, the second foo is still reachable via sum.

Strict pointer safety improves the status quo, but false positives are still possible, when operations that satisfy the rule do not generate an actual pointer representation. For example, it's not clear from the standard text whether diff is traceable, because it's the result of a difference operation with two safely-derived operands, as opposed to an addition with exactly one safely-derived operand. (Whether or not is somewhat immaterial, false positives are going to occur anyway.)

Potatoswatter
  • 134,909
  • 25
  • 265
  • 421
  • Where can I read about GC in the Standard? I thought we must explcitly deallocate a memory allocated dynamically. Since, in your example handle1 must be still in the memory. –  Aug 09 '14 at 14:24
  • @DmitryFucintv If you search the standard document for the word "garbage," then all hits relate to garbage collection, but it does not specify anything explicitly. You can see, though, that permitting GC is the purpose for strict pointer safety. – Potatoswatter Aug 09 '14 at 22:52
  • I've read Bjarn's note about GC and he said that GC was optional. http://www.stroustrup.com/C++11FAQ.html#gc-abi I coudln't find it in the Standard with searching for "garbage". Does it standartized at all? –  Aug 10 '14 at 14:03
  • @DmitryFucintv Strict pointer safety is as much standardization as C++ garbage collection is likely to get. Standard-conforming garbage collectors already exist (and have for many years), but the new rules are designed to enable better designs with fewer false positives. I suppose they could add a `std::garbage_collect_now()` function, but it would normatively have no effect. The operation of a garbage collector is by definition transparent. – Potatoswatter Aug 10 '14 at 23:26