주어진 코드의 기능에 대해 다른 프로그래머 나 감사관에게 즉시 알 수없는 코드의 일부에 자리 잡을 수있는 동적 언어로 수행 할 수있는 여러 가지 '단순한'작업이 있습니다.
irb (대화식 루비 쉘)에서이 시퀀스를 고려하십시오.
irb(main):001:0> "bar".foo
NoMethodError: undefined method `foo' for "bar":String
from (irb):1
from /usr/bin/irb:12:in `<main>'
irb(main):002:0> class String
irb(main):003:1> def foo
irb(main):004:2> "foobar!"
irb(main):005:2> end
irb(main):006:1> end
=> nil
irb(main):007:0> "bar".foo
=> "foobar!"
거기에 일어난 일은 fooString 상수로 메소드를 호출하려고했습니다 . 실패했습니다. 그런 다음 String 클래스를 열고 메소드 fooo return을 정의한 "foobar!"후 호출했습니다. 이것은 효과가 있었다.
이것은 공개 클래스로 알려져 있으며 보안 또는 무결성이있는 루비로 코드를 작성할 때마다 악몽을 낳습니다. 물론 그것은 당신이 아주 깔끔한 일을 할 수있게 해줍니다 ...하지만 누군가가 문자열을 저장할 때마다 파일에 저장하거나 네트워크를 통해 보낼 수 있습니다. 그리고 문자열을 재정의하는이 작은 부분은 코드의 어느 곳에 나 들어갈 수 있습니다.
다른 많은 동적 언어들도 비슷한 일을 할 수 있습니다. Perl에는 Tie :: Scalar 가있어 장면 뒤에서 주어진 스칼라의 작동 방식을 변경할 수 있습니다 (이것은 좀 더 분명하고 볼 수있는 특정 명령이 필요하지만 다른 곳에서 전달 된 스칼라는 문제가 될 수 있습니다). Perl Cookbook에 접근 할 수 있다면 Recipe 13.15-넥타이로 마법 변수 생성하기를 참조하십시오.
이러한 것들 (및 다른 언어는 종종 동적 언어의 일부) 때문에 코드에서 보안의 정적 분석에 대한 많은 접근 방식이 작동하지 않습니다. Perl과 Undecidability 는 이것이 사실임을 보여주고 구문 강조와 같은 사소한 문제조차 지적합니다 ( 런타임 에서 구문 강조 또는 정적 분석기를 완전히 물리 치는 인수를 취하거나 정의하지 whatever / 25 ; # / ; die "this dies!";않기 때문에 문제가 발생할 whatever수 있음 ).
이는 클로저가 정의 된 환경에 액세스 할 수있는 능력으로 Ruby에서 더욱 흥미로울 수 있습니다 ( YouTube : Joshua Ballanco의 RubyConf 2011에서 Ruby를 합리적 으로 유지하기 참조 ). MouseTheLuckyDog 의 Ars Technica 의견 에서이 비디오를 알게 되었습니다 .
다음 코드를 고려하십시오.
def mal(&block)
puts ">:)"
block.call
t = block.binding.eval('(self.methods - Object.methods).sample')
block.binding.eval <<-END
def #{t.to_s}
raise 'MWHWAHAW!'
end
END
end
class Foo
def bar
puts "bar"
end
def qux
mal do
puts "qux"
end
end
end
f = Foo.new
f.bar
f.qux
f.bar
f.qux
이 코드는 완전히 보이지만 mal메소드는 다른 곳에있을 수 있습니다. 물론 열린 클래스를 사용하면 다른 곳에서 재정의 할 수 있습니다.
이 코드를 실행 :
~ / $ 루비 foo.rb
바
> :)
qux
바
b.rb : 20 :`qux ': MWHWAHAW! (런타임 에러)
b.rb : 30 :에서` '
~ / $ 루비 foo.rb
바
> :)
qux
b.rb : 20 :`bar '에서 : MWHWAHAW! (런타임 에러)
b.rb : 29 :에서` '
이 코드에서 클로저는 해당 범위의 클래스에 정의 된 모든 메서드 및 기타 바인딩 에 액세스 할 수있었습니다 . 임의의 방법을 선택하고 예외를 발생시키기 위해 재정의했습니다. ( 이 객체가 무엇을 액세스 할 수 있는지에 대한 아이디어를 얻으려면 Ruby 의 Binding 클래스를 참조하십시오 )
이 컨텍스트에서 액세스 할 수있는 변수, 메소드, 자체 값 및 가능한 반복자 블록이 모두 유지됩니다.
변수의 재정의를 보여주는 더 짧은 버전 :
def mal(&block)
block.call
block.binding.eval('a = 43')
end
a = 42
puts a
mal do
puts 1
end
puts a
실행할 때 다음을 생성합니다.
42
1
43
이것은 정적 분석을 불가능하게 만드는 위에서 언급 한 공개 클래스 이상입니다. 위에서 설명한 것은 다른 곳으로 전달 된 클로저가 정의 된 전체 환경과 함께 전달된다는 것입니다. 이것은 첫 번째 클래스 환경 (함수를 전달할 수있을 때와 마찬가지로 첫 번째 클래스 함수입니다) 이것은 환경 과 당시 사용 가능한 모든 바인딩입니다. 클로저 범위에서 정의 된 모든 변수 를 재정의 할 수 있습니다.
루비에 대해 불평하는 것이 좋든 나쁘 든 ( 방법의 환경에서 접근하기를 원하는 용도 가있다 ( Perl의 Safe 참조 )) "정부 프로젝트에서 루비가 제한되는 이유는 무엇인가? "위에 링크 된 동영상에서 실제로 답변됩니다.
을 고려하면:
- 루비는 모든 클로저에서 환경을 추출 할 수 있습니다
- 루비는 클로저 범위의 모든 바인딩을 캡처합니다.
- 루비는 모든 바인딩을 실시간으로 변경 가능하게 유지합니다
- 루비는 환경을 복제하거나 리 바인딩을 금지하지 않고 새로운 바인딩을 낡은 바인딩으로 만듭니다.
이 네 가지 디자인 선택의 의미로 인해 어떤 코드가 어떤 역할을하는지 알 수 없습니다.
이에 대한 자세한 내용은 Abstract Heresies 블로그를 참조하십시오 . 특정 게시물은 그러한 토론이 있었던 계획에 관한 것입니다. (SO 관련 : Scheme이 왜 일류 환경을 지원하지 않습니까? )
그러나 시간이 지남에 따라, 나는 원래 생각했던 것보다 일류 환경에서 더 많은 어려움과 더 적은 힘이 있음을 깨달았습니다. 이 시점에서 나는 일류 환경이 전혀 쓸모없고 최악의 상황에서는 위험하다고 생각합니다.
이 섹션이 일류 환경의 위험 요소와 제공된 솔루션에서 Ruby를 제거하도록 요청되는 이유를 보여주기를 바랍니다. 루비는 동적 언어 일뿐 아니라 (다른 답변에서 언급 한 것처럼 다른 프로젝트에서 다른 동적 언어가 허용 되었음) 일부 동적 언어를 추론하기 어려운 특정 문제가 있습니다.