Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the effective type of an object written by memset?

Tags:

Code 1:

unsigned int *p = malloc(sizeof *p); memset(p, 0x55, sizeof *p);  unsigned int u = *p; 

Code 2:

void *d = malloc(50); *(double *)d = 1.23; memset(d, 0x55, 50);  unsigned int u = *(unsigned int *)d; 

In each case, what effect does memset have on the effective type of the object in the malloc'd space; and so is initializing u correct or a strict aliasing violation?

The definition of effective type (C11 6.5/6) is:

The effective type of an object for an access to its stored value is the declared type of the object, if any. If a value is stored into an object having no declared type through an lvalue having a type that is not a character type, then the type of the lvalue becomes the effective type of the object for that access and for subsequent accesses that do not modify the stored value. If a value is copied into an object having no declared type using memcpy or memmove, or is copied as an array of character type, then the effective type of the modified object for that access and for subsequent accesses that do not modify the value is the effective type of the object from which the value is copied, if it has one. For all other accesses to an object having no declared type, the effective type of the object is simply the type of the lvalue used for the access.

However it is unclear whether memset behaves like writing through an lvalue of character type, or something else. The description of memset (7.24.6.1) is not very illuminating:

The memset function copies the value of c (converted to an unsigned char) into each of the first n characters of the object pointed to by s.

like image 834
M.M Avatar asked Jun 21 '15 23:06

M.M


People also ask

What can be used instead of memset?

For one thing, sizeof(my_array) returns the total number of bytes in the data structure and not the number of elements.

What is memset and memcpy?

memset() is used to set all the bytes in a block of memory to a particular char value. Memset also only plays well with char as it's its initialization value. memcpy() copies bytes between memory. This type of data being copied is irrelevant, it just makes byte-for-byte copies.

Does memset require free?

memset does not allocate memory. It only fills a region of memory with a certain value. You do not have to free the buffer (unless the buffer was allocated).


1 Answers

My 50ct:

First, I break this into sentences for easier reference:

  1. The effective type of an object for an access to its stored value is the declared type of the object, if any.
  2. If a value is stored into an object having no declared type through an lvalue having a type that is not a character type, then the type of the lvalue becomes the effective type of the object for that access and for subsequent accesses that do not modify the stored value.
  3. If a value is copied into an object having no declared type using memcpy or memmove, or is copied as an array of character type, then the effective type of the modified object for that access and for subsequent accesses that do not modify the value is the effective type of the object from which the value is copied, if it has one.
  4. For all other accesses to an object having no declared type, the effective type of the object is simply the type of the lvalue used for the access.

The footnote might help here: "87) Allocated objects have no declared type.".

DNA: "does not apply"

Case 1:

  • memset(...): 1: DNA (no declared type), 2: DNA (memset writes to char - semantics), 3: DNA (neither memcpy nor memmove), 4: char [] for memset internally only (not permanent).
  • unsigned int u = *p: 1: DNA (no declared type), 2/3: DNA (no write, but read), 4: type of lvalue is unsigned int.

Conclusion: no violation, but the interpretion is implementation defined, as the actual value depends on alignment within the variable and endianess.

Case 2:

  • *(double *)d = 1.23;: 2: d becomes double * for this and following reads.
  • memset(d, 0x55, 50);: same as for Case 1.
  • unsigned int u = *(unsigned int *)d: d is still double *: bang!

In any way, memset() is of litte use for non-char scalars, except if using 0, which is still implementation dependent, as neither (float)0.0, nor the null pointer need to be actually "all bits zero".

Finally:

  • Sentence 2 does not apply to memset, as internally, memset() copies by char: "...of c (converted to an unsigned char) into each of the first n characters ..." (or uses char semantics, at least; the actual implementation is irrelevant here).
  • Sentence 3 does not apply to memset(), either, as that only applies to memcpy/memmove or when copying as "an array of character type". Which it also does not (but the former do, so the or-condition just makes an explicit copy-loop equivalent to the functions).
  • memset() does not change the effective type of the object. That differs from memcpy and memmove. That results from sentence 4, which does not include "... for that access and for subsequent accesses ..." as 2 and 3 state and 1 implies.
like image 87
too honest for this site Avatar answered Sep 18 '22 14:09

too honest for this site