jaraco / irc

Full-featured Python IRC library for Python.
MIT License
392 stars 86 forks source link

Infinite recursion irc.strings / jaraco.text.FoldedCase.__eq__ #67

Closed jaraco closed 8 years ago

jaraco commented 8 years ago

Yo.

I have this stacktracke from an ircbot using the example TestBot:

#!python

Traceback (most recent call last):
  File "./ratbot.py", line 280, in <module>
    main()
  File "./ratbot.py", line 277, in main
    bot.start()   
  File "/home/luke/pipsqueak2-deploy/lib/python3.4/site-packages/irc/bot.py", line 265, in start
    super(SingleServerIRCBot, self).start()
  File "/home/luke/pipsqueak2-deploy/lib/python3.4/site-packages/irc/client.py", line 1246, in start
    self.reactor.process_forever()
  File "/home/luke/pipsqueak2-deploy/lib/python3.4/site-packages/irc/client.py", line 278, in process_forever
    self.process_once(timeout)
  File "/home/luke/pipsqueak2-deploy/lib/python3.4/site-packages/irc/client.py", line 259, in process_once
    self.process_data(i)
  File "/home/luke/pipsqueak2-deploy/lib/python3.4/site-packages/irc/client.py", line 216, in process_data
    c.process_data()
  File "/home/luke/pipsqueak2-deploy/lib/python3.4/site-packages/irc/client.py", line 582, in process_data
    self._process_line(line)
  File "/home/luke/pipsqueak2-deploy/lib/python3.4/site-packages/irc/client.py", line 614, in _process_line
    handler(arguments, command, source, tags)
  File "/home/luke/pipsqueak2-deploy/lib/python3.4/site-packages/irc/client.py", line 646, in _handle_message
    self._handle_event(event)
  File "/home/luke/pipsqueak2-deploy/lib/python3.4/site-packages/irc/client.py", line 673, in _handle_event
    self.reactor._handle_event(self, event)
  File "/home/luke/pipsqueak2-deploy/lib/python3.4/site-packages/irc/client.py", line 398, in _handle_event
    result = handler.callback(connection, event)
  File "/home/luke/pipsqueak2-deploy/lib/python3.4/site-packages/irc/client.py", line 1209, in _dispatcher
    method(connection, event)
  File "./ratbot.py", line 103, in on_pubmsg
    if len(a) > 1 and irc.strings.lower(a[0]) == irc.strings.lower(self.connection.get_nickname()):
  File "/home/luke/pipsqueak2-deploy/lib/python3.4/site-packages/jaraco/text.py", line 67, in __eq__
    return self.lower() == other.lower()
...
  File "/home/luke/pipsqueak2-deploy/lib/python3.4/site-packages/jaraco/text.py", line 67, in __eq__
    return self.lower() == other.lower()
RuntimeError: maximum recursion depth exceeded while calling a Python object

As you can see in the trace it originates from the on_pubmsg method of TestBot. Seems like the == is getting resolved to the eq itself.

I figured out what triggers it: It's a message starting with a colon ":", which would make a[0] an empty string.


jaraco commented 8 years ago

Thanks for this report. At first, I was astonished and confused, but after some investigation, I have some clarity.

The issue appears to be that str.translate has a special behavior for when the source string is empty:

>>> class Subclass(str):
...   pass
... 
>>> type(Subclass().translate({}))
<class '__main__.Subclass'>
>>> type(Subclass('val').translate({}))
<class 'str'>

And the jaraco.text.FoldedCase and irc.strings.IRCFoldedCase classes are relying on the fact that .lower returns a simple str and not a subclass, but this expectation is violated when the input is empty.


Original comment by: Jason R. Coombs

jaraco commented 8 years ago

Bypass call to translate if string is empty, avoiding infinite recursion. Fixes #67.

→ <<cset 4f6017247bef>>


Original comment by: Jason R. Coombs

jaraco commented 8 years ago

Add test capturing infinite recursion when string is empty. Ref #67.

→ <<cset 09692c895a5b>>


Original comment by: Jason R. Coombs

jaraco commented 8 years ago

Released as 13.1.1.


Original comment by: Jason R. Coombs

jaraco commented 8 years ago

Great!


Original comment by: Lukas Erlacher