[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