0

When you accessing block of memory (f.e. in real case using mmap) correct pointer for sem_t have to by multiple of 4. If it is not, then sem_init() still doesn't return -1 (error value), but sem_t isn't valid. Why it is working like this?

Below code that is showing behaviour of semaphores.

#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <strings.h> //bzero

int main(int argc, const char *argv[]) {
  //sizeof(sem_t) == 32 on 86_64, 16 on 86
  void *adrr = malloc(sizeof(sem_t)*2);
  bzero(adrr, sizeof(sem_t)*2); 

  sem_t *sem1 = adrr+1;
  if(sem_init(sem1, 1, 0) == -1) printf("ERROR\n");
  sem_wait(sem1);
  printf("Not working\n");
  bzero(adrr, sizeof(sem_t)*2);

  sem_t *sem2 = adrr+2;
  sem_init(sem2, 1, 0);
  sem_wait(sem2);
  printf("Not working\n");
  bzero(adrr, sizeof(sem_t)*2); 

  sem_t *sem3 = adrr+3;
  sem_init(sem3, 1, 0);
  sem_wait(sem3);
  printf("Not working\n");
  bzero(adrr, sizeof(sem_t)*2);

  sem_t *sem4 = adrr+4;
  sem_init(sem4, 1, 0);
  sem_wait(sem4);
  printf("Working\n");
  free(adrr);
  return 0; 
}
Chimstaz
  • 3
  • 2
  • [The POSIX `sem_init` reference](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sem_init.html) doesn't say anything that the `sem_t` object have to be placed on an address evenly divisible by 4. Where did you get that information? – Some programmer dude May 21 '17 at 18:00
  • Adding 1 to a void pointer (i.e. `adrr`) seems strange. See http://stackoverflow.com/questions/6449935/increment-void-pointer-by-one-byte-by-two – Support Ukraine May 21 '17 at 18:13
  • I found nothing about that, but when I run above code, only semaphore pointed by last pointer is working correctly. – Chimstaz May 21 '17 at 18:14
  • You are expected to pass a pointer to a validly aligned `sem_t` structure. If you pass a pointer that is not so aligned, you get undefined behaviour. You must be using GCC. Standard C does not allow arithmetic on `void` pointers. – Jonathan Leffler May 21 '17 at 18:18
  • when the parameters to the function: `main()` are not used, then use the signature: `int main( void )` – user3629249 May 22 '17 at 16:12
  • for ease of readability and understanding: 1) follow the axiom: *only one statement per line and (at most) one variable declaration per statement.* 2) separate code blocks (for, if, else, while, do...while, switch, case, default) via a single blank line. – user3629249 May 22 '17 at 16:15
  • when calling any of the heap allocation functions: (malloc, calloc, realloc), always check (!=NULL) the returned value to assure the operation was successful. – user3629249 May 22 '17 at 16:15

1 Answers1

2

ALL1 types in C may have alignment requirements. These requirements are always implementation defined, and may be different on different architectures or even on different compilers on the same architecture (though that is rare).

Violating an implementation defined alignment requirement results in undefined behavior -- anything may happen, though generally what happens is the program gets an error or crashes when accessing the misaligned object.

What you appear to have determined is that on your specific implementation, sem_t has an alignment requirement of 4 -- fairly common on 32-bit architectures. Other implementations may be different.


1You can argue that char never has an alignment requirement, or that it's alignment requirement is required to be 1

Chris Dodd
  • 119,907
  • 13
  • 134
  • 226
  • FWIW: 32-bit compilations on (64-bit) Macs allow `double` to be 4-byte aligned, but 64-bit compilations on the same machine require 8-byte alignment. – Jonathan Leffler May 21 '17 at 18:22
  • "though that is rare" - I would not sign that one. AFAIK `long double` has different alignments on x86, depending on the ABI (it is not only the architecture specifying alignment and layout of types). 1 byte is the unit of alignment for all other types, so no, `char` has no alignment requirement. – too honest for this site May 21 '17 at 19:10