views:

125

answers:

6

Relevant code is this:

typedef unsigned long int chunk_head;

typedef struct malloc_chunk
{
    // Contains the size of the data in the chunk and the flag byte.
    chunk_head      head;

    // Deliberately left unsized to allow overflow. 
    // Contains the payload of the chunk.
    unsigned int    data[];
};

And just as an example, the "get" macro is this:

//Get the size of the data contained within the chunk.
#define GET_CHUNK_SIZE(chunk) ((chunk.head) & 0xFFFFFF)

The upper byte I'm using the bits for flags -- "inuse" and "can be coalesced", and any additional ones that I find will be useful.

Now that I'm done providing background information, as I stated in the title, I need to be able to change the lower 3 bytes to how large the chunk is. My initial instinct was to bitwise AND the header with the size, since it would be properly aligned, but then I realized it might overwrite the flag bytes too, because it automatically prepended zeroes until it size matched the long. I'm not even sure you can bitwise AND an int and a long. Anyway, help greatly appreciated.

A: 

chunk.head = (chunk.head & ~0xffffffL) | (new_lower_bits)

DigitalRoss
+6  A: 

How about:

head = (head & 0xff000000) | (new_size & 0x00ffffff)
James McNellis
Andy Shulman
James McNellis
A: 
#define SET_CHUNK_SIZE(chunk, size) (chunk.head = (chunk.head & 0xFF000000) | (size & 0x00FFFFFF))

Is that what you meant or did I miss something?

Richard Pennington
Almost right, but the `|=` means you could never clear bits in the size portion. I suspect `=` is more appropriate.
Justin Love
Justin you're right. Fixing.
Richard Pennington
A: 
// retain the old top 8 bits
chunk.head &= 0xFF00000000

// set the lower 24 bits
chunk.head |= (0x00FFFFFF & new_bits)
R Samuel Klatchko
+4  A: 

For some reason most of the responses you received so far insist on sweeping the potential size overflow issue under the carpet, i.e. they "and" the chunk size with 0x00FFFFFF thus quietly discarding the excessive size bits (if any) and then proceed to write the completely meaningless tail portion of the size into the field. I don't know why would anyone do something like that.

The more reasonable code might look as follows

assert((size & 0xFF000000) == 0);
chunk.head = (chunk.head & 0xFF000000) | size;

There is no valid reason to "and" the size with 0x00FFFFFF. You should either abort or at least assert on excessive size, not quietly discard the excess.

AndreyT
+3  A: 

Use bit fields to do this. It avoids having to use the macros, nice in the debugger too:

typedef struct chunk_head {
  unsigned size:24;
  unsigned inuse:1;
  unsigned cancoalesce:1;
  // Room for 6 more...
};

typedef struct malloc_chunk {
  struct chunk_head head;
  int data[];
};
Hans Passant
Only reason I didn't do this (believe me, I considered using them for a long time) was that by all reports, the compiler produces more optimized code for masks than it does for bit fields. And because I need to eke out every last ounce of performance I can, I opted for the speedier code.
Andy Shulman