[Tutor] Named-value formatting fails
Steven D'Aprano
steve at pearwood.info
Sun Jan 9 05:37:23 CET 2011
A more detailed response.
Tim Johnson wrote:
> I'm using 2.6.5 on ubuntu 10.04.
> I'm evaluating a very large string using a named-value formatting
> scheme. The process fails with the following error message:
> """not enough arguments for format string"""
I'd take that as a fairly straightforward error message. You have N
fields on the right hand side, and at least N+1 on the left hand side,
for some value of N. I'm not sure why you're perplexed -- there's
nothing in your post that explains why this is more difficult than a
mismatch in targets vs fields provided.
> In the first place, I wouldn't expect to even see this error
> message, because as the python documentation says:
> """
> Python calls the get-item method of the right-hand-side mapping
> (__getitem__), when the righthand side is an instance object.
> """
Context and URL please. Just because you've just looked it up and have
it fresh in your brain doesn't me the rest of us have too :)
> As for the right-hand mapping - I'm using the following:
> class Evalx:
> def __init__(self, localvals = None, globalvals = None):
Dear me... messing with globals and locals. That's always a bad sign.
But let's assume this is that one time in 100 that it is actually
justified...
> if localvals is None:
> self.locals = sys._getframe(1).f_locals
Are you aware that this is non-portable and subject to change without
notice?
> else :
> self.locals = locals
> if globalvals is None:
> self.globals = sys._getframe(1).f_globals
> else :
> self.globals = globals
> def __getitem__(self,key):
> return eval(key,self.globals,self.locals)
Using eval is nearly always a bad thing. Your class is now potentially
vulnerable to code injection attacks. I hope you can trust the source of
the target string *and* the globals and locals functions.
(And of course just because you can trust it *today*, doesn't mean you
can tomorrow. Code has a way of being reused.
> the implementation looks like this:
> self.content = content % Evalx()
What's self? What's content? What global and local variables do you have?
(This is just one of the many reasons why messing with globals and
locals is bad... you often can't see what a piece of code does unless
you know exactly what *all* the locals and globals are, not just the
ones in the piece of code you're looking at.)
> I would really appreciate some insights on this issue.
> I don't really know how to debug this, except for to look for some
> "%s" in the `content' string.
Quite.
>>> x = 42
>>> "%(x)s" % Evalx()
'42'
>>> "%(x)s %s" % Evalx()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: not enough arguments for format string
It's not just %s, of course, any % target that isn't named. This
includes %s %d %i %f %g %G %r %x %X plus others.
Oh, and if the security vulnerability isn't obvious already:
>>> "%(x)s %(os.system('echo \"If I can fool you into running this, I
will own your PC.\"'))s" % Evalx()
If I can fool you into running this, I will own your PC.
'42 0'
This is just one of *many* ways to inject code into your string
formatting operation.
--
Steven
More information about the Tutor
mailing list