~ chicken-core (chicken-5) a3f09e53101c34fd161dc00e04f575304ffd5be3
commit a3f09e53101c34fd161dc00e04f575304ffd5be3 Author: Peter Bex <peter@more-magic.net> AuthorDate: Tue May 26 22:38:44 2015 +0200 Commit: Peter Bex <peter@more-magic.net> CommitDate: Sun May 31 14:56:14 2015 +0200 Also perform range checks on foreign integer argument types. Enforce integers to lie within the range representable by the foreign type. This simplifies runtime a little by passing the size in bits to the checking procedure. This allows us to replace the four procedures sys#foreign-[unsigned-]integer[64]-argument with the two procedures sys#foreign-[unsigned-]ranged-integer-argument. This is more correct for highly system-dependent types like size_t, which may be 32 bits or 64 bits on different systems. Otherwise, we would have to add these 8 missing procedures: - sys#foreign-[unsigned-]integer32-argument - sys#foreign-[unsigned-]short-argument - sys#foreign-[unsigned-]long-argument - sys#foreign-[unsigned-]size_t-argument diff --git a/c-platform.scm b/c-platform.scm index 8e4525eb..62df0f4f 100644 --- a/c-platform.scm +++ b/c-platform.scm @@ -196,7 +196,7 @@ ##sys#foreign-char-argument ##sys#foreign-fixnum-argument ##sys#foreign-flonum-argument ##sys#foreign-block-argument ##sys#foreign-struct-wrapper-argument ##sys#foreign-string-argument ##sys#foreign-pointer-argument ##sys#void - ##sys#foreign-integer-argument ##sys#foreign-unsigned-integer-argument + ##sys#foreign-ranged-integer-argument ##sys#foreign-unsigned-ranged-integer-argument ##sys#peek-fixnum ##sys#setislot ##sys#poke-integer ##sys#permanent? ##sys#values ##sys#poke-double ##sys#intern-symbol ##sys#make-symbol ##sys#null-pointer? ##sys#peek-byte ##sys#file-exists? ##sys#substring-index ##sys#substring-index-ci ##sys#lcm ##sys#gcd)) @@ -818,8 +818,8 @@ (rewrite '##sys#foreign-struct-wrapper-argument 17 2 "C_i_foreign_struct_wrapper_argumentp") (rewrite '##sys#foreign-string-argument 17 1 "C_i_foreign_string_argumentp") (rewrite '##sys#foreign-pointer-argument 17 1 "C_i_foreign_pointer_argumentp") -(rewrite '##sys#foreign-integer-argument 17 1 "C_i_foreign_integer_argumentp") -(rewrite '##sys#foreign-unsigned-integer-argument 17 1 "C_i_foreign_unsigned_integer_argumentp") +(rewrite '##sys#foreign-ranged-integer-argument 17 2 "C_i_foreign_ranged_integer_argumentp") +(rewrite '##sys#foreign-unsigned-ranged-integer-argument 17 2 "C_i_foreign_unsigned_ranged_integer_argumentp") (rewrite '##sys#direct-return 17 2 "C_direct_return") (rewrite 'blob-size 2 1 "C_block_size" #f) diff --git a/chicken.h b/chicken.h index f268077f..0b7bd0b0 100644 --- a/chicken.h +++ b/chicken.h @@ -2200,10 +2200,16 @@ C_fctexport C_word C_fcall C_i_foreign_symbol_argumentp(C_word x) C_regparm; C_fctexport C_word C_fcall C_i_foreign_tagged_pointer_argumentp(C_word x, C_word t) C_regparm; C_fctexport C_word C_fcall C_i_foreign_pointer_argumentp(C_word x) C_regparm; C_fctexport C_word C_fcall C_i_foreign_scheme_or_c_pointer_argumentp(C_word x) C_regparm; +/* XXX TODO OBSOLETE: This can be removed after recompiling c-platform.scm */ C_fctexport C_word C_fcall C_i_foreign_integer_argumentp(C_word x) C_regparm; +/* XXX TODO OBSOLETE: This can be removed after recompiling c-platform.scm */ C_fctexport C_word C_fcall C_i_foreign_unsigned_integer_argumentp(C_word x) C_regparm; +/* XXX TODO OBSOLETE: This can be removed after recompiling c-platform.scm */ C_fctexport C_word C_fcall C_i_foreign_integer64_argumentp(C_word x) C_regparm; +/* XXX TODO OBSOLETE: This can be removed after recompiling c-platform.scm */ C_fctexport C_word C_fcall C_i_foreign_unsigned_integer64_argumentp(C_word x) C_regparm; +C_fctexport C_word C_fcall C_i_foreign_ranged_integer_argumentp(C_word x, C_word bits) C_regparm; +C_fctexport C_word C_fcall C_i_foreign_unsigned_ranged_integer_argumentp(C_word x, C_word bits) C_regparm; C_fctexport C_char *C_lookup_procedure_id(void *ptr); C_fctexport void *C_lookup_procedure_ptr(C_char *id); diff --git a/library.scm b/library.scm index be457081..caac0830 100644 --- a/library.scm +++ b/library.scm @@ -5130,14 +5130,19 @@ EOF (define (##sys#foreign-pointer-argument x) (##core#inline "C_i_foreign_pointer_argumentp" x)) (define (##sys#foreign-tagged-pointer-argument x tx) (##core#inline "C_i_foreign_tagged_pointer_argumentp" x tx)) (define (##sys#foreign-integer-argument x) (##core#inline "C_i_foreign_integer_argumentp" x)) +;; OBSOLETE (define (##sys#foreign-integer64-argument x) (##core#inline "C_i_foreign_integer64_argumentp" x)) - +;; OBSOLETE (define (##sys#foreign-unsigned-integer-argument x) (##core#inline "C_i_foreign_unsigned_integer_argumentp" x)) - +;; OBSOLETE (define (##sys#foreign-unsigned-integer64-argument x) (##core#inline "C_i_foreign_unsigned_integer64_argumentp" x)) +(define (##sys#foreign-ranged-integer-argument obj size) + (##core#inline "C_i_foreign_ranged_integer_argumentp" obj size)) +(define (##sys#foreign-unsigned-ranged-integer-argument obj size) + (##core#inline "C_i_foreign_unsigned_ranged_integer_argumentp" obj size)) ;;; Low-level threading interface: diff --git a/runtime.c b/runtime.c index 717f2d58..bbd16f6e 100644 --- a/runtime.c +++ b/runtime.c @@ -5885,6 +5885,19 @@ C_regparm C_word C_fcall C_a_i_bitwise_xor(C_word **a, int c, C_word n1, C_word else return C_flonum(a, nn1); } +/* Faster version that ignores sign in bignums. TODO: Omit labs() too? */ +C_inline int integer_length_abs(C_word x) +{ + if (x & C_FIXNUM_BIT) { + return C_ilen(labs(C_unfix(x))); + } else { + C_uword result = (C_bignum_size(x) - 1) * C_BIGNUM_DIGIT_LENGTH, + *last_digit = C_bignum_digits(x) + C_bignum_size(x) - 1, + last_digit_length = C_ilen(*last_digit); + return result + last_digit_length; + } +} + C_regparm C_word C_fcall C_i_integer_length(C_word x) { if (x & C_FIXNUM_BIT) { @@ -6931,7 +6944,36 @@ C_regparm C_word C_fcall C_i_foreign_tagged_pointer_argumentp(C_word x, C_word t return x; } +C_regparm C_word C_fcall C_i_foreign_ranged_integer_argumentp(C_word x, C_word bits) +{ + if((x & C_FIXNUM_BIT) != 0) { + if (C_truep(C_fixnum_lessp(C_i_fixnum_length(x), bits))) return x; + else barf(C_BAD_ARGUMENT_TYPE_FOREIGN_LIMITATION, NULL, x); + } else if (C_truep(C_i_bignump(x))) { + if (C_truep(C_fixnum_lessp(C_i_integer_length(x), bits))) return x; + else barf(C_BAD_ARGUMENT_TYPE_FOREIGN_LIMITATION, NULL, x); + } else { + barf(C_BAD_ARGUMENT_TYPE_NO_INTEGER_ERROR, NULL, x); + } +} + +/* XXX TODO OBSOLETE: This can be removed after recompiling c-platform.scm */ +C_regparm C_word C_fcall C_i_foreign_unsigned_ranged_integer_argumentp(C_word x, C_word bits) +{ + if((x & C_FIXNUM_BIT) != 0) { + if(x & C_INT_SIGN_BIT) barf(C_BAD_ARGUMENT_TYPE_NO_UINTEGER_ERROR, NULL, x); + else if(C_ilen(C_unfix(x)) <= C_unfix(bits)) return x; + else barf(C_BAD_ARGUMENT_TYPE_FOREIGN_LIMITATION, NULL, x); + } else if(C_truep(C_i_bignump(x))) { + if(C_bignum_negativep(x)) barf(C_BAD_ARGUMENT_TYPE_NO_UINTEGER_ERROR, NULL, x); + else if(integer_length_abs(x) <= C_unfix(bits)) return x; + else barf(C_BAD_ARGUMENT_TYPE_FOREIGN_LIMITATION, NULL, x); + } else { + barf(C_BAD_ARGUMENT_TYPE_NO_UINTEGER_ERROR, NULL, x); + } +} +/* XXX TODO OBSOLETE: This can be removed after recompiling c-platform.scm */ C_regparm C_word C_fcall C_i_foreign_integer_argumentp(C_word x) { double m; @@ -6955,6 +6997,7 @@ C_regparm C_word C_fcall C_i_foreign_integer_argumentp(C_word x) } +/* XXX TODO OBSOLETE: This can be removed after recompiling c-platform.scm */ C_regparm C_word C_fcall C_i_foreign_integer64_argumentp(C_word x) { double m, r; @@ -6982,6 +7025,7 @@ C_regparm C_word C_fcall C_i_foreign_integer64_argumentp(C_word x) } +/* XXX TODO OBSOLETE: This can be removed after recompiling c-platform.scm */ C_regparm C_word C_fcall C_i_foreign_unsigned_integer_argumentp(C_word x) { double m ,r; @@ -6993,7 +7037,6 @@ C_regparm C_word C_fcall C_i_foreign_unsigned_integer_argumentp(C_word x) else barf(C_BAD_ARGUMENT_TYPE_FOREIGN_LIMITATION, NULL, x); } - /* XXX OBSOLETE: This should be removed on the next round */ if(!C_immediatep(x) && C_block_header(x) == C_FLONUM_TAG) { m = C_flonum_magnitude(x); @@ -7004,7 +7047,7 @@ C_regparm C_word C_fcall C_i_foreign_unsigned_integer_argumentp(C_word x) return C_SCHEME_UNDEFINED; } - +/* XXX TODO OBSOLETE: This can be removed after recompiling c-platform.scm */ C_regparm C_word C_fcall C_i_foreign_unsigned_integer64_argumentp(C_word x) { double m, r; @@ -7020,7 +7063,6 @@ C_regparm C_word C_fcall C_i_foreign_unsigned_integer64_argumentp(C_word x) else barf(C_BAD_ARGUMENT_TYPE_FOREIGN_LIMITATION, NULL, x); } - /* XXX OBSOLETE: This should be removed on the next round */ if(!C_immediatep(x) && C_block_header(x) == C_FLONUM_TAG) { m = C_flonum_magnitude(x); @@ -8628,18 +8670,6 @@ bignum_divrem(C_word **ptr, C_word x, C_word y, C_word *q, C_word *r) } } -C_inline int integer_length_abs(C_word x) -{ - if (x & C_FIXNUM_BIT) { - return C_ilen(labs(C_unfix(x))); - } else { - C_uword result = (C_bignum_size(x) - 1) * C_BIGNUM_DIGIT_LENGTH, - *last_digit = C_bignum_digits(x) + C_bignum_size(x) - 1, - last_digit_length = C_ilen(*last_digit); - return result + last_digit_length; - } -} - /* Burnikel-Ziegler recursive division: Split high number (x) in three * or four parts and divide by the lowest number (y), split in two * parts. There are descriptions in [MpNT, 4.2], [MCA, 1.4.3] and the diff --git a/support.scm b/support.scm index 4cd67379..580d91d8 100644 --- a/support.scm +++ b/support.scm @@ -956,7 +956,13 @@ (nonnull-s8vector . s8vector) (nonnull-s16vector . s16vector) (nonnull-u32vector . u32vector) (nonnull-s32vector . s32vector) (nonnull-u64vector . u64vector) (nonnull-s64vector . s64vector) - (nonnull-f32vector . f32vector) (nonnull-f64vector . f64vector)))) + (nonnull-f32vector . f32vector) (nonnull-f64vector . f64vector))) + (ftmap '((integer . "int") (unsigned-integer . "unsigned int") + (integer32 . "C_s32") (unsigned-integer32 . "C_u32") + (integer64 . "C_s64") (unsigned-integer64 . "C_u64") + (short . "short") (unsigned-short . "unsigned short") + (long . "long") (unsigned-long . "unsigned long") + (size_t . "size_t")))) (lambda (param type) (follow-without-loop type @@ -964,7 +970,8 @@ (let repeat ((t t)) (case t ((char unsigned-char) (if unsafe param `(##sys#foreign-char-argument ,param))) - ((int unsigned-int short unsigned-short byte unsigned-byte int32 unsigned-int32) + ;; TODO: Should "[unsigned-]byte" be range checked? + ((int unsigned-int byte unsigned-byte int32 unsigned-int32) (if unsafe param `(##sys#foreign-fixnum-argument ,param))) ((float double number) (if unsafe param `(##sys#foreign-flonum-argument ,param))) ((blob scheme-pointer) @@ -1010,18 +1017,21 @@ `(##sys#foreign-struct-wrapper-argument ',(##sys#slot (assq t tmap) 1) ,param) ) ) - ((integer long size_t integer32) - (if unsafe param `(##sys#foreign-integer-argument ,param))) - ((integer64) - (if unsafe param `(##sys#foreign-integer64-argument ,param))) - ((unsigned-integer unsigned-integer32 unsigned-long) - (if unsafe - param - `(##sys#foreign-unsigned-integer-argument ,param) ) ) - ((unsigned-integer64) - (if unsafe - param - `(##sys#foreign-unsigned-integer64-argument ,param) ) ) + ((integer32 integer64 integer short long size_t) + (let* ((foreign-type (##sys#slot (assq t ftmap) 1)) + (size-expr (sprintf "sizeof(~A) * CHAR_BIT" foreign-type))) + (if unsafe + param + `(##sys#foreign-ranged-integer-argument + ,param (foreign-value ,size-expr int))))) + ((unsigned-short unsigned-long unsigned-integer + unsigned-integer32 unsigned-integer64) + (let* ((foreign-type (##sys#slot (assq t ftmap) 1)) + (size-expr (sprintf "sizeof(~A) * CHAR_BIT" foreign-type))) + (if unsafe + param + `(##sys#foreign-unsigned-ranged-integer-argument + ,param (foreign-value ,size-expr int))))) ((c-pointer c-string-list c-string-list*) (let ((tmp (gensym))) `(let ((,tmp ,param)) diff --git a/tests/compiler-tests.scm b/tests/compiler-tests.scm index f79fda54..42cb0256 100644 --- a/tests/compiler-tests.scm +++ b/tests/compiler-tests.scm @@ -275,15 +275,14 @@ (eqv? (sub1 limit) ((foreign-lambda* ?type-name ((?type-name x)) "C_return(x);") (sub1 limit)))) - ;; TODO: Should we test for these? - #;(print "Cannot hold one more than maximum value, " limit "...") - #;(assert + (print "Cannot hold one more than maximum value, " limit "...") + (assert (handle-exceptions exn #t (begin ((foreign-lambda* ?type-name ((?type-name x)) "C_return(x);") limit) #f))) - #;(print "Cannot hold -1 (any fixnum negative value)") - #;(assert + (print "Cannot hold -1 (any fixnum negative value)") + (assert (handle-exceptions exn #t (begin ((foreign-lambda* ?type-name ((?type-name x)) "C_return(x);") -1) @@ -307,17 +306,16 @@ (eqv? (- limit) ((foreign-lambda* ?type-name ((?type-name x)) "C_return(x);") (- limit)))) - ;; TODO: Should we check for these? - #;(print "Cannot hold one more than maximum value " limit "...") - #;(assert + (print "Cannot hold one more than maximum value " limit "...") + (assert (handle-exceptions exn #t - (begin ((foreign-lambda* integer ((integer x)) + (begin ((foreign-lambda* ?type-name ((?type-name x)) "C_return(x);") limit) #f))) - #;(print "Cannot hold one less than minimum value " (- limit) "...") - #;(assert + (print "Cannot hold one less than minimum value " (- limit) "...") + (assert (handle-exceptions exn #t - (begin ((foreign-lambda* integer ((integer x)) + (begin ((foreign-lambda* ?type-name ((?type-name x)) "C_return(x);") (sub1 (- limit))) #f)))))))Trap