Skip to content

Commit

Permalink
🐛 fix wrong bigint due to alignment (#6)
Browse files Browse the repository at this point in the history
  • Loading branch information
no2chem authored Sep 18, 2018
1 parent 012cb23 commit c364b0c
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 73 deletions.
86 changes: 35 additions & 51 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "bigint-buffer",
"version": "1.1.0",
"version": "1.1.1",
"description": "bigint to buffer conversion with native support",
"main": "dist/node.js",
"browser": {
Expand Down Expand Up @@ -52,7 +52,7 @@
"benchmark": "^2.1.4",
"chai": "^4.1.2",
"coveralls": "^3.0.2",
"gts": "^0.5.4",
"gts": "^0.8.0",
"istanbul": "^0.4.1",
"karma": "^3.0.0",
"karma-chrome-launcher": "^2.2.0",
Expand All @@ -73,7 +73,7 @@
"webpack-cli": "^3.1.0"
},
"engines": {
"node": ">= 0.10.0"
"node": ">= 10.0.0"
},
"publishConfig": {
"access": "public"
Expand Down
38 changes: 19 additions & 19 deletions src/bigint-buffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,53 +43,53 @@ napi_value toBigInt (napi_env env, napi_callback_info info) {
assert(status == napi_ok);

// If len is not divisible by 8 bytes, we'll need to copy
bool not_64_aligned = len & 7;
bool fits_in_stack = len <= BUFFER_STACK_SIZE;
size_t overflow_len = (8 - (len & 7));
bool not_64_aligned = (len & 7) != 0;
size_t overflow_len = not_64_aligned ? 8 - (len & 0x7) : 0;
// Buffer is managed by VM, so copy it out (TODO: perhaps we can increase refcount?)
size_t aligned_len = len + overflow_len;
size_t len_in_words = not_64_aligned ? (len >> 3) + 1 : (len >> 3);
bool fits_in_stack = aligned_len <= BUFFER_STACK_SIZE;

uint8_t copy[BUFFER_STACK_SIZE];
uint8_t* bufTemp = fits_in_stack ? copy : malloc(aligned_len);
memset(bufTemp + len, 0, overflow_len);
if (overflow_len > 0) {
memset(bufTemp + len, 0, overflow_len);
}
memcpy(bufTemp, buffer, len);
buffer = bufTemp;
uint64_t* as_64_aligned = (uint64_t*) bufTemp;
size_t overflow_in_bits = overflow_len << 3; // == overflow_len * 8

napi_value out;
size_t len_in_words = (len >> 3) // Right Shift 3 === Divide by 8
+ ((len & 7) ? 1 : 0); // len & 7 === len % 8 === 0?

// swap
if (big_endian) {
uint64_t* buffer64 = (uint64_t*) buffer;
size_t overflow_in_bits = overflow_len << 3; // == overflow_len * 8
if (len_in_words == 1) {
buffer64[0] = not_64_aligned ? __builtin_bswap64(buffer64[0]) >> overflow_in_bits : __builtin_bswap64(buffer64[0]);
as_64_aligned[0] = not_64_aligned ? __builtin_bswap64(as_64_aligned[0]) >> overflow_in_bits : __builtin_bswap64(as_64_aligned[0]);
} else {
uint64_t temp;
size_t last_word = len_in_words - 1;
size_t end_ptr = last_word;
int32_t offset;
for (offset = 0; offset < (int32_t)(len_in_words / 2); offset++) {
temp = buffer64[offset];
buffer64[offset] = buffer64[end_ptr];
buffer64[end_ptr] = temp;
temp = as_64_aligned[offset];
as_64_aligned[offset] = as_64_aligned[end_ptr];
as_64_aligned[end_ptr] = temp;
end_ptr--;
}
uint64_t prev_overflow = 0;
for (offset = last_word; offset >= 0; offset--) {
uint64_t as_little_endian = __builtin_bswap64(buffer64[offset]);
uint64_t overflow = as_little_endian & BIT_MASK(overflow_in_bits); //top?
buffer64[offset] = (as_little_endian >> overflow_in_bits) | prev_overflow;
uint64_t as_little_endian = __builtin_bswap64(as_64_aligned[offset]);
uint64_t overflow = as_little_endian & BIT_MASK(overflow_in_bits);
as_64_aligned[offset] = not_64_aligned ? (as_little_endian >> overflow_in_bits) | prev_overflow : as_little_endian;
prev_overflow = overflow << (64 - overflow_in_bits);
}
}
}

status = napi_create_bigint_words(env, 0, len_in_words, (uint64_t*) buffer , &out);
status = napi_create_bigint_words(env, 0, len_in_words, as_64_aligned , &out);
assert(status == napi_ok);

if (!fits_in_stack) {
free(buffer);
free(bufTemp);
}

return out;
Expand Down
29 changes: 29 additions & 0 deletions src/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,26 @@ describe('Try buffer conversion (little endian)', () => {
])),
BigInt(`0xbadc0ffee0ddf00ddeadbeef`));
});
it('0xbadc0ffee0ddf00ddeadbeefbadc0ffee0ddf00ddeadbeef should equal 0xbadc0ffee0ddf00ddeadbeefbadc0ffee0ddf00ddeadbeefn',
async () => {
assertEquals(
toBigIntLE(Buffer.from([
0xef, 0xbe, 0xad, 0xde, 0x0d, 0xf0, 0xdd, 0xe0,
0xfe, 0x0f, 0xdc, 0xba, 0xef, 0xbe, 0xad, 0xde,
0x0d, 0xf0, 0xdd, 0xe0, 0xfe, 0x0f, 0xdc, 0xba
])),
BigInt(`0xbadc0ffee0ddf00ddeadbeefbadc0ffee0ddf00ddeadbeef`));
});
it('0xbadc0ffee0ddf00ddeadbeefbadc0ffee0ddf00ddeadbeefbeef should equal 0xbadc0ffee0ddf00ddeadbeefbadc0ffee0ddf00ddeadbeefbeefn',
async () => {
assertEquals(
toBigIntLE(Buffer.from([
0xef, 0xbe, 0xef, 0xbe, 0xad, 0xde, 0x0d, 0xf0, 0xdd,
0xe0, 0xfe, 0x0f, 0xdc, 0xba, 0xef, 0xbe, 0xad, 0xde,
0x0d, 0xf0, 0xdd, 0xe0, 0xfe, 0x0f, 0xdc, 0xba
])),
BigInt(`0xbadc0ffee0ddf00ddeadbeefbadc0ffee0ddf00ddeadbeefbeef`));
});
});

describe('Try buffer conversion (big endian)', () => {
Expand Down Expand Up @@ -138,6 +158,15 @@ describe('Try buffer conversion (big endian)', () => {
BigInt(
`0xbadc0ffee0ddf00ddeadbeefbadc0ffee0ddf00ddeadbeefbadc0ffee0ddf00ddeadbeef`));
});

it('other long value should equal long val', async () => {
assertEquals(
toBigIntBE(Buffer.from(
'd7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544',
'hex')),
BigInt(
`0xd7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544`));
});
});

describe('Try bigint conversion (little endian)', () => {
Expand Down

0 comments on commit c364b0c

Please sign in to comment.