On Wed, Feb 05, 2003 at 06:00:43AM +0900, Mauricio FernŠŌdez wrote:
> But now, what happens if I do:
> 
> ...
>   def no_redef(*args)
>     @no_override ||= []
>     args.each { |i| @no_override << i }
>     @no_override.freeze
>   end
> ...
> 
> Is it impossible enough now? ;-) 

Not quite.  Here are my 5 solutions:

# Solution 1: Redefine Array#+
class B < Unbreakable::A
  def a; puts "You won!"; end
  Array.class_eval do
    def +(x)
      return []
    end
  end
  def a; puts "You won!"; end
end

# Solution 2: Redefine Array#index
class B < Unbreakable::A
  def a; puts "You won!"; end
  Array.class_eval do
    def index(id)
      return nil
    end
  end
  def a; puts "You won!"; end
end

# Solution 3: Redefine Fixnum#==
class B < Unbreakable::A
  def a; puts "You won!"; end
  Fixnum.instance_eval do
    define_method(:==) { |x| true }
  end
  def a; puts "You won!"; end
end

# Solution 4: Use alias_method to create an alias for alias_method so
# that I can still create aliases in the derived class.
class B < Unbreakable::A
  def a; puts "You won!"; end
  Module.instance_eval do
    alias_method :alias_method_2, :alias_method
  end
  def b; puts "You won!"; end
  alias_method_2 :a, :b
end

# Solution 5: Use set_trace_func to capture all bindings; use this so
# that any method that any calls __no_redef_list__ are equivalent to
# "return".
class B < Unbreakable::A
  def a; puts "You won!"; end
  call_stack = []
  current_call = nil
  set_trace_func(proc {|*args|
    if args[3] == :__no_redef_list__ then
      eval "return", call_stack[4]
    end
    case args[0]
      when 'call'
        call_stack.unshift(current_call)
      when 'return'
        call_stack.shift()
    end
    current_call = args
  })
  def a; puts "You won!"; end
  set_trace_func nil
end


> My ultimate goal with this contest is seeing if it is at all possible to
> prevent redefinition unconditionally, against all attacks. 

My suspicion is that this is not possible without modifying the
interpreter.  I also suspect that protecting against all "attacks" is
unnecessary, and that protecting the programmer against shooting himself
in the foot is sufficient.

Paul