주어진 코드의 기능에 대해 다른 프로그래머 나 감사관에게 즉시 알 수없는 코드의 일부에 자리 잡을 수있는 동적 언어로 수행 할 수있는 여러 가지 '단순한'작업이 있습니다.
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!"
거기에 일어난 일은 foo
String 상수로 메소드를 호출하려고했습니다 . 실패했습니다. 그런 다음 String 클래스를 열고 메소드 foo
o 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를 제거하도록 요청되는 이유를 보여주기를 바랍니다. 루비는 동적 언어 일뿐 아니라 (다른 답변에서 언급 한 것처럼 다른 프로젝트에서 다른 동적 언어가 허용 되었음) 일부 동적 언어를 추론하기 어려운 특정 문제가 있습니다.