Merge pull request #721 from ilammy/aliasing-issues

Fix unaligned access in bytevector-{u,s}{16,32,64}-{ref,set!}
This commit is contained in:
Alex Shinn 2020-11-30 20:11:54 +09:00 committed by GitHub
commit 4edf3344f8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 146 additions and 36 deletions

View file

@ -234,11 +234,18 @@
(equal? (bytevector-s16-native-ref b 0)
(- 44444 65536)))))
(test-assert "bytevector-s16-{ref,set!} [unaligned]"
(let ((b (make-bytevector 3)))
(test-assert "bytevector-{u16,s16}-{ref,set!} [unaligned]"
(let ((b (make-bytevector 5)))
(bytevector-s16-set! b 1 -77 (endianness little))
(equal? (bytevector-s16-ref b 1 (endianness little))
-77)))
(bytevector-s16-set! b 3 -77 (endianness big))
(and (equal? (bytevector-s16-ref b 1 (endianness little))
-77)
(equal? (bytevector-u16-ref b 1 (endianness little))
(- 65536 77))
(equal? (bytevector-s16-ref b 3 (endianness big))
-77)
(equal? (bytevector-u16-ref b 3 (endianness big))
(- 65536 77)))))
(test-end)
(test-begin "2.6 Operations on 32-bit Integers")
@ -276,6 +283,19 @@
2222222222)
(equal? (bytevector-s32-native-ref b 0)
(- 2222222222 (expt 2 32))))))
(test-assert "bytevector-{u32,s32}-{ref,set!} [unaligned]"
(let ((b (make-bytevector 9)))
(bytevector-s32-set! b 1 -77777 (endianness little))
(bytevector-s32-set! b 5 -77777 (endianness big))
(and (equal? (bytevector-s32-ref b 1 (endianness little))
-77777)
(equal? (bytevector-u32-ref b 1 (endianness little))
(- (expt 2 32) 77777))
(equal? (bytevector-s32-ref b 5 (endianness big))
-77777)
(equal? (bytevector-u32-ref b 5 (endianness big))
(- (expt 2 32) 77777)))))
(test-end)
(test-begin "2.7 Operations on 64-bit Integers")
@ -314,6 +334,18 @@
(bytevector-u64-set! b 0 0 (endianness big))
(= 0 (bytevector-u64-ref b 0 (endianness big)))))
(test-assert "bytevector-{u64,s64}-{ref,set!} [unaligned]"
(let ((b (make-bytevector 17)))
(bytevector-s64-set! b 1 -7777777777 (endianness little))
(bytevector-s64-set! b 9 -7777777777 (endianness big))
(and (equal? (bytevector-s64-ref b 1 (endianness little))
-7777777777)
(equal? (bytevector-u64-ref b 1 (endianness little))
(- (expt 2 64) 7777777777))
(equal? (bytevector-s64-ref b 9 (endianness big))
-7777777777)
(equal? (bytevector-u64-ref b 9 (endianness big))
(- (expt 2 64) 7777777777)))))
(test-end)
(test-begin "2.8 Operations on IEEE-754 Representations")
@ -375,6 +407,14 @@
(bytevector-ieee-double-set! b 8 number (endianness big))
(equal? (bytevector-ieee-double-ref b 0 (endianness little))
(bytevector-ieee-double-ref b 8 (endianness big)))))
(test-assert "bytevector-ieee-double-{ref,set!} [unaligned]"
(let ((b (make-bytevector 17))
(number 3.14))
(bytevector-ieee-double-set! b 1 number (endianness little))
(bytevector-ieee-double-set! b 9 number (endianness big))
(equal? (bytevector-ieee-double-ref b 1 (endianness little))
(bytevector-ieee-double-ref b 9 (endianness big)))))
(test-end)

View file

@ -50,6 +50,76 @@ static double sexp_swap_double(const double x) {
return y;
}
/* 16-bit integers */
static inline int16_t ref_s16(const void* p) {
int16_t v;
memcpy(&v, p, sizeof(v));
return v;
}
static inline uint16_t ref_u16(const void* p) {
uint16_t v;
memcpy(&v, p, sizeof(v));
return v;
}
static inline void set_s16(void* p, int16_t v) {
memcpy(p, &v, sizeof(v));
}
static inline void set_u16(void* p, uint16_t v) {
memcpy(p, &v, sizeof(v));
}
/* 32-bit integers */
static inline int32_t ref_s32(const void* p) {
int32_t v;
memcpy(&v, p, sizeof(v));
return v;
}
static inline uint32_t ref_u32(const void* p) {
uint32_t v;
memcpy(&v, p, sizeof(v));
return v;
}
static inline void set_s32(void* p, int32_t v) {
memcpy(p, &v, sizeof(v));
}
static inline void set_u32(void* p, uint32_t v) {
memcpy(p, &v, sizeof(v));
}
/* 64-bit integers */
static inline int64_t ref_s64(const void* p) {
int64_t v;
memcpy(&v, p, sizeof(v));
return v;
}
static inline uint64_t ref_u64(const void* p) {
uint64_t v;
memcpy(&v, p, sizeof(v));
return v;
}
static inline void set_s64(void* p, int64_t v) {
memcpy(p, &v, sizeof(v));
}
static inline void set_u64(void* p, uint64_t v) {
memcpy(p, &v, sizeof(v));
}
/* 32-bit floats */
static inline float ref_f32(const void* p) {
float v;
memcpy(&v, p, sizeof(v));
return v;
}
static inline void set_f32(void* p, float v) {
memcpy(p, &v, sizeof(v));
}
/* 64-bit floats */
static inline double ref_f64(const void* p) {
double v;
memcpy(&v, p, sizeof(v));
return v;
}
static inline void set_f64(void* p, double v) {
memcpy(p, &v, sizeof(v));
}
sexp_sint_t decode_utf8(unsigned char* p, int ch_len) {
if (ch_len <= 1)
return *p;
@ -222,101 +292,101 @@ sexp utf32_2_str(sexp ctx, char* bv, int len, sexp endianness, int endianness_ma
(inline "((int8_t*)arg0)[arg1] = arg2"))
(define-c int16_t bytevector-s16-native-ref (bytevector int)
(inline "*((int16_t*)(arg0+arg1))"))
(inline "ref_s16(arg0+arg1)"))
(define-c void bytevector-s16-native-set! (bytevector int int16_t)
(assert (< -1 arg1 (bytevector-length arg0)))
(inline "*((int16_t*)(arg0+arg1)) = arg2"))
(inline "set_s16(arg0+arg1, arg2)"))
(define-c int16_t bytevector-s16-ref ((value ctx sexp) bytevector int sexp)
(inline "(arg3 == sexp_global(arg0, SEXP_G_ENDIANNESS) ? *((int16_t*)(arg1+arg2)) : sexp_swap_s16(*((int16_t*)(arg1+arg2))))"))
(inline "(arg3 == sexp_global(arg0, SEXP_G_ENDIANNESS) ? ref_s16(arg1+arg2) : sexp_swap_s16(ref_s16(arg1+arg2)))"))
(define-c void bytevector-s16-set! ((value ctx sexp) bytevector int int16_t sexp)
(assert (< -1 arg2 (bytevector-length arg1)))
(inline "*((int16_t*)(arg1+arg2)) = (arg4 == sexp_global(arg0, SEXP_G_ENDIANNESS) ? arg3 : sexp_swap_s16(arg3))"))
(inline "set_s16(arg1+arg2, (arg4 == sexp_global(arg0, SEXP_G_ENDIANNESS) ? arg3 : sexp_swap_s16(arg3)))"))
(define-c int32_t bytevector-s32-native-ref (bytevector int)
(inline "*((int32_t*)(arg0+arg1))"))
(inline "ref_s32(arg0+arg1)"))
(define-c void bytevector-s32-native-set! (bytevector int int32_t)
(assert (< -1 arg1 (bytevector-length arg0)))
(inline "*((int32_t*)(arg0+arg1)) = arg2"))
(inline "set_s32(arg0+arg1, arg2)"))
(define-c int32_t bytevector-s32-ref ((value ctx sexp) bytevector int sexp)
(inline "(arg3 == sexp_global(arg0, SEXP_G_ENDIANNESS) ? *((int32_t*)(arg1+arg2)) : sexp_swap_s32(*((int32_t*)(arg1+arg2))))"))
(inline "(arg3 == sexp_global(arg0, SEXP_G_ENDIANNESS) ? ref_s32(arg1+arg2) : sexp_swap_s32(ref_s32(arg1+arg2)))"))
(define-c void bytevector-s32-set! ((value ctx sexp) bytevector int int32_t sexp)
(assert (< -1 arg2 (bytevector-length arg1)))
(inline "*((int32_t*)(arg1+arg2)) = (arg4 == sexp_global(arg0, SEXP_G_ENDIANNESS) ? arg3 : sexp_swap_s32(arg3))"))
(inline "set_s32(arg1+arg2, (arg4 == sexp_global(arg0, SEXP_G_ENDIANNESS) ? arg3 : sexp_swap_s32(arg3)))"))
(define-c int64_t bytevector-s64-native-ref (bytevector int)
(inline "*((int64_t*)(arg0+arg1))"))
(inline "ref_s64(arg0+arg1)"))
(define-c void bytevector-s64-native-set! (bytevector int int64_t)
(assert (< -1 arg1 (bytevector-length arg0)))
(inline "*((int64_t*)(arg0+arg1)) = arg2"))
(inline "set_s64(arg0+arg1, arg2)"))
(define-c int64_t bytevector-s64-ref ((value ctx sexp) bytevector int sexp)
(inline "(arg3 == sexp_global(arg0, SEXP_G_ENDIANNESS) ? *((int64_t*)(arg1+arg2)) : sexp_swap_s64(*((int64_t*)(arg1+arg2))))"))
(inline "(arg3 == sexp_global(arg0, SEXP_G_ENDIANNESS) ? ref_s64(arg1+arg2) : sexp_swap_s64(ref_s64(arg1+arg2)))"))
(define-c void bytevector-s64-set! ((value ctx sexp) bytevector int int64_t sexp)
(assert (< -1 arg2 (bytevector-length arg1)))
(inline "*((int64_t*)(arg1+arg2)) = (arg4 == sexp_global(arg0, SEXP_G_ENDIANNESS) ? arg3 : sexp_swap_s64(arg3))"))
(inline "set_s64(arg1+arg2, (arg4 == sexp_global(arg0, SEXP_G_ENDIANNESS) ? arg3 : sexp_swap_s64(arg3)))"))
(define-c uint16_t bytevector-u16-native-ref (bytevector int)
(inline "*((uint16_t*)(arg0+arg1))"))
(inline "ref_u16(arg0+arg1)"))
(define-c void bytevector-u16-native-set! (bytevector int uint16_t)
(assert (< -1 arg1 (bytevector-length arg0)))
(inline "*((uint16_t*)(arg0+arg1)) = arg2"))
(inline "set_u16(arg0+arg1, arg2)"))
(define-c uint16_t bytevector-u16-ref ((value ctx sexp) bytevector int sexp)
(inline "(arg3 == sexp_global(arg0, SEXP_G_ENDIANNESS) ? *((uint16_t*)(arg1+arg2)) : sexp_swap_u16(*((uint16_t*)(arg1+arg2))))"))
(inline "(arg3 == sexp_global(arg0, SEXP_G_ENDIANNESS) ? ref_u16(arg1+arg2) : sexp_swap_u16(ref_u16(arg1+arg2)))"))
(define-c void bytevector-u16-set! ((value ctx sexp) bytevector int uint16_t sexp)
(assert (< -1 arg2 (bytevector-length arg1)))
(inline "*((uint16_t*)(arg1+arg2)) = (arg4 == sexp_global(arg0, SEXP_G_ENDIANNESS) ? arg3 : sexp_swap_u16(arg3))"))
(inline "set_u16(arg1+arg2, (arg4 == sexp_global(arg0, SEXP_G_ENDIANNESS) ? arg3 : sexp_swap_u16(arg3)))"))
(define-c uint32_t bytevector-u32-native-ref (bytevector int)
(inline "*((uint32_t*)(arg0+arg1))"))
(inline "ref_u32(arg0+arg1)"))
(define-c void bytevector-u32-native-set! (bytevector int uint32_t)
(assert (< -1 arg1 (bytevector-length arg0)))
(inline "*((uint32_t*)(arg0+arg1)) = arg2"))
(inline "set_u32(arg0+arg1, arg2)"))
(define-c uint32_t bytevector-u32-ref ((value ctx sexp) bytevector int sexp)
(inline "(arg3 == sexp_global(arg0, SEXP_G_ENDIANNESS) ? *((uint32_t*)(arg1+arg2)) : sexp_swap_u32(*((uint32_t*)(arg1+arg2))))"))
(inline "(arg3 == sexp_global(arg0, SEXP_G_ENDIANNESS) ? ref_u32(arg1+arg2) : sexp_swap_u32(ref_u32(arg1+arg2)))"))
(define-c void bytevector-u32-set! ((value ctx sexp) bytevector int uint32_t sexp)
(assert (< -1 arg2 (bytevector-length arg1)))
(inline "*((uint32_t*)(arg1+arg2)) = (arg4 == sexp_global(arg0, SEXP_G_ENDIANNESS) ? arg3 : sexp_swap_u32(arg3))"))
(inline "set_u32(arg1+arg2, (arg4 == sexp_global(arg0, SEXP_G_ENDIANNESS) ? arg3 : sexp_swap_u32(arg3)))"))
(define-c uint64_t bytevector-u64-native-ref (bytevector int)
(inline "*((uint64_t*)(arg0+arg1))"))
(inline "ref_u64(arg0+arg1)"))
(define-c void bytevector-u64-native-set! (bytevector int uint64_t)
(assert (< -1 arg1 (bytevector-length arg0)))
(inline "*((uint64_t*)(arg0+arg1)) = arg2"))
(inline "set_u64(arg0+arg1, arg2)"))
(define-c uint64_t bytevector-u64-ref ((value ctx sexp) bytevector int sexp)
(inline "(arg3 == sexp_global(arg0, SEXP_G_ENDIANNESS) ? *((uint64_t*)(arg1+arg2)) : sexp_swap_u64(*((uint64_t*)(arg1+arg2))))"))
(inline "(arg3 == sexp_global(arg0, SEXP_G_ENDIANNESS) ? ref_u64(arg1+arg2) : sexp_swap_u64(ref_u64(arg1+arg2)))"))
(define-c void bytevector-u64-set! ((value ctx sexp) bytevector int uint64_t sexp)
(assert (< -1 arg2 (bytevector-length arg1)))
(inline "*((uint64_t*)(arg1+arg2)) = (arg4 == sexp_global(arg0, SEXP_G_ENDIANNESS) ? arg3 : sexp_swap_u64(arg3))"))
(inline "set_u64(arg1+arg2, (arg4 == sexp_global(arg0, SEXP_G_ENDIANNESS) ? arg3 : sexp_swap_u64(arg3)))"))
(define-c float bytevector-ieee-single-native-ref (bytevector int)
(inline "*((float*)(arg0+arg1))"))
(inline "ref_f32(arg0+arg1)"))
(define-c void bytevector-ieee-single-native-set! (bytevector int float)
(assert (< -1 arg1 (bytevector-length arg0)))
(inline "*((float*)(arg0+arg1)) = arg2"))
(inline "set_f32(arg0+arg1, arg2)"))
(define-c float bytevector-ieee-single-ref ((value ctx sexp) bytevector int sexp)
(inline "(arg3 == sexp_global(arg0, SEXP_G_ENDIANNESS) ? *((float*)(arg1+arg2)) : sexp_swap_float(*(float*)(arg1+arg2)))"))
(inline "(arg3 == sexp_global(arg0, SEXP_G_ENDIANNESS) ? ref_f32(arg1+arg2) : sexp_swap_float(ref_f32(arg1+arg2)))"))
(define-c void bytevector-ieee-single-set! ((value ctx sexp) bytevector int float sexp)
(assert (< -1 arg2 (bytevector-length arg1)))
(inline "*((float*)(arg1+arg2)) = (arg4 == sexp_global(arg0, SEXP_G_ENDIANNESS) ? arg3 : sexp_swap_float(arg3))"))
(inline "set_f32(arg1+arg2, (arg4 == sexp_global(arg0, SEXP_G_ENDIANNESS) ? arg3 : sexp_swap_float(arg3)))"))
(define-c double bytevector-ieee-double-native-ref (bytevector int)
(inline "*((double*)(arg0+arg1))"))
(inline "ref_f64(arg0+arg1)"))
(define-c void bytevector-ieee-double-native-set! (bytevector int double)
(assert (< -1 arg1 (bytevector-length arg0)))
(inline "*((double*)(arg0+arg1)) = arg2"))
(inline "set_f64(arg0+arg1, arg2)"))
(define-c double bytevector-ieee-double-ref ((value ctx sexp) bytevector int sexp)
(inline "(arg3 == sexp_global(arg0, SEXP_G_ENDIANNESS) ? *((double*)(arg1+arg2)) : sexp_swap_double(*(double*)(arg1+arg2)))"))
(inline "(arg3 == sexp_global(arg0, SEXP_G_ENDIANNESS) ? ref_f64(arg1+arg2) : sexp_swap_double(ref_f64(arg1+arg2)))"))
(define-c void bytevector-ieee-double-set! ((value ctx sexp) bytevector int double sexp)
(assert (< -1 arg2 (bytevector-length arg1)))
(inline "*((double*)(arg1+arg2)) = (arg4 == sexp_global(arg0, SEXP_G_ENDIANNESS) ? arg3 : sexp_swap_double(arg3))"))
(inline "set_f64(arg1+arg2, (arg4 == sexp_global(arg0, SEXP_G_ENDIANNESS) ? arg3 : sexp_swap_double(arg3)))"))
(define-c sexp (%string->utf16 "str2utf16")
((value ctx sexp) string (value (string-size arg1) int) (default (native-endianness) sexp)))