Skip to content

Commit 090a6b4

Browse files
author
Timon Karnezos
committed
Fixed citusdata#16. Changed bitstream_pack to write one byte at a time instead of 8 at a time to prevent writing to memory not explicitly allocated. Only affects some SPARSE configurations.
1 parent b1315fa commit 090a6b4

File tree

1 file changed

+55
-16
lines changed

1 file changed

+55
-16
lines changed

hll.c

Lines changed: 55 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -369,31 +369,70 @@ typedef struct
369369
static void
370370
bitstream_pack(bitstream_write_cursor_t * bwcp, uint32_t val)
371371
{
372-
// Fetch the quadword where our data goes.
373-
uint64_t qw = * (uint64_t *) bwcp->bwc_curp;
372+
size_t bits_left_in_first_byte = 8 - bwcp->bwc_used;
373+
size_t bits_to_write_after_first_byte = bwcp->bwc_nbits - bits_left_in_first_byte;
374+
size_t full_bytes_to_write = bits_to_write_after_first_byte / 8;
375+
size_t remainder_bits_after_full_bytes = bits_to_write_after_first_byte % 8;
374376

375-
// Swap the bytes.
376-
qw = bswap_64(qw);
377+
// write is small enough that it fits in current byte's remaining space with
378+
// room to spare, so pad the bottom of the byte by left-shifting
379+
if (bwcp->bwc_nbits < bits_left_in_first_byte)
380+
{
381+
* bwcp->bwc_curp = (* bwcp->bwc_curp) | ((uint8_t)(val << (bits_left_in_first_byte - bwcp->bwc_nbits)));
382+
383+
// consume part of the byte and exit
384+
bwcp->bwc_used += bwcp->bwc_nbits;
385+
return;
386+
}
377387

378-
// Shift our bits into place and combine.
379-
qw |= ((uint64_t) val << (64 - bwcp->bwc_nbits - bwcp->bwc_used));
388+
// write fits exactly in current byte's remaining space, so just OR it in to
389+
// the bottom bits of the byte
390+
if (bwcp->bwc_nbits == bits_left_in_first_byte)
391+
{
392+
* bwcp->bwc_curp = (* bwcp->bwc_curp) | (uint8_t)(val);
380393

381-
// Swap the bytes back again.
382-
qw = bswap_64(qw);
394+
// consume remainder of byte and exit
395+
bwcp->bwc_used = 0;
396+
bwcp->bwc_curp += 1;
397+
return;
398+
}
383399

384-
// Write the word back out.
385-
* (uint64_t *) bwcp->bwc_curp = qw;
400+
// write DOES NOT fit into current byte, so shift off all but the topmost
401+
// bits from the value and OR those into the bottom bits of the byte
402+
/* bwcp->bwc_nbits > bits_left_in_first_byte */
403+
* bwcp->bwc_curp = (* bwcp->bwc_curp) | ((uint8_t)(val >> (bwcp->bwc_nbits - bits_left_in_first_byte)));
386404

387-
// We've used some more bits now.
388-
bwcp->bwc_used += bwcp->bwc_nbits;
405+
// consume remainder of byte
406+
bwcp->bwc_used = 0;
407+
bwcp->bwc_curp += 1;
389408

390-
// Normalize the cursor.
391-
while (bwcp->bwc_used >= 8)
409+
// if there are 8 or more bits of the value left to write, write them in one
410+
// byte chunks, higher chunks first
411+
if (full_bytes_to_write > 0)
392412
{
393-
bwcp->bwc_used -= 8;
394-
bwcp->bwc_curp += 1;
413+
for (size_t i = 0; i < full_bytes_to_write; ++i)
414+
{
415+
size_t bits_to_keep = bits_left_in_first_byte + (8 * (i + 1));
416+
size_t right_shift = (bwcp->bwc_nbits - bits_to_keep);
417+
418+
// no OR here because byte is guaranteed to be completely unused
419+
// see above, before conditional
420+
* bwcp->bwc_curp = (uint8_t)(val >> right_shift);
421+
422+
// consume entire byte
423+
bwcp->bwc_used = 0;
424+
bwcp->bwc_curp += 1;
425+
}
395426
}
427+
if (remainder_bits_after_full_bytes > 0)
428+
{
429+
uint8_t mask = (1 << remainder_bits_after_full_bytes) - 1;
430+
// no OR here because byte is guaranteed to be completely unused
431+
* bwcp->bwc_curp = ((uint8_t)val & mask) << (8 - remainder_bits_after_full_bytes);
396432

433+
// consume part of the byte
434+
bwcp->bwc_used = remainder_bits_after_full_bytes;
435+
}
397436
}
398437

399438
static void

0 commit comments

Comments
 (0)