Skip to content

Commit 5ef33a9

Browse files
committed
Don't bitshift by negative amounts.
Don't bitshift by negative amounts when encoding/decoding run sizes in chunk header maps. This affected systems with page sizes greater than 8 KiB. Reported by Ingvar Hagelund <ingvar@redpill-linpro.com>.
1 parent 6e98caf commit 5ef33a9

File tree

4 files changed

+50
-13
lines changed

4 files changed

+50
-13
lines changed

ChangeLog

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ brevity. Much more detail can be found in the git revision history:
44

55
https://github.com/jemalloc/jemalloc
66

7+
* 4.x.x (XXX)
8+
9+
Bug fixes:
10+
- Don't bitshift by negative amounts when encoding/decoding run sizes in chunk
11+
header maps. This affected systems with page sizes greater than 8 KiB.
12+
713
* 4.0.0 (August 17, 2015)
814

915
This version contains many speed and space optimizations, both minor and

include/jemalloc/internal/arena.h

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,7 @@ arena_chunk_map_misc_t *arena_run_to_miscelm(arena_run_t *run);
519519
size_t *arena_mapbitsp_get(arena_chunk_t *chunk, size_t pageind);
520520
size_t arena_mapbitsp_read(size_t *mapbitsp);
521521
size_t arena_mapbits_get(arena_chunk_t *chunk, size_t pageind);
522+
size_t arena_mapbits_size_decode(size_t mapbits);
522523
size_t arena_mapbits_unallocated_size_get(arena_chunk_t *chunk,
523524
size_t pageind);
524525
size_t arena_mapbits_large_size_get(arena_chunk_t *chunk, size_t pageind);
@@ -530,6 +531,7 @@ size_t arena_mapbits_decommitted_get(arena_chunk_t *chunk, size_t pageind);
530531
size_t arena_mapbits_large_get(arena_chunk_t *chunk, size_t pageind);
531532
size_t arena_mapbits_allocated_get(arena_chunk_t *chunk, size_t pageind);
532533
void arena_mapbitsp_write(size_t *mapbitsp, size_t mapbits);
534+
size_t arena_mapbits_size_encode(size_t size);
533535
void arena_mapbits_unallocated_set(arena_chunk_t *chunk, size_t pageind,
534536
size_t size, size_t flags);
535537
void arena_mapbits_unallocated_size_set(arena_chunk_t *chunk, size_t pageind,
@@ -652,14 +654,29 @@ arena_mapbits_get(arena_chunk_t *chunk, size_t pageind)
652654
return (arena_mapbitsp_read(arena_mapbitsp_get(chunk, pageind)));
653655
}
654656

657+
JEMALLOC_ALWAYS_INLINE size_t
658+
arena_mapbits_size_decode(size_t mapbits)
659+
{
660+
size_t size;
661+
662+
if (CHUNK_MAP_SIZE_SHIFT > 0)
663+
size = (mapbits & CHUNK_MAP_SIZE_MASK) >> CHUNK_MAP_SIZE_SHIFT;
664+
else if (CHUNK_MAP_SIZE_SHIFT == 0)
665+
size = mapbits & CHUNK_MAP_SIZE_MASK;
666+
else
667+
size = (mapbits & CHUNK_MAP_SIZE_MASK) << -CHUNK_MAP_SIZE_SHIFT;
668+
669+
return (size);
670+
}
671+
655672
JEMALLOC_ALWAYS_INLINE size_t
656673
arena_mapbits_unallocated_size_get(arena_chunk_t *chunk, size_t pageind)
657674
{
658675
size_t mapbits;
659676

660677
mapbits = arena_mapbits_get(chunk, pageind);
661678
assert((mapbits & (CHUNK_MAP_LARGE|CHUNK_MAP_ALLOCATED)) == 0);
662-
return ((mapbits & CHUNK_MAP_SIZE_MASK) >> CHUNK_MAP_SIZE_SHIFT);
679+
return (arena_mapbits_size_decode(mapbits));
663680
}
664681

665682
JEMALLOC_ALWAYS_INLINE size_t
@@ -670,7 +687,7 @@ arena_mapbits_large_size_get(arena_chunk_t *chunk, size_t pageind)
670687
mapbits = arena_mapbits_get(chunk, pageind);
671688
assert((mapbits & (CHUNK_MAP_LARGE|CHUNK_MAP_ALLOCATED)) ==
672689
(CHUNK_MAP_LARGE|CHUNK_MAP_ALLOCATED));
673-
return ((mapbits & CHUNK_MAP_SIZE_MASK) >> CHUNK_MAP_SIZE_SHIFT);
690+
return (arena_mapbits_size_decode(mapbits));
674691
}
675692

676693
JEMALLOC_ALWAYS_INLINE size_t
@@ -754,18 +771,33 @@ arena_mapbitsp_write(size_t *mapbitsp, size_t mapbits)
754771
*mapbitsp = mapbits;
755772
}
756773

774+
JEMALLOC_ALWAYS_INLINE size_t
775+
arena_mapbits_size_encode(size_t size)
776+
{
777+
size_t mapbits;
778+
779+
if (CHUNK_MAP_SIZE_SHIFT > 0)
780+
mapbits = size << CHUNK_MAP_SIZE_SHIFT;
781+
else if (CHUNK_MAP_SIZE_SHIFT == 0)
782+
mapbits = size;
783+
else
784+
mapbits = size >> -CHUNK_MAP_SIZE_SHIFT;
785+
786+
assert((mapbits & ~CHUNK_MAP_SIZE_MASK) == 0);
787+
return (mapbits);
788+
}
789+
757790
JEMALLOC_ALWAYS_INLINE void
758791
arena_mapbits_unallocated_set(arena_chunk_t *chunk, size_t pageind, size_t size,
759792
size_t flags)
760793
{
761794
size_t *mapbitsp = arena_mapbitsp_get(chunk, pageind);
762795

763796
assert((size & PAGE_MASK) == 0);
764-
assert(((size << CHUNK_MAP_SIZE_SHIFT) & ~CHUNK_MAP_SIZE_MASK) == 0);
765797
assert((flags & CHUNK_MAP_FLAGS_MASK) == flags);
766798
assert((flags & CHUNK_MAP_DECOMMITTED) == 0 || (flags &
767799
(CHUNK_MAP_DIRTY|CHUNK_MAP_UNZEROED)) == 0);
768-
arena_mapbitsp_write(mapbitsp, (size << CHUNK_MAP_SIZE_SHIFT) |
800+
arena_mapbitsp_write(mapbitsp, arena_mapbits_size_encode(size) |
769801
CHUNK_MAP_BININD_INVALID | flags);
770802
}
771803

@@ -777,10 +809,9 @@ arena_mapbits_unallocated_size_set(arena_chunk_t *chunk, size_t pageind,
777809
size_t mapbits = arena_mapbitsp_read(mapbitsp);
778810

779811
assert((size & PAGE_MASK) == 0);
780-
assert(((size << CHUNK_MAP_SIZE_SHIFT) & ~CHUNK_MAP_SIZE_MASK) == 0);
781812
assert((mapbits & (CHUNK_MAP_LARGE|CHUNK_MAP_ALLOCATED)) == 0);
782-
arena_mapbitsp_write(mapbitsp, (size << CHUNK_MAP_SIZE_SHIFT) | (mapbits
783-
& ~CHUNK_MAP_SIZE_MASK));
813+
arena_mapbitsp_write(mapbitsp, arena_mapbits_size_encode(size) |
814+
(mapbits & ~CHUNK_MAP_SIZE_MASK));
784815
}
785816

786817
JEMALLOC_ALWAYS_INLINE void
@@ -799,11 +830,10 @@ arena_mapbits_large_set(arena_chunk_t *chunk, size_t pageind, size_t size,
799830
size_t *mapbitsp = arena_mapbitsp_get(chunk, pageind);
800831

801832
assert((size & PAGE_MASK) == 0);
802-
assert(((size << CHUNK_MAP_SIZE_SHIFT) & ~CHUNK_MAP_SIZE_MASK) == 0);
803833
assert((flags & CHUNK_MAP_FLAGS_MASK) == flags);
804834
assert((flags & CHUNK_MAP_DECOMMITTED) == 0 || (flags &
805835
(CHUNK_MAP_DIRTY|CHUNK_MAP_UNZEROED)) == 0);
806-
arena_mapbitsp_write(mapbitsp, (size << CHUNK_MAP_SIZE_SHIFT) |
836+
arena_mapbitsp_write(mapbitsp, arena_mapbits_size_encode(size) |
807837
CHUNK_MAP_BININD_INVALID | flags | CHUNK_MAP_LARGE |
808838
CHUNK_MAP_ALLOCATED);
809839
}

include/jemalloc/internal/private_symbols.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ arena_mapbits_large_size_get
5050
arena_mapbitsp_get
5151
arena_mapbitsp_read
5252
arena_mapbitsp_write
53+
arena_mapbits_size_decode
54+
arena_mapbits_size_encode
5355
arena_mapbits_small_runind_get
5456
arena_mapbits_small_set
5557
arena_mapbits_unallocated_set

src/arena.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ JEMALLOC_INLINE_C arena_chunk_map_misc_t *
3939
arena_miscelm_key_create(size_t size)
4040
{
4141

42-
return ((arena_chunk_map_misc_t *)((size << CHUNK_MAP_SIZE_SHIFT) |
42+
return ((arena_chunk_map_misc_t *)(arena_mapbits_size_encode(size) |
4343
CHUNK_MAP_KEY));
4444
}
4545

@@ -58,8 +58,7 @@ arena_miscelm_key_size_get(const arena_chunk_map_misc_t *miscelm)
5858

5959
assert(arena_miscelm_is_key(miscelm));
6060

61-
return (((uintptr_t)miscelm & CHUNK_MAP_SIZE_MASK) >>
62-
CHUNK_MAP_SIZE_SHIFT);
61+
return (arena_mapbits_size_decode((uintptr_t)miscelm));
6362
}
6463

6564
JEMALLOC_INLINE_C size_t
@@ -73,7 +72,7 @@ arena_miscelm_size_get(arena_chunk_map_misc_t *miscelm)
7372
chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(miscelm);
7473
pageind = arena_miscelm_to_pageind(miscelm);
7574
mapbits = arena_mapbits_get(chunk, pageind);
76-
return ((mapbits & CHUNK_MAP_SIZE_MASK) >> CHUNK_MAP_SIZE_SHIFT);
75+
return (arena_mapbits_size_decode(mapbits));
7776
}
7877

7978
JEMALLOC_INLINE_C int

0 commit comments

Comments
 (0)