Get libffi closures to cope with SELinux execmem/execmod

Alexandre Oliva aoliva@redhat.com
Mon Feb 5 14:21:00 GMT 2007


On Jan 31, 2007, "Boehm, Hans" <hans.boehm@hp.com> wrote:

> I still think this is really ugly in principle, but I'm now inclined to
> agree that we need such a mechanism.  (This is not a statement about
> Alexandre's implementation, which is quite clever and clean.)

Thanks

> We have an object O1 which is finalizable, and indirectly points to O2.
> O2 is the last member of class P, and the representation of class P
> includes a resource R that must be explicitly reclaimed when P is
> collected.  (Which presumably happens when P's class loader is also
> collected?)

Yep

> Thus R has a finalizer.  O1 sometimes resurrects itself from its
> finalizer.  (Or it might resurrect some other object on the chain to
> O2; it doesn't matter.)  Since Java finalization is unordered, R may
> be finalized, even though it will be needed again after O1
> resurrects itself.

I'd state it even more generally without involving objects and
classes.  Multiple objects O_n point, directly or indirectly, to R.
Although the objects are configured for unordered finalization, R is
configured for traditional finalization, such that, when its finalizer
runs, it knows no other finalizer can resurrect it.

> The way the GC was originally designed, this should be impossible
> because R won't be considered for finalization after O1 has run.

Exactly.  And this is the very property I'm trying to restore.  The
way the GC was originally designed, it held that:

  terminally_unreachable(O_j) => O_j is finalizable

but as it turned out this could be implemented with a simpler, more
local test:

  O_i reaches O_j => O_j is not finalizable

and in the stage of preparation for finalization i only had to iterate
over other potentially-finalizable objects, because other live objects
would have already made O_j ineligible.

But then, when Java finalization was introduced, this conceptual model
fell apart, because Java finalizers can (and should) run even for
objects that are reachable (from other finalizable objects).

However, it also broke the implementation above for mixed cases.  It
no longer holds that, if for every j such that O_j is a finalizable
object with normal semantics and terminally_unreachable(O_j), there
exists some i such that O_i is also a finalizable object with normal
semantics and O_i reaches O_j.  O_j may be reachable from a Java
object, and that's what breaks the original property.

The change I proposed restores the property, but in a more localized
way: only if you say "hey, I really care about that original property"
will it enforce it.  In other cases, we'd use the implementation that
worked to enforce the property for non-mixed cases but that fails to
enforce it in border cases.  This sounds broken to me.

> Thus we need a way for R to protect itself without cooperation from O1,
> which we don't control.  Alexandre's patch does that by allowing objects
> to declare themselves to not be finalizable while reachable from other
> finalizable objects, overriding other instructions to finalize objects
> out of order.

> The reasons I don't feel enthusiastic about including this:

> - It doesn't fit well with the GCs original design.  It feels like a
> hack on the interface, even more so than the Java finalization
> extension.

I agree.  That's why I've been hinting that, instead of adding a new
finalization type, we should modify the non-Java finalization types
such that they enforce the original property even in Java mode.

I haven't been able to think of any case in which it could possibly be
useful for a finalizer to want to run only if no other finalizers with
normal semantics reach it, even if other finalizers with Java
semantics do.

What I have in mind is something like this (untested) patch.  How do
you feel about it?


Index: finalize.c
===================================================================
--- finalize.c	(revision 121196)
+++ finalize.c	(working copy)
@@ -2,6 +2,7 @@
  * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
  * Copyright (c) 1991-1996 by Xerox Corporation.  All rights reserved.
  * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
+ * Copyright (C) 2007 Free Software Foundation, Inc
 
  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
@@ -637,10 +638,43 @@
   	if (!GC_is_marked(real_ptr)) {
   	    if (curr_fo -> fo_mark_proc == GC_null_finalize_mark_proc) {
   	        GC_MARK_FO(real_ptr, GC_normal_finalize_mark_proc);
+		GC_set_mark_bit(real_ptr);
   	    }
-  	    GC_set_mark_bit(real_ptr);
   	}
       }
+
+      /* now revive finalize-when-unreachable objects reachable from
+	 other finalizable objects */
+      curr_fo = GC_finalize_now;
+      prev_fo = 0;
+      while (curr_fo != 0) {
+	next_fo = fo_next(curr_fo);
+	if (curr_fo -> fo_mark_proc != GC_null_finalize_mark_proc) {
+	  real_ptr = (ptr_t)curr_fo -> fo_hidden_base;
+	  if (!GC_is_marked(real_ptr)) {
+	      GC_set_mark_bit(real_ptr);
+	  } else {
+	      if (prev_fo == 0)
+		GC_finalize_now = next_fo;
+	      else
+		fo_set_next(prev_fo, next_fo);
+
+              curr_fo -> fo_hidden_base =
+              		(word) HIDE_POINTER(curr_fo -> fo_hidden_base);
+              GC_words_finalized -=
+                 	ALIGNED_WORDS(curr_fo -> fo_object_size)
+              		+ ALIGNED_WORDS(sizeof(struct finalizable_object));
+
+	      i = HASH2(real_ptr, log_fo_table_size);
+	      fo_set_next (curr_fo, fo_head[i]);
+	      GC_fo_entries++;
+	      fo_head[i] = curr_fo;
+	      curr_fo = prev_fo;
+	  }
+	}
+	prev_fo = curr_fo;
+	curr_fo = next_fo;
+      }
   }
 
   /* Remove dangling disappearing links. */


-- 
Alexandre Oliva         http://www.lsd.ic.unicamp.br/~oliva/
FSF Latin America Board Member         http://www.fsfla.org/
Red Hat Compiler Engineer   aoliva@{redhat.com, gcc.gnu.org}
Free Software Evangelist  oliva@{lsd.ic.unicamp.br, gnu.org}



More information about the Gcc-patches mailing list