| 4982 | } |
| 4983 | |
| 4984 | static void* internal_memalign(mstate m, size_t alignment, size_t bytes) { |
| 4985 | void* mem = 0; |
| 4986 | if (alignment < MIN_CHUNK_SIZE) /* must be at least a minimum chunk size */ |
| 4987 | alignment = MIN_CHUNK_SIZE; |
| 4988 | if ((alignment & (alignment-SIZE_T_ONE)) != 0) {/* Ensure a power of 2 */ |
| 4989 | size_t a = MALLOC_ALIGNMENT << 1; |
| 4990 | while (a < alignment) a <<= 1; |
| 4991 | alignment = a; |
| 4992 | } |
| 4993 | if (bytes >= MAX_REQUEST - alignment) { |
| 4994 | if (m != 0) { /* Test isn't needed but avoids compiler warning */ |
| 4995 | MALLOC_FAILURE_ACTION; |
| 4996 | } |
| 4997 | } |
| 4998 | else { |
| 4999 | size_t nb = request2size(bytes); |
| 5000 | size_t req = nb + alignment + MIN_CHUNK_SIZE - CHUNK_OVERHEAD; |
| 5001 | mem = internal_malloc(m, req); |
| 5002 | if (mem != 0) { |
| 5003 | mchunkptr p = mem2chunk(mem); |
| 5004 | if (PREACTION(m)) |
| 5005 | return 0; |
| 5006 | if ((((size_t)(mem)) & (alignment - 1)) != 0) { /* misaligned */ |
| 5007 | /* |
| 5008 | Find an aligned spot inside chunk. Since we need to give |
| 5009 | back leading space in a chunk of at least MIN_CHUNK_SIZE, if |
| 5010 | the first calculation places us at a spot with less than |
| 5011 | MIN_CHUNK_SIZE leader, we can move to the next aligned spot. |
| 5012 | We've allocated enough total room so that this is always |
| 5013 | possible. |
| 5014 | */ |
| 5015 | char* br = (char*)mem2chunk((size_t)(((size_t)((char*)mem + alignment - |
| 5016 | SIZE_T_ONE)) & |
| 5017 | -alignment)); |
| 5018 | char* pos = ((size_t)(br - (char*)(p)) >= MIN_CHUNK_SIZE)? |
| 5019 | br : br+alignment; |
| 5020 | mchunkptr newp = (mchunkptr)pos; |
| 5021 | size_t leadsize = pos - (char*)(p); |
| 5022 | size_t newsize = chunksize(p) - leadsize; |
| 5023 | |
| 5024 | if (is_mmapped(p)) { /* For mmapped chunks, just adjust offset */ |
| 5025 | newp->prev_foot = p->prev_foot + leadsize; |
| 5026 | newp->head = newsize; |
| 5027 | } |
| 5028 | else { /* Otherwise, give back leader, use the rest */ |
| 5029 | set_inuse(m, newp, newsize); |
| 5030 | set_inuse(m, p, leadsize); |
| 5031 | dispose_chunk(m, p, leadsize); |
| 5032 | } |
| 5033 | p = newp; |
| 5034 | } |
| 5035 | |
| 5036 | /* Give back spare room at the end */ |
| 5037 | if (!is_mmapped(p)) { |
| 5038 | size_t size = chunksize(p); |
| 5039 | if (size > nb + MIN_CHUNK_SIZE) { |
| 5040 | size_t remainder_size = size - nb; |
| 5041 | mchunkptr remainder = chunk_plus_offset(p, nb); |
no test coverage detected