473,803 Members | 4,192 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Re: Simple and safe evaluator


Okay guys. I have the _ast based safe eval installed and working in my
program. It appears to be working just fine. Thanks for the help.

Now, a few more questions:

1. I see that _ast is a 2.5 module?? So, for folks using my code with
<2.5 I could do something like this:

# I've got some imports here to look after the error() and warning()
funcs ....

emsg_done = 0
etx = ""

def unsafe_eval(s):
""" safe eval for < python 2.5 (lacks _ast) """
global emsg_done
if not emsg_done:
warning("You are using an unsafe eval() function. Please
upgrade to Python version 2.5 or greater.")
emsg_done=1
# need error trap here as well ...
return eval(s, {"__builtins__" :None}, {} )

def safe_eval(text) :
"similar to eval, but only works on numerical values."
global etx
try:
ast = compile(text, "<string>", 'eval', _ast.PyCF_ONLY_ AST)
except:
error("Expressi on error in '%s'" % text)
etx = text # for error reporting, bvdp
return _traverse(ast.b ody)
try:
import _ast
num_eval = safe_eval
except:
num_eval = unsafe_eval

# rest of matt's ast code follows.

Which appears to do the following: if there isn't an _ast module we just
define an alternate, not-so-safe, function and warn the user; otherwise
we use the safe version. I'm a bit uncomfortable with the import _ast
being after the function which uses the code, but it seems to work.

2. I thought I'd be happy with * / + -, etc. Of course now I want to add
a few more funcs like int() and sin(). How would I do that?

Thanks. This is looking very nice indeed.

Bob.
Jun 27 '08 #1
7 1698
On Jun 16, 4:47 pm, bvdp <b...@mellowood .cawrote:
2. I thought I'd be happy with * / + -, etc. Of course now I want to add
a few more funcs like int() and sin(). How would I do that?
For the builtin eval, just populate the globals dict with the names
you want to make available:

import math

globs = {'__builtins__' : None}

# expose selected builtins
for name in 'True False int float round abs divmod'.split() :
globs[name] = eval(name)

# expose selected math constants and functions
for name in 'e pi sqrt exp log ceil floor sin cos tan'.split():
globs[name] = getattr(math,na me)

return eval(s, globs, {})
The change to the _ast version is left as an exercise to the reader ;)

George
Jun 27 '08 #2
George Sakkis wrote:
On Jun 16, 4:47 pm, bvdp <b...@mellowood .cawrote:
>2. I thought I'd be happy with * / + -, etc. Of course now I want to add
a few more funcs like int() and sin(). How would I do that?

For the builtin eval, just populate the globals dict with the names
you want to make available:

import math

globs = {'__builtins__' : None}

# expose selected builtins
for name in 'True False int float round abs divmod'.split() :
globs[name] = eval(name)

# expose selected math constants and functions
for name in 'e pi sqrt exp log ceil floor sin cos tan'.split():
globs[name] = getattr(math,na me)

return eval(s, globs, {})
Thanks. That was easy :)
The change to the _ast version is left as an exercise to the reader ;)
And I have absolutely no idea on how to do this. I can't even find the
_ast import file on my system. I'm assuming that the _ast definitions
are buried in the C part of python, but that is just a silly guess.

Bob.
Jun 27 '08 #3
On Jun 17, 8:02 am, bvdp <b...@mellowood .cawrote:
Thanks. That was easy :)
The change to the _ast version is left as an exercise to the reader ;)

And I have absolutely no idea on how to do this. I can't even find the
_ast import file on my system. I'm assuming that the _ast definitions
are buried in the C part of python, but that is just a silly guess.

Bob.
If you just need numeric expressions with a small number of functions,
I would suggest checking the expression string first with a simple
regular expression, then using the standard eval() to evaluate the
result. This blocks the attacks mentioned above, and is simple to
implement. This will not work if you want to allow string values in
expressions though.

import re
def safe_eval( expr, safe_cmds=[] ):
toks = re.split( r'([a-zA-Z_\.]+|.)', expr )
bad = [t for t in toks if len(t)>1 and t not in safe_cmds]
if not bad:
return eval( expr )
>>safe_eval( "abs(5*-77+33.1) + (int(405.3) * 5.7e-12)", 'int float sum abs'.split() )
351.90000000230 85
>>safe_eval( "abs(5*-77+33.1) + (int(405.3) * 5.7e-12)" )
safe_eval( "open('thesis.t ex').write('')" )
Mike.
Jun 27 '08 #4
sw******@acm.or g wrote:
On Jun 17, 8:02 am, bvdp <b...@mellowood .cawrote:
>Thanks. That was easy :)
>>The change to the _ast version is left as an exercise to the reader ;)
And I have absolutely no idea on how to do this. I can't even find the
_ast import file on my system. I'm assuming that the _ast definitions
are buried in the C part of python, but that is just a silly guess.

Bob.

If you just need numeric expressions with a small number of functions,
I would suggest checking the expression string first with a simple
regular expression, then using the standard eval() to evaluate the
result. This blocks the attacks mentioned above, and is simple to
implement. This will not work if you want to allow string values in
expressions though.

import re
def safe_eval( expr, safe_cmds=[] ):
toks = re.split( r'([a-zA-Z_\.]+|.)', expr )
bad = [t for t in toks if len(t)>1 and t not in safe_cmds]
if not bad:
return eval( expr )
Yes, this appears to be about as good (better?) an idea as any.
Certainly beats writing my own recursive decent parser for this :)

And it is not dependent on python versions. Cool.

I've run a few tests with your code and it appears to work just fine.
Just a matter of populating the save_cmds[] array and putting in some
error traps. Piece of cake. And should be fast as well.

Thanks!!!

Bob.
Jun 27 '08 #5
On Jun 16, 8:32*pm, bvdp <b...@mellowood .cawrote:
sween...@acm.or g wrote:
On Jun 17, 8:02 am, bvdp <b...@mellowood .cawrote:
Thanks. That was easy :)
>The change to the _ast version is left as an exercise to the reader ;)
And I have absolutely no idea on how to do this. I can't even find the
_ast import file on my system. I'm assuming that the _ast definitions
are buried in the C part of python, but that is just a silly guess.
Bob.
If you just need numeric expressions with a small number of functions,
I would suggest checking the expression string first with a simple
regular expression, then using the standard eval() to evaluate the
result. *This blocks the attacks mentioned above, and is simple to
implement. *This will not work if you want to allow string values in
expressions though.
import re
def safe_eval( expr, safe_cmds=[] ):
* *toks = re.split( r'([a-zA-Z_\.]+|.)', expr )
* *bad = [t for t in toks if len(t)>1 and t not in safe_cmds]
* *if not bad:
* * * * * *return eval( expr )

Yes, this appears to be about as good (better?) an idea as any.
Certainly beats writing my own recursive decent parser for this :)

And it is not dependent on python versions. Cool.

I've run a few tests with your code and it appears to work just fine.
Just a matter of populating the save_cmds[] array and putting in some
error traps. Piece of cake. And should be fast as well.

Thanks!!!

Bob.
FWIW, I got around to implementing a function that checks if a string
is safe to evaluate (that it consists only of numbers, operators, and
"(" and ")"). Here it is. :)

import cStringIO, tokenize
def evalSafe(source ):
'''
Return True if a source string is composed only of numbers,
operators
or parentheses, otherwise return False.
'''
try:
src = cStringIO.Strin gIO(source).rea dline
src = tokenize.genera te_tokens(src)
src = (token for token in src if token[0] is not tokenize.NL)

for token in src:
ttype, tstr = token[:2]

if (
tstr in "()" or
ttype in (tokenize.NUMBE R, tokenize.OP)
and not tstr == ',' # comma is an OP.
):
continue
raise SyntaxError("un safe token: %r" % tstr)

except (tokenize.Token Error, SyntaxError):
return False

return True

for s in (

'(1 2)', # Works, but isn't math..

'1001 * 99 / (73.8 ^ 88 % (88 + 23e-10 ))', # Works

'1001 * 99 / (73.8 ^ 88 % (88 + 23e-10 )',
# Raises TokenError due to missing close parenthesis.

'(1, 2)', # Raises SyntaxError due to comma.

'a * 21', # Raises SyntaxError due to identifier.

'import sys', # Raises SyntaxError.

):
print evalSafe(s), '<--', repr(s)

Jun 27 '08 #6
In article <f4************ *************** *******@u12g200 0prd.googlegrou ps.com>,
Simon Forman <sa*******@gmai l.comwrote:
>
FWIW, I got around to implementing a function that checks if a string
is safe to evaluate (that it consists only of numbers, operators, and
"(" and ")"). Here it is. :)
What's safe about "10000000 ** 10000000"?
--
Aahz (aa**@pythoncra ft.com) <* http://www.pythoncraft.com/

"as long as we like the same operating system, things are cool." --piranha
Jun 27 '08 #7
Aahz wrote:
In article <f4************ *************** *******@u12g200 0prd.googlegrou ps.com>,
Simon Forman <sa*******@gmai l.comwrote:
>FWIW, I got around to implementing a function that checks if a string
is safe to evaluate (that it consists only of numbers, operators, and
"(" and ")"). Here it is. :)

What's safe about "10000000 ** 10000000"?
Guess it depends on your definition of safe. I think that in most cases
folks looking for "safe" are concerned about a malicious interjection of
a command like "rm *" ... your example hangs the system for a long time
and eventually will error out when it runs out of memory, but (probably)
doesn't cause data corruption.

It would be nice if in a future version of Python we could have a
safe/limited eval() ... which would limit the resources.
Jun 27 '08 #8

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

7
1198
by: bvdp | last post by:
Is there a simple/safe expression evaluator I can use in a python program. I just want to pass along a string in the form "1 + 44 / 3" or perhaps "1 + (-4.3*5)" and get a numeric result. I can do this with eval() but I really don't want to subject my users to the problems with that method. In this use I don't need python to worry about complex numbers, variables or anything else. Just do the math on a set of values. Would eval() with...
7
242
by: bvdp | last post by:
I'm finding my quest for a safe eval() quite frustrating :) Any comments on this: Just forget about getting python to do this and, instead, grab my set of values (from a user supplied text file) and call an external program like 'bc' to do the dirty work. I think that this would avoid someone from embedding os.system("rm ...") in what I thought would be a math expression and having it maybe do damage? Perhaps I'm getting too paranoid in...
0
9564
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
10548
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
10316
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
0
10069
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
9125
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
7604
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
5629
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
4275
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
3798
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.