[C++ patch] Set attributes for C++ runtime library calls

Mike Stump mikestump@comcast.net
Sat Aug 24 04:36:00 GMT 2013


On Aug 23, 2013, at 5:53 PM, Gabriel Dos Reis <gdr@integrable-solutions.net> wrote:
> If you quoted the standard to back up your assertions, I would have been
> able to "feel free to point this out" :-)
> 
> The thing is I am still trying to figure out what (1) what you would have liked;

I've directly stated it, not sure how you missed it.  The life of the original object does not end.

> (2) what you believe the standards mandate, with appropriate quote; and

The life of the original object does not end.  See below for the quote.

>>> Really?
>> 
>>>> statement, or, is it merely changing the value?
>>> 
>>> That is an assignment to an existing int storage.
>> 
>>>> And what if we do a memcpy (ip, &j, sizeof (int));
>>> 
>>> Well, the case of 'memcpy' isn't defined by the standard
>> 
>> Odd, in the c++98 standard memcpy was defined by the standard, as well as the open code that memcpy would be.  I find memcpy in [diff.library].  I can quote all the requirements that makes the open code work as well.  It is defined.
> 
> When I say "the case of 'memcpy' isn't defined", I was not saying that
> the function "memcpy" itself isn't defined by the standard.  I was discussing
> its effect in the scope of this discussion, e.g. lifetime vs. assignment.
> That isn't defined in the standard.

And yet memcpy is exactly defined and all interactions with the entire rest of the standard are as specified.  Those semantics that are defined and required, are, by definition.  You can't make them go away by claiming they are undefined.

int i = 1, j = 2;
{
	memcpy (&i, &j)
	// here i exists and is 2.
}

  3.7.1  Static storage duration                      [basic.stc.static]

1 All  objects which neither have dynamic storage duration nor are local
  have static storage duration.  The storage  for  these  objects  shall
  last   for   the   duration   of   the   program  (_basic.start.init_,
  _basic.start.term_).

This covers why i exists.  As for why i has the value 2, gosh:

       7.21.2.1  The memcpy function                                                                  
                                                                                                      
       Synopsis                                                                                       
                                                                                                      
       [#1]                                                                                           
                                                                                                      
               #include <string.h>                                                                 
               void *memcpy(void * restrict s1,                                                       
                       const void * restrict s2,                                                      
                       size_t n);                                                                     
                                                                                                      
       Description                                                                                    
                                                                                                      
       [#2] The memcpy function copies n characters from the object                                   
       pointed  to  by  s2  into  the  object pointed to by s1.  If                                   
       copying  takes  place  between  objects  that  overlap,  the                                   
       behavior is undefined.                                                                         


  1.6  The C++ memory model                               [intro.memory]

1 The fundamental storage unit in the C++ memory model is the  byte.

An object  of  POD4)  type
  (_basic.types_) shall occupy contiguous bytes of storage.

 5.3.3  Sizeof                                            [expr.sizeof]

1 The sizeof operator yields the number of bytes in the object represen-
  tation of its operand.  The operand is either an expression, which  is
  not  evaluated, or a parenthesized type-id.  The sizeof operator shall

4 The  object representation of an object of type T is the sequence of N
  unsigned char objects taken up by the object of type T, where N equals
  sizeof(T).   The  value representation of an object is the set of bits
  that hold the value of type T.  For POD types, the  value  representa-
  tion  is  a set of bits in the object representation that determines a
  value, which is one discrete element of an implementation-defined  set
  of values.37)

>> You can see evidence that we meant for it to work here:
>> 
>> 2 For any complete POD object type T, whether or not the object holds  a
>>  valid value of type T, the underlying bytes (_intro.memory_) making up
>>  the object can be copied into an array of char or unsigned char.36) If
>>  the content of the array of char or unsigned char is copied back  into
>>  the  object,  the  object  shall subsequently hold its original value.
>>  [Example:
>>  #define N sizeof(T)
>>  char buf[N];
>>  T obj;                          // obj initialized to its original value
>>  memcpy(buf, &obj, N);           // between these two calls to memcpy,
>>                                  // obj might be modified
>>  memcpy(&obj, buf, N);           // at this point, each subobject of obj of scalar type
>>                                  // holds its original value
>> 
>> thought, I view this as completely redundant with the standard and should just be a note.  From the base standard, in C99 is it defined in 7.24.4.2.3 and I suspect remains largely unchanged from previous standards.
>> 
> 
> This does not say whether the effect of memcpy is assigment or copy
> construction.

Right, because it doesn't define taking the bytes of one object and assigning another object to have those bytes.  The definition of memcpy does that.

char c1, c2;

c1 = c2;

This is defined to take the bytes that comprise c2 (1 byte, by definition), and slam them into c1.  After this runs, c1 will have the value of c2.  This, is, by definition.  We can plainly see the assignment operator.  This is assignment, the hint is the spelling of the operator.  It is spelled =.  This is what the C standard means, when they say copies.  copies is defined to mean, =.

> Which was the point I was making.

Sure it does.  Directly, please read the statement again:

      The memcpy function copies n characters from the object                                   
      pointed  to  by  s2  into  the  object pointed to by s1.

I said what the words mean.  I'd said copy means the = operator.

Here is the text for =:

       [#3] An assignment operator stores a  value  in  the  object
       designated  by  the  left operand.

This is the very definition of the word copy, trust me.  This is how the standard was meant to be read.

>>>> I think the most logical line of reasoning is that when the requirements of [basic.lval] are met, the, this is a change of value of an object, not a modification to it's lifetime.
>>> 
>>> Why?
>> 
>> Because if you end the lifetime of the original int, you destroy the semantic that everyone knows for C.  This cannot be done.
> 
> But:
>  (1) we are not talking about C

Sure we are.  The semantics of memcpy and its behavior come from C, and are identical to it.  Since this is true, I can freely quote the required semantics of the C standard, they are identical.

>  (2) C does not have a notion of lifetime -- at least not in the sense of C++.

It absolutely does:  Let me quote:

       [#1]  An  object  has a storage duration that determines its                                
       lifetime.

       [#17]  Note  that if a for loop were used instead of a while |
       loop, the lifetime of the unnamed object would be  the  body
       of  the  loop only, and on entry next time around p would be
       pointing to an object  which  is  no  longer  guaranteed  to |
       exist, which would result in undefined behavior.

       expression  is  evaluated.   The  size of each instance of a
       variable length  array  type  does  not  change  during  its
       lifetime.


       214The buffer has to have a lifetime at least  as  great  as                                
          the  open stream, so the stream should be closed before a                                
          buffer that has automatic storage duration is deallocated                                
          upon block exit.

       environment.    All  objects  in  static  storage  shall  be
       initialized (set to their  initial  values)  before  program
       startup.   The  manner and timing of such initialization are

       [#5] An instance  of  each  object  with  automatic  storage
       duration is associated with each entry into its block.  Such
       an object exists and retains its  last-stored  value  during
       the  execution of the block and while the block is suspended
       (by a call of a function or receipt of a signal).

       [#2] The malloc function allocates space for an object whose                                
       size is specified by size and whose value is  indeterminate.                                

         -- The value of a pointer that refers to space deallocated                                
            by a call to the  free  or  realloc  function  is  used                                
            (7.20.3).                                                                              

       [#2] The free function causes the space pointed to by ptr to                                
       be  deallocated,  that  is,  made  available   for   further                                
       allocation.

I'll note that C++ merely sought to explain and formalize the rules of C.  We extended and added a few bits, but, the object model is based upon the C model.  I can't begin to fathom how you could have possibly missed the notion of lifetime in C.  It right there, an just about exactly matches C++.

> So, whatever notion of semantics you think everyone knows of C
> is largely irrelevant.

No, you must not understand C++ to say this.  C++ is defined to be, exactly what C is, with a few exceptions here and there, and in this case, there are no exceptions.  This is by design.  I'm sorry if you didn't realize this.

>>>> So, in the case quoted, since the type of the accesses are both int, we don't reuse the storage, since the requirements of [basic.lval] are met.
>>> 
>>> Consider:
>>> 
>>>   struct S {
>>>       S(int);
>>>       ~S();
>>>       // …
>>>   };
>>> 
>>>   int main() {
>>>       S s(8);
>>> 
>>>        new (&s) S(9); // #1
>>>   }
>>> 
>>> Is #1 a reuse of storage to create a new object or assignment?
>> 
>> Behaves as assignment, s exists post the new, til the closing }.
> 
> What does not mean concretely?

Concretely, it means exactly what is stated in the standard.  I've quoted all the words.  copy means =.  = is an assignment operator.  Concretely, where did you get lost?

In the //, one can imagine you're asking about

S (int v) { val = v; }
int val;

to be concrete.  We can see the = operator.  This is the assignment operator, by definition.

>>>> Indeed, the programmer expects that they can access i after *ip = j; and that the _value_ that object, while changed from the original 1, will be 2 just after the *ip = j; statement.
>>>> 
>>>> Since we know that i must be 3 at the end, we then know what the wording, reused, must mean, cause other meanings that could possibly make it work for you in the case you are considering, would destroy this property of pointers, and everyone knows the semantics of pointers, they are undisputed.  Or put another way, you cannot misread reused in this way.
>>> 
>>> And why do you assert that I misread 'reused' in this way?
>> 
>> See your email that I originally replied to.
>> 
>> Let me quote it here:
>> 
>>> If the user-supplied operator new returns &a, then it must
>>> also ensure that 'a' is not used anywhere else -- e.g. I you can't
>>> do lvalue-to-value conversion on 'a' to see what is written there.
>>> Because its storage has been reused.
>> 
>> You said it was reused, this is wrong.
> 
> You keep saying it is wrong without quoting the standards that is the
> basis for that.

I've quoted the required semantics of the standard.  What part was unclear to you?

>> You use that as backing to say that the lifetime of the original object ends, this is wrong.
> 
> You *assert* it is wrong.

I quoted the required semantics of the language standard. What part was unclear to you?


More information about the Gcc-patches mailing list