2012-07-14 1 views
2

공용 IRC 봇에서 this calculator을 사용하고 있습니다. 파이썬이 기본적으로 임의의 정밀도를 사용한다고 가정하면 어떤 사용자라도 calc 10000**10000**10000 또는 calc factorial(1000000)과 같은 것을 실행하고 효과적으로 봇을 "죽"수 있습니다.Python IRC bot에서 값 비싼 계산 피하기

나는 이것을 피할 수있는 방법이 있는지 알고 싶습니다. 나는 표현식의 모든 용어를 float으로 캐스팅하려했지만 float(factorial(1000000)은 파이썬 인터프리터에서 마무리하는 데 오랜 시간이 걸리고 멀티 스레딩 방식이 올바른 방법인지는 확실하지 않습니다.

+0

나는 eval을 사용한다는 것을 알고 있지만, 나는 오랫동안 위험한 명령을 실행하려고 시도해 왔으며 아무 것도 할 수 없었다. 나는 이것이 100 % 안전하다는 것을 보장하지는 않지만 사용하게 될 사용자가 "준 신뢰"하다는 의미인데, 이는 그들이 os로 이상한 일을하지 않을 것이라는 것을 의미하지만 나는 그들이 단지 죽일 것이라고 확신한다. 재미있는 로봇. – user1002327

+0

다음은 계산기의 실제 코드입니다. 질문을 간단하게하기 위해 사용한 것입니다. http://pastebin.com/auF1krdh – user1002327

+0

파이썬에 대해 전혀 알지 못하는데, Loic과 같은 접근법이 필요하다고 생각합니다. 계산기를 독립적 인 프로세스로 시작하고 지정된 시간 후에 종료하십시오. 팩토리얼 같은 기능을 사용하는 것이 두려운 것은 사용자가 빠른 계산 가능한 입력 만 삽입하도록하는 것은 거의 불가능하며 발에서 계산기를 쏠 수있는 방법이 너무 많습니다. –

답변

1

어쨌든 float() 캐스트가 해결 된 것 같습니다.

우선, 역 삼각 함수는 도메인 외부에서 값을 가져 가지 않으므로 완전히 안전하고 예외가 잡힐 수 있습니다.

>>> acos(5e100) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
ValueError: math domain error 

fmod() 기능과 동일한 문제가 발생합니다.

그들이 다시 함수 반환 ValueError하게 정말 큰 를, 아니라면 "정상"삼각 함수가 큰 값으로 어떤 문제가하지 않는 것.

반올림 함수 (ceil(), floor()round())는 정상적으로 작동하며 값이 너무 큰 경우 inf을 반환합니다. degrees(), log(), log10(), pow(), sqrt(), fabs(), hypot()radians() 기능도 동일합니다.

쌍곡선 삼각 함수와 exp() 함수는 OverflowError을 반환하거나 inf을 반환합니다.

atan2() 함수는 큰 값으로 완벽하게 작동합니다.

단순한 산술 연산의 경우 float 형변환은 계산을 수행하는 대신 OverflowError (또는 inf)을 던집니다.

>>> float(10) ** float(100) ** float(100) ** float(1000) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
OverflowError: (34, 'Numerical result out of range') 
>>> float(5e500) * float(4e1000) 
inf 

마지막으로 문제가되는 factorial() 함수. 내가해야만하는 것은 함수를 반복적 인 방식으로 재정의하고 safe_dict에 추가하는 것입니다.

import sys 

def factorial(n): 
    fact = 1 
    while (n > 0): 
     fact = float(fact) * float(n) 
     n -= float(1) 
     if float(fact) > sys.float_info.max: 
      return "Too big" 
    return str(fact) 

print factorial(50e500) 

이것은 매우 추악하고 비효율적 인 계계를 계산하는 방법이지만 내 요구에는 충분합니다. 사실, 불필요한 많은 것을 추가했다고 생각합니다. float() s.

이제 표현식의 모든 단어 주위에 float()을 붙이는 방법을 알아야합니다. 자동으로 발생합니다.

2

정말 대답이 아니지만 그렇게 할 것입니다. 당신이 달리는 모든 일은 다른 과정 안에서 이루어져야합니다. 내가 아는 한 프로세스에서 단일 스레드의 CPU 사용량이나 메모리 사용을 제한 할 수는 없습니다.

즉, 사용자가 입력 한 내용을 실행하고 예를 들어 파일에 쓰는 작업과 마찬가지로 새 프로세스를 만들어야합니다. fork을 사용하여이 작업을 수행하고 PID을 사용하여 새 파일을 만들고 주 프로세스는 하위 프로세스가 종료 될 때까지 확인해야합니다. 프로세스가 종료되면 "cool_calculator_ [pid] .out"파일을 열고 IRC으로 다시 보냅니다.

아주 간단합니다.

그런 다음 ulimit 또는 다른 도구를 사용하여 하위 프로세스를 제한하거나 마스터 프로세스를 사용하여 자식 프로세스를 종료 할 수 있습니다. pid이있는 파일이 비어 있으면 오류 또는 무엇인가가 있다고 대답하십시오. 나는 심지어 초과 된 메모리 또는 CPU 초과 등의 일부 오류를 작성할 수 있습니다 같아요.

모두 나쁜 프로세스를 죽이려는 방식에 따라 달라집니다.

결국 마스터 프로세스는 자식을 생성하고 필요한 경우이를 종료하고 응답을 되돌려주는 작업을해야합니다.

+0

오, C에서 오버플로를위한 모든 종류의 에러를 얻었으므로 그 오버 플로우를 감지 할 수 있는지 알고 싶다. 파이썬은 가능합니다. 전에 말했듯이, 모든 것을 캐스팅하는 것은 충분하지 않지만, 많은 문제를 해결합니다. 'float (10000) ** float (9999999999)'thro 'float (factorial (12000))'도 그렇지만'float (계승 (120000)) '이 어떤 이유로 전체 계산을 완료하려고합니다. – user1002327

+1

'float (계승 (120000))'*는 OverflowError를 던집니다. 단지 시간이 걸립니다. 계승이 계산 된 후에 OverflowError가 발생합니다. – DSM

+0

아, 오래 걸릴 것이라고 생각해서 끝내지 않았습니다. 그 점을 지적 해 주셔서 감사합니다. – user1002327