Current-Users archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: Stack alignment with pthreads



Hi Martin,

On Sunday, at 11:54, Martin Husemann wrote:
| I did some checks with a slightly modified test program on various archs and
| the results are clearly not clear.

Imho you should test alignment for 'char' and from 2 to 16 bytes only. Greater
values are likely to be ignored as mentioned in the gcc info page.

Also I think that you must add 1 to the 'align >= x' test, since ffs returns 1
for the first bit. align(2) implies ffs(align) >= 2, no?

With your test program modified accordingly I get this on i386 (with my patch in
makecontext for the threads):

Testing on main's stack:
aligned(2): PASS: address: 0xbfbfe54e alignement: 2 (2^1)
aligned(4): PASS: address: 0xbfbfe54c alignement: 4 (2^2)
aligned(8): PASS: address: 0xbfbfe548 alignement: 8 (2^3)
aligned(16): PASS: address: 0xbfbfe540 alignement: 64 (2^6)
Testing on thread's stack:
aligned(2): PASS: address: 0xb7fffdae alignement: 2 (2^1)
aligned(4): PASS: address: 0xb7fffcac alignement: 4 (2^2)
aligned(8): PASS: address: 0xb7fffba8 alignement: 8 (2^3)
aligned(16): PASS: address: 0xb7fffaa0 alignement: 32 (2^5)


| One could conclude that using aligned() on
| automatic variables does not work

Well, it will work if the assumptions made by gcc are true (e.g. first arg on
the stack aligned on xx bytes, 16 on i386). The problem is that these
assumptions are not really documented (or I couldn't find the doc, at
least). The bug comes at 90% from the lack of doc...

#include <stdio.h>
#include <inttypes.h>
#include <stdbool.h>
#include <pthread.h>
#include <strings.h>

static void *
test2(void *data)
{
  char test __attribute__((aligned(2)));
  uintptr_t v = (uintptr_t)&test;
  size_t align;

  align = ffs((int)v);

  printf("aligned(2): %s: address: %p alignement: %d (2^%zu)\n",
         align >= 2 ? "PASS" : "FAIL", &test, 1<<(align-1), (align-1));
  return NULL;
}

static void *
test4(void *data)
{
  char test __attribute__((aligned(4)));
  uintptr_t v = (uintptr_t)&test;
  size_t align;

  align = ffs((int)v);

  printf("aligned(4): %s: address: %p alignement: %d (2^%zu)\n",
         align >= 3 ? "PASS" : "FAIL", &test, 1<<(align-1), (align-1));
  return NULL;
}

static void *
test8(void *data)
{
  char test __attribute__((aligned(8)));
  uintptr_t v = (uintptr_t)&test;
  size_t align;

  align = ffs((int)v);

  printf("aligned(8): %s: address: %p alignement: %d (2^%zu)\n",
         align >= 4 ? "PASS" : "FAIL", &test, 1<<(align-1), (align-1));
  return NULL;
}

static void *
test16(void *data)
{
  char test __attribute__((aligned(16)));
  uintptr_t v = (uintptr_t)&test;
  size_t align;

  align = ffs((int)v);

  printf("aligned(16): %s: address: %p alignement: %d (2^%zu)\n",
         align >= 5 ? "PASS" : "FAIL", &test, 1<<(align-1), (align-1));
  return NULL;
}

int
main()
{
  pthread_t tg;

  printf("Testing on main's stack:\n");
  test2(NULL);
  test4(NULL);
  test8(NULL);
  test16(NULL);

  printf("Testing on thread's stack:\n");

  pthread_create(&tg, NULL, test2, NULL);
  pthread_join(tg, NULL);

  pthread_create(&tg, NULL, test4, NULL);
  pthread_join(tg, NULL);

  pthread_create(&tg, NULL, test8, NULL);
  pthread_join(tg, NULL);

  pthread_create(&tg, NULL, test16, NULL);
  pthread_join(tg, NULL);

  return 0;
}


Home | Main Index | Thread Index | Old Index