summaryrefslogtreecommitdiffstats
path: root/ffi.c
Commit message (Collapse)AuthorAgeFilesLines
* ffi: functions and macros for basic type properties.Kaz Kylheku2017-06-021-0/+74
| | | | | | | | | | | | | | | | | | * ffi.c (ffi_alignof, ffi_offsetof, ffi_arraysize, ffi_elemsize, ffi_elemtype): New functions. (ffi_init): Registered intrinsics ffi-alignof, ffi-offsetof, ffi-arraysize, ffi-elemsize, ffi-elemtype. * ffi.h (ffi_alignof, ffi_offsetof, ffi_arraysize, ffi_elemsize, ffi_elemtype): Declared. * lisplib.c (ffi_set_entries): New autoload entries alignof, offsetof, arraysize, elemsize, elemtype. * share/txr/stdlib/ffi.tl (alignof, offsetof, arraysize, elemsize, elemtype): New macros. * txr.1: Documented new functions and macros.
* ffi: don't allow size calculation of bitfield type.Kaz Kylheku2017-06-021-0/+4
| | | | | * ffi.c (ffi_size): Check for a bitfield type and diagnose.
* ffi: new feature: enums.Kaz Kylheku2017-05-311-0/+151
| | | | | | | | | | | | | | | | * ffi.c (enum_s): New symbol variable. (struct txr_ffi_type): New member, sym_num, num_sym. (ffi_enum_type_mark): New static function. (ffi_type_enum_ops): New static structure. (ffi_enum_put, ffi_enum_get, ffi_enum_rput, ffi_enum_rget): New static functions. (make_ffi_type_enum): New static function. (ffi_type_compile): Extend with enum syntax. (ffi_init): Initialize enum_s with new interned symbol. * ffi.c (enum_s): Declared. * txr.1: Documented.
* ffi: bugfix: basic type needs proper mark function.Kaz Kylheku2017-05-311-5/+15
| | | | | | | | * ffi.c (ffi_type_common_mark, ffi_type_mark): New static function (ffi_struct_type_mark, ffi_ptr_type_mark): Use new ffi_type_common_mark function for common members. (ffi_type_builtin_ops): Wire in ffi_type_mark.
* ffi: pad retval to ffi_arg size on all platforms.Kaz Kylheku2017-05-291-4/+5
| | | | | | | | | | * ffi.c (pad_retval): Define same way regardless of big or little endian. For instance, we don't want to call alloca(1) for a char return value. It could be the case on little endian targets that libffi prepares an entire ffi_arg return value. Even though we just read the low order byte, we still have to prepare enough space for the whole thing.
* ffi: bugfix: null out return value to padded size.Kaz Kylheku2017-05-281-1/+1
| | | | | | | * ffi.c (ffi_closure_dispatch_safe): In the abort case when we put zeros in the return value, we must overwrite the entire ffi_arg cell, in adherence with the special return value quirk of libffi.
* ffi: adapt to return value braindamage in libffi.Kaz Kylheku2017-05-281-41/+301
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This change gets TXR FFI working on Power PC 64, big endian. Many thanks to the GCC Compile Farm. Turns out, the libffi API has changed some years ago, with outdated documentation lingering. Return values for the basic integral types must all be handled with a buffer of type ffi_arg and casting. This is true in both ffi_call and closures: in both directions. For instance, if a foreign function returns char, we must retrieve a ffi_arg value (which might be as large as 64 bits). Then we must cast this value to char. In actual fact, on a big endian system with an 8 byte ffi_arg, the char value may be located in byte 7 of the 8 byte buffer, not in byte 0. FFI's own test suite got this wrong and had to be patched back in 2013: it was doing things the way we are doing them: https://sourceware.org/ml/libffi-discuss/2013/msg00199.html The doc was updated at the same time to tell the truth: https://sourceware.org/ml/libffi-discuss/2013/msg00200.html Luckily, we can fix TXR's ffi module without damaging its framework. The object model is flexible enough to absorb the change. Basically, we add two new methods to the txr_ffi_type objects: virtual functions rget and rput. We only add these when targetting big endian. These have the same type signature as get and put, but are specialized for handling return values. For all integer types smaller than 64 bits, these functions are separately implemented with distinct semanics which handle the FFI API requirements with ffi_arg and casting and all. For all other types, rget and rput are identical to get and put. * ffi.c (pad_retval, ifbe, ifbe2): New macros, conditionally defined for big and little endian. (struct txr_ffi_type): New members rput and rget. (ffi_i8_rput, ffi_i8_rget, ffi_u8_rput, ffi_u8_rget, ffi_i16_rput, ffi_i16_rget, ffi_u16_rput, ffi_u16_rget, ffi_i32_rput, ffi_i32_rget, ffi_u32_rput, ffi_u32_rget, ffi_char_rput, ffi_char_rget, ffi_uchar_rput, ffi_uchar_rget, ffi_bchar_rget, ffi_short_rput, ffi_short_rget, ffi_ushort_rput, ffi_ushort_rget, ffi_int_rput, ffi_int_rget, ffi_uint_rput, ffi_uint_rget, ffi_long_rput, ffi_long_rget, ffi_ulong_rput, ffi_ulong_rget, ffi_wchar_rput): New functions. (make_ffi_type_builtin): Take rput and rget arguments, regardless of platform. On big endian, store these in the corresponding members. If they are null, duplicate get and put instead. (ffi_type_compile, ffi_init_types): Specify the rput and rget functions for the basic types, using the ifbe macro which nullifies the references to functions when they don't exist on little endian. For all other types, pass the new arguments as null. (ffi_call_wrap): Pad the return vaue buffer size to a minimum size on big endian; it must be at least sizeof (ffi_alloc). Use the rget method for the return value on big endian. (ffi_closure_dispatch, ffi_closure_dispatch_safe): Use rput on big endian for storing return value.
* ffi: remove redundant flag calc in call wrapper.Kaz Kylheku2017-05-261-1/+0
| | | | | | * ffi.c (ffi_call_wrap): Don't calculate in_pass_needed in put loop, since we already calculated it in the argument buffer allocation loop.
* ffi: bitfield support.Kaz Kylheku2017-05-251-26/+210
| | | | | | | | | | | | | | | | | | | | | | | * ffi.c (sbit_s, ubit_s): New symbol variables. (struct txr_ffi_type): New members, shift and mask. (ffi_sbit_put, ffi_sbit_get, ffi_ubit_put, ffi_ubit_get, bitfield_syntax_p): New static functions. (make_ffi_type_pointer): Disallow pointers to bitfields. (make_ffi_type_struct): Process bitfield members and set up shifts and masks accordingly. Recently introduced bug fixed here at the same time: the alignment calculation for each member must be done top-of-loop. (ffi_struct_compile): Exclude bitfields from the check against members with zero type. Compile the bitfield syntax. (ffi_typedef): Do not allow typedefs of bitfield type. Not only doesn't this make sense, but bitfield types are destructively modified in make_ffi_type_struct: they are imbued with a mask and offset tied to their position in a particular struct. * ffi.h (sbit_s, ubit_s): Delared. * txr.1: Documented bitfields.
* ffi: bugfix: remove nil slots when making struct.Kaz Kylheku2017-05-251-1/+2
| | | | | | | | | * ffi.c (ffi_type_compile): In the case when a struct type is compiled and the Lisp struct doesn't exist, the function creates the struct type. However, the FFI struct type syntax allows nil as a slot name, indicating a padding field. These nils must be scrubbed from the slot list when making the Lisp struct type, or else an error occurs.
* ffi: bugfix: gc-correct handling of memb array.Kaz Kylheku2017-05-251-2/+2
| | | | | | | | | | * ffi.c (make_ffi_type_struct): Use calloc for allocating memb, so all the Lisp objects in it are initially nil. Then install it into the structure upfront. Afterward, as we iterate over the slots and types and install them into the array, we lose references to them. But now since the array is now wired into the FFI struct type structure, these objects are now visible to GC.
* ffi: don't compile struct member type twice.Kaz Kylheku2017-05-251-1/+1
| | | | | | * ffi.c (ffi_struct_compile): Eliminate redundant call to ffi_type_compile, replacing it with the compiled type we already have.
* ffi: bugfix: incorrect error throws in buf ops.Kaz Kylheku2017-05-251-4/+4
| | | | | * ffi.c (ffi_put_into, ffi_in, ffi_get, ffi_out): Add missing error symbol argument in uw_throwf calls.
* ffi: precompute member offsets in struct type.Kaz Kylheku2017-05-251-26/+14
| | | | | | | | | | | | | | This change will make bitfield support easier. * ffi.c (struct smemb): New member, offs. (ffi_struct_in, ffi_struct_put, ffi_struct_out, ffi_struct_get, ffi_struct_release): For each member, refer to the offset in the memb array, rather than calculating it on-the-fly. (make_ffi_type_struct): Calculate the offset for each member. This is exactly the same as the total_size calculation before; just the name is changed to offs, and bit operations are used for the alignment calculations.
* ffi: use array for struct member description.Kaz Kylheku2017-05-241-40/+56
| | | | | | | | | | | | | | | | | * ffi.c (struct smemb): New struct type. (struct txr_ffi_type): Removed members mnames and mtypes. New member memb. (ffi_type_struct_destroy_op): Free the new memb descriptor array, and overwrite with null pointer. (ffi_struct_type_mark): Mark eltype only if not nil. If memb pointer is not nil, walk the array and mark it. Remove marking of removed mtypes and mnames members. (ffi_ptr_in_release, ffi_struct_in, ffi_struct_put, ffi_struct_out, ffi_struct_get, ffi_struct_release): Walk the struct members using the new array descriptor. (make_ffi_type_struct): Allocate the memb array, and initialize it. Remove initialization of mnames and mtypes. (make_ffi_type_array): Remove initialization of mnames.
* ffi: bugfix: gc issue affecting cptr and carray.Kaz Kylheku2017-05-241-15/+7
| | | | | | | | | * ffi.c (ffi_type_compile): The problem here is using make_ffi_type_builtin and then installing an eltype. That type has no gc function that will mark tft->eltype, exposing the eltype to premature reclamation. We must change these to use make_ffi_type_pointer. That constructor takes the element type too, so the code gets simplified.
* ffi: buffix: alignment still wrong for ptr types.Kaz Kylheku2017-05-241-9/+4
| | | | | | | | | | | | For pointers, the code still reflects the wrong assumption that the size and alignment are the same. * ffi.c (make_ffi_type_pointer): Remove the size argument; it's always passed as sizeof (mem_t *), which is pointless. Just initialize the size and align members in a fixed way. Use sizeof and alignof to do this right. (ffi_type_compile): Remove size argument from all make_ffi_type_pointer calls.
* ffi: eliminate overloading of mtypes member.Kaz Kylheku2017-05-241-31/+31
| | | | | | | | | | | | | | | | | | | | | | | | | | | | * ffi.c (struct txr_ffi_type): New member, eltype. Represents element type of arrays and target type of pointers, so that the mtypes member isn't overloaded for this purpose, and will only represent the list of types of a struct. (ffi_struct_type_mark): Mark eltype, since this function is used by arrays also. (ffi_ptr_type_mark): Mark eltype. Do not mark mtypes, since the ptr types don't use it any more. (ffi_varray_alloc, ffi_wchar_get, ffi_cptr_get, ffi_cptr_alloc, ffi_ptr_in_in, ffi_ptr_in_d_in, ffi_ptr_in_out, ffi_ptr_out_in, ffi_ptr_out_put, ffi_ptr_out_out, ffi_ptr_get, ffi_ptr_d_get, ffi_ptr_in_put, ffi_ptr_out_s_in, ffi_ptr_in_release, ffi_array_in_common, ffi_array_put_common, ffi_array_out_common, ffi_array_get_common, ffi_array_release_comon, ffi_array_null_term_in, ffi_array_null_term_get, ffi_varray_release, ffi_carray_get, ffi_carray_put): Access eltype instead of mtypes. (make_ffi_type_builtin): Don't initialize mnames and mtypes to nil, since we are using calloc. (make_ffi_type_pointer): Don't initialize mnames or mtypes to nil. Do initialize eltype to the target type. (make_ffi_type_array): Initialize eltype instead of mtypes. (ffi_type_compile): For cptr and carray, initialize eltype instead of mtypes.
* ffi: sanity check on object in ffi_val_get.Kaz Kylheku2017-05-241-1/+5
| | | | | | | | | | | | | | | | | * ffi.c (ffi_val_get): Throw an exception if the object doesn't appear valid. * gc.c (valid_object_p): New function. Invalid objects are those that are pointers, but either not into a heap, or else to a freed object or to an object that is marked by the garbage collector (should only be seen while GC is running). All others are valid. There can be false positives here: a value with the LIT tag is in fact a pointer, but we don't check whether that is valid. * gc.c (valid_object_p): Declared. * txr.1: Remarks added to documentation of FFI val type.
* ffi: val type.Kaz Kylheku2017-05-231-1/+19
| | | | | | | | | | | * ffi.c (val_s): New symbol variable. (ffi_val_put, ffi_val_get): New functions. (ffi_init_types): Register val type. (ffi_init): Initialize val_s. * ffi.h (val_s): Declared. * txr.1: Documented.
* ffi: bugfix: revisit alignment.Kaz Kylheku2017-05-211-30/+62
| | | | | | | | | | | | Replace the incorrect alignment assumption for the basic types (size == alignment) with the true calculation obtained from the compiler. * ffi.c (alignof): New macro. (make_ffi_type_builtin): Take alignment as separate argument. (ffi_type_compile, ffi_init_types): Using alignof macro, calculate alignment of each type that is created using make_ffi_type_builtin, and pass to that function.
* ffi: overhaul ffi-call API and document it.Kaz Kylheku2017-05-201-7/+17
| | | | | | | | | | | | | | | * ffi.c (ffi_call_wrap): Take struct args * parameters rather than a list. Check that number of arguments matches required number from call desc. No need to build argument array any more; we just refer to the one in args. Also, the first two parameters are reversed for consistency with other functions. (ffi_init): Update registration of ffi-call to reflect type change. * ffi.h (ffi_call_wrap): Declaration updated. * txr.1: Documented ffi-call.
* ffi: variable length zarray needs in operation.Kaz Kylheku2017-05-201-0/+34
| | | | | | | | * ffi.c (ffi_varray_null_term_in): New static function. (ffi_type_compile): Wire in new function as in operation of variable length zarray. * txr.1: Documented.
* ffi: new carray-buf-sync function.Kaz Kylheku2017-05-201-0/+14
| | | | | | | | | * ffi.c (carray_buf_sync): New function. (ffi_init): carray-buf-sync intrinsic registered. * ffi.h (carray_buf_sync): Declared. * txr.1: Documented.
* ffi: diagnose carray of incomplete type.Kaz Kylheku2017-05-201-0/+4
| | | | | * ffi.c (carray_buf): Do not allow an element type with zero size; throw an exception.
* ffi: reorder initializations in carray-buf.Kaz Kylheku2017-05-201-1/+1
| | | | | | | * ffi.c (carray_buf): Do the buf_get first, then length_buf, since buf_get takes a self argument. This way the diagnostic is better if the object isn't a buf.
* ffi: new function, carray-cptr.Kaz Kylheku2017-05-191-0/+9
| | | | | | | | | * ffi.c (carray_cptr): New function. (ffi_init): Registered intrinsic. * ffi.h (carray_cptr): Declared. * txr.1: Documented.
* ffi: implement get for null terminated varrays.Kaz Kylheku2017-05-191-1/+32
| | | | | | * ffi.c (ffi_varray_null_term_get): New static function. (ffi_type_compile): Install the new get function for variable length zarray.
* ffi: incomplete types can't be aggregate elements.Kaz Kylheku2017-05-191-0/+16
| | | | | | | | | Ban types like (struct foo (bar void)) or (array 3 (array int)). * ffi.c (ffi_struct_compile): Check every element type for zero size and diagnose. (ffi_type_compile): Likewise, for arrays.
* ffi: release return value when aborting callback.Kaz Kylheku2017-05-191-4/+8
| | | | | | | | | | | | | | Continuing on the topic of the previous commit, what if in a callback an error occurs in the put operation that produces the return value? In that case we end up clobbering with the abort_retval or nulling out with zero bytes, either way potentially leaking memory. * ffi.c (ffi_closure_dispatch_safe): If the return value type has release semantics, then as the very first thing, null out the return value buffer. Then later if a dynamic control transfer is intercepted, invoke the release semantics before doing anything to the return value buffer.
* ffi: clean up temp allocs on exception.Kaz Kylheku2017-05-191-25/+138
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The problem is that the argument conversions in a FFI call can bail due to an exception, leaving the argument space partially initialized, and containing pointers to temporary buffers that have been allocated with malloc. In this change, we take care of this problem. We introduce a new virtual function called release to the FFI type hieararchy. Most types do not implement this: only types that have something to free, or aggregates which have to iterate over element types. The release virtual relies on pointers being null if nothing has been allocated. For this reason, we allocate the argument space and all temporar areas with zero filling. * ffi.c (zalloca): New macro. (struct txr_ffi_type): New member function pointer, release. (ffi_fixed_alloc): Use chk_calloc instead of chk_malloc, so that any pointers in the area are null. (ffi_varray_alloc): Use chk_calloc, which simplifies the code. (ffi_simple_release, ffi_ptr_in_release, ffi_struct_release): New static functions. (ffi_array_release_common, ffi_array_release, ffi_varray_release): New static functions. (make_ffi_type_pointer): New argument for specifying release function. (make_ffi_type_struct): Initialize release member of type structure to ffi_struct_release. (make_ffi_type_array): Initialize release member of type structure to ffi_array_release. (ffi_type_compile): Set up release function for varray, several ptr variants and buf-d. (ffi_init_types): Set up release function for string types. (ffi_call_wrap): Internals restructured. Instead of repeatedly processing type and arg lists, we now store them into arrays allocated with alloca. We allocate the argument space with zalloca instead of alloca. Allocating the arguments is separated from the put conversions into two loops, because the alloca calls must be outside of the unwind catching block. This is because the unwind control transfer will roll back the alloca allocation done since the establishment of the catch block! A new unwind block now iterates over the arguments and calls release on each one which has a release function.
* ffi: bugfix: obj could be nil in buf ops.Kaz Kylheku2017-05-181-2/+2
| | | | | | | * ffi.c (ffi_buf_in): Only get the original pointer if obj isn't nil; otherwise use a null pointer. (ffi_buf_d_in): Don't refer to length_buf(obj); obj could be nil. And anyway, we know the buffer size from the type.
* ffi: unknown carray length represented as nil.Kaz Kylheku2017-05-181-1/+1
| | | | | | * ffi.c (length_carray): Convert the internal representation of unknown length, which is a -1 of type cnum, into a nil return value.
* ffi: carray-free resets length.Kaz Kylheku2017-05-181-0/+1
| | | | | | * ffi.c (carray_free): Don't just reset the pointer to null, but also set the number of elements to zero. That will prevent indexing operations from dereferencing null.
* ffi: bugfix: broken buf in semantics, bad doc.Kaz Kylheku2017-05-181-9/+4
| | | | | | | | | | | | | * ffi.c (ffi_buf_in): The bug in this one is that if *loc has been mutated to a null pointer, we want to produce a nil, rather than to try to duplicate the buffer. (ffi_buf_d_in): The bug here is that *loc is always different from origptr, because origptr is from the original buffer object, whereas we placed a copy of it into *loc. The semantics is changed. We take ownership of whatever pointer is there. If it is null, then yield nil. * txr.1: buf and buf-d documentation revised.
* ffi: new carray_buf function.Kaz Kylheku2017-05-171-0/+11
| | | | | | | | | Treat a buffer through a carray view. * ffi.c (carray_buf): New function. (ffi_init): Register carray-buf intrinsic. * ffi.h (carray_buf): Declared.
* ffi: carrays able to reference objects.Kaz Kylheku2017-05-171-4/+13
| | | | | | | | | | | | | | | | | | | | | The idea here is that carrays can have a pointer to some area that is owned by another object. So that the area doesn't disappear when the other object becomes garbage, a carray which does this maintains a pointer to that other object. * ffi.c (ffi_carray_get): Pass new parameter to make_carray. (struct carray): New member, ref. (carray_mark_op): Mark new ref member. (make_carray): New parameter: the object which is stored in the structure as ref. (carray_dup): Null out the ref member. When a carray is duplicated, it owns its own buffer, and henceforth mustn't prevent the original object from being reclaimed. (carray_own): Don't allow a carray to claim ownership of the pointer if it references another object; we have no protocol to inform that other object. * ffi.h (make_carray): Declaration updated.
* ffi: carray type to round out semantics.Kaz Kylheku2017-05-171-2/+290
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The carray type deals with C array passing conventions as a pointer to the first element of an array of unknown size. It fills in the functionality gap not covered by array and varray. * ffi.c (carray_s): New symbol variable. (ffi_carray_get, ffi_carray_put): New static functions. (ffi_type_compile): Handle (carray <type>) syntax. (struct carray): New struct type. (carray_struct, carray_struct_checked, carray_print_op, carray_mark_op, carray_destroy_op): New static functions. (carray_borrowed_ops, carray_owned_ops): New static structs. (make_carray, carray_set_length, carray_dup, carray_own, carray_free, carray_type, length_carray, carray_get, carray_vec, carray_blank, vec_carray, list_carray, carray_ref, carray_refset): New functions. (ffi_init): Initialize carray_s. Register carray-set_length, carray_dup, carray_own, carray-free, carray_type, length_carray, carray-vec, array_blank, vec_carray, list_carray, carray_ref and carray-refset intrinsics. * ffi.h (carray_s): Declared. (make_carray, carray_set_length, carray_dup, carray_own, carray_free, carray_type, length_carray, carray_get, carray_vec, carray_blank, vec_carray, list_carray, carray_ref, carray_refset): Declared.
* ffi: tagged cptr type, for improved safety.Kaz Kylheku2017-05-161-0/+8
|
* ffi: don't set up cptr as Lisp type inappropriately.Kaz Kylheku2017-05-151-7/+20
| | | | | | | | | | | | The type compiler specifies cptr as the Lisp type for various ptr types and the buf type. This will be misleading with the increasing role of cptr. * ffi.c (ffi_get_lisp_type): New static function. (ffi_type_compile): Use buf as the Lisp type for the buf and buf-d FFI types. For ptr and its variants, use the target type's Lisp type as the pointer's Lisp type. For instance (ptr int) has integer as its Lisp type.
* Splitting cptr object into separate CPTR tag.Kaz Kylheku2017-05-151-3/+3
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | CPTR shares representation and a lot of implementation with COBJ. The COBJ class symbol is the CPTR type tag. There is no hierarchy among CPTR tags. The nil tag is used for a modicum of type looseness, so that we don't straitjacket ourselves too much into this tag-based typing scheme. All existing cptr objects are becoming CPTR, and all get a nil tag, except for dlopen library handles, and dlsym symbols, which are tagged as dlhandle and dlsym. The FFI framework will support tag-declared cptr's. This will help with safety. For instance, suppose an API has half a dozen different kinds of opaque handles. If they are all just cptr on the TXR Lisp side, it's easy to mix them up, passing the wrong one to the wrong C function. * lib.h (enum type): New enum member, CPTR. (cptr_print_op, cptr_typed, cptrp, cptr_type, cptr_handle): Declared. (cptr_addr_of): Parameters added. * lib.c (code2type): Map CPTR type code to cptr_s. (equal): Handle CPTR objects. They are only equal to other CPTR objects which have the same operations, and are equal under the equal function of those operations. (cptr_print_op): New function. (cptr_ops): Use cptr_print_op rather than cobj_print_op. (cptr_typed): New function. (cptr): Use cptr_typed to make a cptr with tag nil, rather than using cobj. (cptrp, cptr_handle, cptr_type): New functions. (cptr_get): Go through cptr_handle rather than cobj_handle. (cptr_addr_of, cptr_zap, cptr_free): Use call to cptr_handle rather than cobj_handle for the type checking side effect. New parameters for type and parent function name. (obj_print_impl): Handle CPTR with same case as COBJ. * gc.c (finalize, mark_obj): Handle CPTR cases using common code with COBJ. * hash.c (equal_hash): Handle CPTR just like COBJ. * eval.c (eval_init): Register cptrp and cptr-type intrinsic functions. * ffi.c (ffi_cptr_put, ffi_cptr_get, ffi_cptr_alloc): Use the potentially type-safe cptr_handle, instead of cptr_get. However, for an untagged cptr, there is no type safety because tft->mtypes is nil. The argument can be any kind of cptr. * sysif.c (dlhandle_s, dlsym_s): New symbol variables. (cptr_dl_ops): Use cptr_print_op. (dlopen_wrap, dlclose_wrap): Use typed cptr with dlhandle as the type. (dlsym_wrap, dlsym_checked, dlvsym_wrap, dlvsym_checked): Recognize only a cptr of type dlhandle for the library. Construct a typed cptr of type dlsym. (sysif_init): Initialize dlhandle_s and dlsym_s. Register dlsym function using dlsym_s.
* cobj: rename poorly named default operation.Kaz Kylheku2017-05-151-5/+5
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Renaming cobj_hash_op to cobj_eq_hash_op. This function is only appropriate to use with COBJ objects which use eq as their equal funtion. I've spotted one instance of an inappropriate use which have to be addressed by a different commit: the equal function is other than eq, but cobj_hash_op is used for the equal hash. * lib.h (cobj_hash_op): Declaration renamed to cobj_eq_hash_op. * hash.c (cobj_hash_op): Renamed to cobj_eq_hash_op. (hash_iter_ops): Refer to renamed cobj_hash_eq_op. * ffi.c (ffi_type_builtin_ops, ffi_type_struct_ops, ffi_type_ptr_ops, ffi-closure_ops, ffi_call_desc_ops): Likewise. * lib.c (cptr_ops): Likewise. * parser.c (parser_ops): Likewise. * rand.c (random_state_ops): Likewise. * regex.c (char_set_ops, regex_obj_ops): Likewise. * socket.c (dgram_strm_ops): Likewise. * stream.c (null_ops, stdio_ops, tail_ops, pipe_ops, dir_ops, string_in_ops, byte_in_ops, strlist_in_ops, string_out_ops, strlist_out_ops, cat_stream_ops, record_adapter_ops): Likewise. * struct.c (struct_type_ops): Likewise. * sysif.c (cptr_dl_ops): Likewise. * syslog.c (syslog_strm_ops): Likewise. * unwind.c (cont_ops): Likewise.
* ffi and utf8: C++ fixes.Kaz Kylheku2017-05-151-26/+28
| | | | | | | | | | | | * ffi.c (ffi_varray_alloc, ffi_char_array_put): Use cnum type consistently to avoid signed/unsigned comparison warning from g++. (ffi_closure_dispatch_safe): Put block of code into a braced statement so that the macro-generated switch case branch isn't crossing the initialization of a variable. Also, convert cast added where we are passing a void * to a mem_* parameter. * utf8.c (utf8_dup_from): Fix coerce macros being used to strip qualifiers, not only convert type.
* ffi: null out all freed or borrowed pointers.Kaz Kylheku2017-05-131-15/+24
| | | | | | | | | | | | | | | | When taking ownership of any pointer from FFI space, null it out. This is safer in general and prevents corruption problems in the callback interface when an exception is thrown. For instance (ptr wstr-d) callback argument: callback takes ownership of the pointer in a string object; throws an exception. The FFI call dispatch runs the in semantics to get the string value out; but the old pointer is still there which may not be used. * ffi.c (ffi_str_d_get, ffi_wstr_d_get, ffi_bstr_d_get, ffi_buf_d_in, ffi_buf_d_get, ffi_ptr_d_get): Overwrite the source location of a freed or owned pointer with null.
* ffi: use dynamic allocation for wstr and wstr-d.Kaz Kylheku2017-05-131-13/+21
| | | | | | | | | | | | | | | | | | | The direct pointer use of the wstr type causes problems for callbacks. Plus allowing the foreign world to retain the pointers into string objects is inherenty unsafe. We can introduce an "unsafe wstr" type in a later release for efficiency. * ffi.c (ffi_wstr_in): New function. (ffi_wstr_put): Removed by ffi_wstr_d_put rename. (ffi_wstr_d_put): Renamed to ffi_wstr_put: both wstr and wstr-d strings have a dynamically-allocating put. (ffi_init_types): Give wstr type ffi_wstr_in handler. wstr-d type's registration switched to ffi_wstr_put, which is just ffi_wstr_d_put renamed. * txr.1: Memory management notes for wstr updated.
* ffi: darwin port: missing types.Kaz Kylheku2017-05-121-0/+4
| | | | | | | | * configure: detect clockid_t and loff_t, providing HAVE_CLOCKID_T and HAVE_LOFF_T config macros. * ffi.c (ffi_init_extra_types): Register clockid-t and loff-t types only if available.
* ffi and buf porting: stdarg.h needed.Kaz Kylheku2017-05-111-0/+1
| | | | * buf.c, ffi.c: Must include <stdarg.h> for va_list.
* ffi: support programmable abort return value.Kaz Kylheku2017-05-111-4/+11
| | | | | | | | | | | | | | | | | | | | | | | | | * ffi.c (stuct txr_ffi_closure): New member, abort_retval. (ffi_closure_mark_op): Mark the new member. (ffi_closure_dispatch_safe): Implement the abort_retval. If it is not nil, use put to place the value into the return buffer. There is a risk that this could also throw an exception, which is no longer protected: programer's problem. (ffi_make_closure): New abort_ret_in argument, which is defaulted and stored. (ffi_init): Update registration of ffi-make-closure to reflect new argument. * ffi.h (ffi_make_closure): Declaration updated. * share/txr/stdlib/ffi.tl (sys:deffi-cb-expander): Add abort-retval parameter; insert into ffi-make-closure call. (deffi-cb): Take optional abort-retval expression; pass it down to the expander function. (deffi-cb-unsafe): Pass nil as abort-retval down to expander. * txr.1: Documented.
* ffi: a measure of safety for callbacks.Kaz Kylheku2017-05-111-3/+77
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | We don't want, by default, for callbacks to capture delimited continuations across foreign code, or perpetrate non-local transfers across foreign code. Here, we take an approach similar for what was done in ftw_wrap. * ffi.c (s_exit_point): New global variable with internal linkage. (ffi_call_wrap): If s_exit_point isn't nil, then it means that the callback intercepted a nonlocal transfer and stored its exit point. We resume the transfer to that exit point instead of returning normally. (ffi_closure_dispatch_safe): New static function. (ffi_make_closure): Support a new argument which indicates whether to make a closure which uses ffi_closure_dispatch_safe, or ffi_closure_dispatch. (ffi_init): Update registration of ffi-make-closure intrinsic. * ffi.h (ffi_make_closure): Declaration updated. * share/txr/stdlib/ffi.tl (sys:deffi-cb-expander): New function. (deffi-cb): Macro internals replaced by call to new function. (deffi-cb-safe): New macro. * txr.1: Documentation of ffi-make-closure updated. New deffi-cb-unsafe macro documented.
* ffi: encode-side character array specializations.Kaz Kylheku2017-05-111-2/+65
| | | | | | | | | | | | If the object being encoded is a string, and the array element type is char, wchar or bchar, then encode a string, honoring null termination flag. Unused space in the destination array is filled with zeros. * ffi.c (ffi_char_array_put, ffi_wchar_array_put, ffi_bchar_array_put): New functions. (ffi_array_put, ffi_array_out): Use new functions under the right conditions.