4 Pointer Functions

▼ |  | The Racket Foreign Interface

1 | Overview
2 | Loading Foreign Libraries
3 | C Types
4 | Pointer Functions
5 | Derived Utilities
6 | Miscellaneous Support
7 | Unexported Primitive Functions
| Bibliography
| Index

► | 4 | Pointer Functions

4.1 | Pointer Dereferencing
4.2 | Memory Management
4.3 | Pointer Structure Property

On this page:

cpointer?
ptr-equal?
ptr-add
offset-ptr?
ptr-offset
cpointer-gcable?
4.1`` Pointer Dereferencing
set-ptr-offset!
ptr-add!
ptr-ref
ptr-set!
memmove
memcpy
memset
cpointer-tag
set-cpointer-tag!
4.2`` Memory Management
malloc
free
end-stubborn-change
malloc-immobile-cell
free-immobile-cell
register-finalizer
make-late-weak-box
make-late-weak-hasheq
make-sized-byte-string
void/ reference-sink
4.3`` Pointer Structure Property
prop: cpointer

top contents ← prev up next →

### 4`` Pointer Functions🔗ℹ

> procedure (cpointer? v) → boolean?
> v : any/c

Returns #t if v is a C pointer or a value that can be used as a pointer: #f (used as a NULL pointer), byte strings (used as memory blocks), or a structure instance with the prop:cpointer structure type property. Returns #f for other values.

> procedure (ptr-equal? cptr1 cptr2) → boolean?
> cptr1 : cpointer?
> cptr2 : cpointer?

Compares the values of the two pointers. Two different Racket pointer objects can contain the same pointer.

If the values are both pointers that are not represented by #f, a byte string, a callback, a pointer based on _fpointer, or a structure with the prop:cpointer property, then the ptr-equal? comparison is the same as using equal?.

> procedure (ptr-add cptr offset [type]) → cpointer?
> cptr : cpointer?
> offset : exact-integer?
> type : ctype? = _byte

Returns a cpointer that is like cptr offset by offset instances of ctype.

The resulting cpointer keeps the base pointer and offset separate. The two pieces are combined at the last minute before any operation on the pointer, such as supplying the pointer to a foreign function. In particular, the pointer and offset are not combined until after all allocation leading up to a foreign-function call; if the called function does not itself call anything that can trigger a garbage collection, it can safely use pointers that are offset into the middle of a GCable object.

> procedure (offset-ptr? cptr) → boolean?
> cptr : cpointer?

A predicate for cpointers that have an offset, such as pointers that were created using ptr-add. Returns #t even if such an offset happens to be 0. Returns #f for other cpointers and non-cpointers.

> procedure (ptr-offset cptr) → exact-integer?
> cptr : cpointer?

Returns the offset of a pointer that has an offset. The resulting offset is always in bytes.

> procedure (cpointer-gcable? cptr) → boolean?
> cptr : cpointer?

Returns #t if cptr is treated as a reference to memory that is (assumed to be) managed by the garbage collector, #f otherwise.

For a pointer based on _gcpointer as a result type, cpointer-gcable? will return #t. For a pointer based on _pointer as a result type, cpointer-gcable? will return #f.

#### 4.1`` Pointer Dereferencing🔗ℹ

> procedure (set-ptr-offset! cptr offset [ctype]) → void?
> cptr : cpointer?
> offset : exact-integer?
> ctype : ctype? = _byte

Sets the offset component of an offset pointer. The arguments are used in the same way as ptr-add. If cptr has no offset, the exn:fail:contract exception is raised.

> procedure (ptr-add! cptr offset [ctype]) → void?
> cptr : cpointer?
> offset : exact-integer?
> ctype : ctype? = _byte

Like ptr-add, but destructively modifies the offset contained in a pointer. The same operation could be performed using ptr-offset and set-ptr-offset!.

> procedure (ptr-ref cptr type [offset]) → any
> cptr : cpointer?
> type : ctype?
> offset : exact-nonnegative-integer? = 0
> (ptr-ref cptr type abs-tag offset) → any
> cptr : cpointer?
> type : ctype?
> abs-tag : 'abs
> offset : exact-nonnegative-integer?
> (ptr-set! cptr type val) → void?
> cptr : cpointer?
> type : ctype?
> val : any/c
> (ptr-set! cptr type offset val) → void?
> cptr : cpointer?
> type : ctype?
> offset : exact-nonnegative-integer?
> val : any/c
> (ptr-set! cptr type abs-tag offset val) → void?
> cptr : cpointer?
> type : ctype?
> abs-tag : 'abs
> offset : exact-nonnegative-integer?
> val : any/c

The ptr-ref procedure returns the object referenced by cptr, using the given type. The ptr-set! procedure stores the val in the memory cptr points to, using the given type for the conversion.

In each case, offset defaults to 0 (which is the only value that should be used with ffi-obj objects, see Unexported Primitive Functions). If an offset index is non-0, the value is read or stored at that location, considering the pointer as a vector of types — so the actual address is the pointer plus the size of type multiplied by offset. In addition, a 'abs flag can be used to use the offset as counting bytes rather then increments of the specified type.

Beware that the ptr-ref and ptr-set! procedure do not keep any meta-information on how pointers are used. It is the programmer’s responsibility to use this facility only when appropriate. For example, on a little-endian machine:

> > (define block (malloc _int 5))
> > (ptr-set! block _int 0 196353)
> > (map (lambda (i) (ptr-ref block _byte i)) '(0 1 2 3))
> (1 255 2 0)

In addition, ptr-ref and ptr-set! cannot detect when offsets are beyond an object’s memory bounds; out-of-bounds access can easily lead to a segmentation fault or memory corruption.

> > procedure
> > (memmove |  | cptr |  |  |  |
> > | [ | offset] |  |  |  |
> > |  | src-cptr |  |  |  |
> > | [ | src-offset] |  |  |  |
> > |  | count |  |  |  |
> > | [ | type]) |  | → |  | void?
> cptr : cpointer?
> offset : exact-integer? = 0
> src-cptr : cpointer?
> src-offset : exact-integer? = 0
> count : exact-nonnegative-integer?
> type : ctype? = _byte

Copies to cptr from src-cptr. The destination pointer can be offset by an optional offset, which is in type instances. The source pointer can be similarly offset by src-offset. The number of bytes copied from source to destination is determined by count, which is in type instances when supplied.

> > procedure
> > (memcpy |  | cptr |  |  |  |
> > | [ | offset] |  |  |  |
> > |  | src-cptr |  |  |  |
> > | [ | src-offset] |  |  |  |
> > |  | count |  |  |  |
> > | [ | type]) |  | → |  | void?
> cptr : cpointer?
> offset : exact-integer? = 0
> src-cptr : cpointer?
> src-offset : exact-integer? = 0
> count : exact-nonnegative-integer?
> type : ctype? = _byte

Like memmove, but the result is undefined if the destination and source overlap.

> procedure (memset cptr [offset] byte count [type]) → void?
> cptr : cpointer?
> offset : exact-integer? = 0
> byte : byte?
> count : exact-nonnegative-integer?
> type : ctype? = _byte

Similar to memmove, but the destination is uniformly filled with byte (i.e., an exact integer between 0 and 255 inclusive). When a type argument is present, the result is that of a call to memset with no type argument and the count multiplied by the size associated with the type.

> procedure (cpointer-tag cptr) → any
> cptr : cpointer?

Returns the Racket object that is the tag of the given cptr pointer.

> procedure (set-cpointer-tag! cptr tag) → void?
> cptr : cpointer?
> tag : any/c

Sets the tag of the given cptr. The tag argument can be any arbitrary value; other pointer operations ignore it. When a cpointer value is printed, its tag is shown if it is a symbol, a byte string, a string. In addition, if the tag is a pair holding one of these in its car, the car is shown (so that the tag can contain other information).

#### 4.2`` Memory Management🔗ℹ

For general information on C-level memory management with Racket, see Inside: Racket C API.

> > procedure
> > (malloc |  | bytes-or-type |  |  |  |
> > | [ | type-or-bytes |  |  |  |
> > |  | cptr |  |  |  |
> > |  | mode |  |  |  |
> > |  | fail-mode]) |  | → |  | cpointer?
> | bytes-or-type |  | : |  |
> (or/c (and/c exact-nonnegative-integer? fixnum?)
> ctype?)
> | type-or-bytes |  | : |  |
> (or/c (and/c exact-nonnegative-integer? fixnum?)
> ctype?)
> |  |  | = |  | absent
> cptr : cpointer? = absent
> | mode |  | : |  |
> (or/c 'raw 'atomic 'nonatomic 'tagged
> 'atomic-interior 'interior
> 'zeroed-atomic 'zeroed-atomic-interior
> 'stubborn 'uncollectable 'eternal)
> |  | = |  | absent
> fail-mode : 'failok = absent

Allocates a memory block of a specified size using a specified allocation. The result is a C pointer to the allocated memory, or #f if the requested size is zero. Although not reflected above, the four arguments can appear in any order, since they are all different types of Racket objects; a size specification is required at minimum:

- If a C type bytes-or-type is given, its size is used to determine the block allocation size.

- If an integer bytes-or-type is given, it specifies the required size in bytes.

- If both bytes-or-type and type-or-bytes are given, then the allocated size is for a vector of values (the multiplication of the size of the C type and the integer).

- If a cptr pointer is given, its content is copied to the new block.

- A symbol mode argument can be given, which specifies what allocation function to use. It should be one of the following:

  - 'raw — Allocates memory that is outside the garbage collector’s space and is not traced by the garbage collector (i.e., is treated as holding no pointers to collectable memory). This memory must be freed with free. The initial content of the memory is unspecified.

  - 'atomic — Allocates memory that can be reclaimed by the garbage collector but is not traced by the garbage collector. The initial content of the memory is unspecified.

    For the BC Racket implementation, this allocation mode corresponds to scheme_malloc_atomic in the C API.

  - 'nonatomic — Allocates memory that can be reclaimed by the garbage collector, is treated by the garbage collector as holding only pointers, and is initially filled with zeros. The memory is allowed to contain a mixture of references to objects managed by the garbage collector and addresses that are outside the garbage collector’s space.

    For the BC Racket implementation, this allocation mode corresponds to scheme_malloc in the C API.

  - 'atomic-interior — Like 'atomic, but the allocated object will not be moved by the garbage collector as long as the allocated object is retained.

    A better name for this allocation mode would be 'atomic-immobile, but it’s 'atomic-interior for historical reasons.

    For the BC Racket implementation, a reference can point to the interior of the object, instead of its starting address. This allocation mode corresponds to scheme_malloc_atomic_allow_interior in the C API.

  - 'interior — Like 'nonatomic, but the allocated object will not be moved by the garbage collector as long as the allocated object is retained.

    A better name for this allocation mode would be 'nonatomic-immobile, but it’s 'interior for historical reasons.

    For the BC Racket implementation, a reference can point to the interior of the object, instead of its starting address. This allocation mode corresponds to scheme_malloc_allow_interior in the C API.

  - 'zeroed-atomic — Like 'atomic, but the allocated object is filled with zeros, instead of having unspecified initial content.

  - 'zeroed-atomic-interior — Like 'atomic-interior, but the allocated object is filled with zeros, instead of having unspecified initial content.

  - 'tagged — Allocates memory that must start with a short value that is registered as a tag with the garbage collector.

    This mode is supported only for the BC Racket implementation, and it corresponds to scheme_malloc_tagged in the C API.

  - 'stubborn — Like 'nonatomic, but supports a hint to the GC via end-stubborn-change after all changes to the object have been made.

    This mode is supported only for the BC Racket implementation, and it corresponds to scheme_malloc_stubborn in the C API.

  - 'eternal — Like 'raw, except the allocated memory cannot be freed.

    This mode is supported only for the CGC Racket variant, and it corresponds to scheme_malloc_uncollectable in the C API.

  - 'uncollectable — Allocates memory that is never collected, cannot be freed, and potentially contains pointers to collectable memory.

    This mode is supported only for the CGC Racket variant, and it corresponds to scheme_malloc_uncollectable in the C API.

- If an additional 'failok flag is given, then some effort may be made to detect an allocation failure and raise exn:fail:out-of-memory instead of crashing.

If no mode is specified, then 'nonatomic allocation is used when the type is a _gcpointer- or _scheme-based type, and 'atomic allocation is used otherwise.

Changed in version 6.4.0.10 of package base: Added the 'tagged allocation mode.
Changed in version 8.0.0.13: Changed CS to support the 'interior allocation mode.
Changed in version 8.1.0.6: Changed CS to remove constraints on the use of memory allocated with the 'nonatomic and 'interior allocation modes.
Changed in version 8.14.0.4: Added the 'zeroed-atomic 'zeroed-atomic-interior allocation modes.

> procedure (free cptr) → void
> cptr : cpointer?

Uses the operating system’s free function for 'raw-allocated pointers, and for pointers that a foreign library allocated and we should free. Note that this is useful as part of a finalizer (see below) procedure hook (e.g., on the Racket pointer object, freeing the memory when the pointer object is collected, but beware of aliasing).

Memory allocated with malloc and modes other than 'raw must not be freed, since those modes allocate memory that is managed by the garbage collector.

> procedure (end-stubborn-change cptr) → void?
> cptr : cpointer?

Uses scheme_end_stubborn_change on the given stubborn-allocated pointer.

> procedure (malloc-immobile-cell v) → cpointer?
> v : any/c

Allocates memory large enough to hold one arbitrary (collectable) Racket value, but that is not itself collectable or moved by the memory manager. The cell is initialized with v; use the type _scheme with ptr-ref and ptr-set! to get or set the cell’s value. The cell must be explicitly freed with free-immobile-cell.

> procedure (free-immobile-cell cptr) → void?
> cptr : cpointer?

Frees an immobile cell created by malloc-immobile-cell.

> procedure (register-finalizer obj finalizer) → void?
> obj : any/c
> finalizer : (any/c . -> . any)

Registers a finalizer procedure finalizer-proc with the given obj, which can be any Racket (GC-able) object. The finalizer is registered with a “late” will executor that makes wills ready for a value only after all weak references (such as in a weak box) for the value have been cleared, which implies that the value is unreachable and no normal will executor has a will ready for the value. The finalizer is invoked when the will for obj becomes ready in the “late” will executor, which means that the value is unreachable (even from wills, and even from itself) by safe code.

The finalizer is invoked in a thread that is in charge of triggering will executors for register-finalizer. The given finalizer procedure should generally not rely on the environment of the triggering thread, and it must not use any parameters or call any parameter functions, except that relying on a default logger and/or calling current-logger is allowed.

Finalizers are mostly intended to be used with cpointer objects (for freeing unused memory that is not under GC control), but it can be used with any Racket object—even ones that have nothing to do with foreign code. Note, however, that the finalizer is registered for the Racket object that represents the pointer. If you intend to free a pointer object, then you must be careful to not register finalizers for two cpointers that point to the same address. Also, be careful to not make the finalizer a closure that holds on to the object. Finally, beware that the finalizer is not guaranteed to be run when a place exits; see ffi/unsafe/alloc and register-finalizer-and-custodian-shutdown for more complete solutions.

As an example for register-finalizer, suppose that you’re dealing with a foreign function that returns a C pointer that you should free, but you mostly want to use the memory at a 16-byte offset. Here is an attempt at creating a suitable type:

> (define _pointer-at-sixteen/free
> (make-ctype _pointer
> #f ; i.e., just _pointer as an argument type
> (lambda (x)
> (let ([p (ptr-add x 16)])
> (register-finalizer x free)
> p))))

The above code is wrong: the finalizer is registered for x, which is no longer needed after the new pointer p is created. Changing the example to register the finalizer for p corrects the problem, but then free is invoked p instead of on x. In the process of fixing this problem, we might be careful and log a message for debugging:

> (define _pointer-at-sixteen/free
> (make-ctype _pointer
> #f
> (lambda (x)
> (let ([p (ptr-add x 16)])
> (register-finalizer p
> (lambda (ignored)
> (log-debug (format "Releasing ~s\n" p))
> (free x)))
> p))))

Now, we never see any logged event. The problem is that the finalizer is a closure that keeps a reference to p. Instead of referencing the value that is finalized, use the input argument to the finalizer; simply changing ignored to p above solves the problem. (Removing the debugging message also avoids the problem, since the finalization procedure would then not close over p.)

> procedure (make-late-weak-box v) → weak-box?
> v : any/c
> procedure (make-late-weak-hasheq v) → (and/c hash? hash-eq? hash-weak?)
> v : any/c

Like make-weak-box and make-weak-hasheq, but with “late” weak references that last longer than references in the result of make-weak-box or make-weak-hasheq. Specifically, a “late” weak reference remains intact if a value is unreachable but not yet processed by a finalizer installed with register-finalizer. “Late” weak references are intended for use by such finalizers.

> procedure (make-sized-byte-string cptr length) → bytes?
> cptr : cpointer?
> length : exact-nonnegative-integer?

Returns a byte string made of the given pointer and the given length in the BC implementation of Racket; no copying is performed. In the CS implementation, the exn:fail:unsupported exception is raised.

Beware that the representation of a Racket byte string normally requires a nul terminator at the end of the byte string (after length bytes), but some functions work with a byte-string representation that has no such terminator—notably bytes-copy.

If cptr is an offset pointer created by ptr-add, the offset is immediately added to the pointer. Thus, this function cannot be used with ptr-add to create a substring of a Racket byte string, because the offset pointer would be to the middle of a collectable object (which is not allowed).

> procedure (void/reference-sink v ...) → void?
> v : any/c

Returns #<void>, but unlike calling the void function where the compiler may optimize away the call and replace it with a #<void> result, calling void/reference-sink ensures that the arguments are considered reachable by the garbage collector until the call returns.

Added in version 6.10.1.2 of package base.

#### 4.3`` Pointer Structure Property🔗ℹ

> value prop:cpointer : struct-type-property?

A structure type property that causes instances of a structure type to work as C pointer values. The property value must be either an exact non-negative integer indicating an immutable field in the structure (which must, in turn, be initialized to a C pointer value), a procedure that takes the structure instance and returns a C pointer value, or a C pointer value.

The prop:cpointer property allows a structure instance to be used transparently as a C pointer value, or it allows a C pointer value to be transparently wrapped by a structure that may have additional values or properties.

top contents ← prev up next →