Warning: This is the manual of the legacy Guile 2.0 series. You may want to read the manual of the current stable series instead.

Next: , Previous: , Up: Defining New Types (Smobs)   [Contents][Index]

5.5.5 Remembering During Operations

It’s important that a smob is visible to the garbage collector whenever its contents are being accessed. Otherwise it could be freed while code is still using it.

For example, consider a procedure to convert image data to a list of pixel values.

image_to_list (SCM image_smob)
  struct image *image;
  SCM lst;
  int i;

  scm_assert_smob_type (image_tag, image_smob);

  image = (struct image *) SCM_SMOB_DATA (image_smob);
  lst = SCM_EOL;
  for (i = image->width * image->height - 1; i >= 0; i--)
    lst = scm_cons (scm_from_char (image->pixels[i]), lst);

  scm_remember_upto_here_1 (image_smob);
  return lst;

In the loop, only the image pointer is used and the C compiler has no reason to keep the image_smob value anywhere. If scm_cons results in a garbage collection, image_smob might not be on the stack or anywhere else and could be freed, leaving the loop accessing freed data. The use of scm_remember_upto_here_1 prevents this, by creating a reference to image_smob after all data accesses.

There’s no need to do the same for lst, since that’s the return value and the compiler will certainly keep it in a register or somewhere throughout the routine.

The clear_image example previously shown (see Type checking) also used scm_remember_upto_here_1 for this reason.

It’s only in quite rare circumstances that a missing scm_remember_upto_here_1 will bite, but when it happens the consequences are serious. Fortunately the rule is simple: whenever calling a Guile library function or doing something that might, ensure that the SCM of a smob is referenced past all accesses to its insides. Do this by adding an scm_remember_upto_here_1 if there are no other references.

In a multi-threaded program, the rule is the same. As far as a given thread is concerned, a garbage collection still only occurs within a Guile library function, not at an arbitrary time. (Guile waits for all threads to reach one of its library functions, and holds them there while the collector runs.)

Next: , Previous: , Up: Defining New Types (Smobs)   [Contents][Index]