What guarantees regarding low order bits does malloc offer?

When you call C malloc , is there any guarantee that the first bits of the lower order will be? If you are writing a compiler / interpreter for a dynamic language, but want to have fixnums of the form bbbbbbbb bbbbbbbb . . . bbbbbbb1 bbbbbbbb bbbbbbbb . . . bbbbbbb1 bbbbbbbb bbbbbbbb . . . bbbbbbb1 (where b is a bit) and pointers of the form bbbbbbbb bbbbbbbb . . . bbbbbbb0 bbbbbbbb bbbbbbbb . . . bbbbbbb0 bbbbbbbb bbbbbbbb . . . bbbbbbb0 (or vice versa), is there any way that malloc will return pointers matching this pattern?

If I just allocated two more bytes than I need, increase the return value by one, if necessary, to fit the bit pattern, and keep the actual pointer returned by malloc in the second byte so that I know what to do with free ?

Can one simply assume that malloc will return a pointer with a null value as the final bit? Can I assume that x86 will have two zeros at the end and that x64 will have four zeros at the end?

+7
source share
3 answers

C does not guarantee that the least significant bit is zero only if the pointer is aligned for all possible types. In practice, the 2 or 3 least significant bits are likely to be zero, but do not count on it.

You can see for yourself, but the best way is to use something like posix_memalign .

If you want to do this yourself, you will need to swap memory and track the original pointer. Something like (assuming you want 16-byte alignment, you can make it generic, not verified):

  void * my_aligned_malloc16 (size_t sz) {
    void * p = malloc (sz + 15 + 16);  // 15 to ensure alignment, 16 for payload
    if (! p) return NULL;
    size_t aligned_addr = ((size_t) p + 15) & (~ 15);
    void * aligned_ptr = (void *) aligned_addr;
    memcpy (aligned_ptr, & p, sizeof (void *));  // save original pointer as payload
    return (void *) (aligned_addr + 16);  // return aligned address past payload
 }

 void my_aligned_free16 (void * ptr) { 
    void ** original_pointer = (void **) (((size_t) ptr) - 16);
    free (* original_pointer);  
 }

As you can see, this is pretty ugly, so prefer to use something like posix_memalign . Perhaps your runtime has a similar function if it is not available, for example. memalign (thanks @R ..) or _ aligned_malloc when using MSVC.

+9
source

Malloc is guaranteed to return a pointer with the correct alignment for any data type, which on some architectures will be four bytes, and others may be eight. You can imagine an environment in which alignment will be one. The C library will have a macro somewhere that tells you what the actual rounding is.

+3
source

My answer may be a little off topic, but my anxieties in the cockpit go away like crazy - "Pull up! Pull up!"

This scheme depends too much on the HW architecture and the deep details of the implementation of the compiler and C libraries. C allows you to go to this level of insignificant bits and bytes and look at the bit pattern and alignment of objects to encode device drivers, etc. On the other hand, you create a high-level object, an interpreter, and runtime. C can also do this, but you don’t need to use the low-level convolution capabilities of C; IMHO, you should avoid this. Been there, done it, there are holes in the legs to show it.

If you manage to create your own interpreter, you will want to transfer it to another platform, where the rules for the presentation and alignment of bits may differ, possibly radically. Coming up with a design that does not depend on such complex manipulations with bits and peeping under covers will help you without problems in the future.

-k

+3
source

All Articles