Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

byte strings with utf8 in them can cause logger to recurse and explode #3471

Closed
ara4n opened this issue Jul 1, 2018 · 5 comments
Closed

Comments

@ara4n
Copy link
Member

ara4n commented Jul 1, 2018

As per #3470.

Whilst I've fixed that particular cause, it feels disasterous that if we pass a byte-string as a parameter to the logger which includes a utf8 sequence, the logger explodes, recursing and taking out the whole app, typically with a massive memory leak whilst stuck in a pyflame that looks like:

https://matrix.org/_matrix/media/v1/download/matrix.org/AHBHDDaOVTayKiibbmnHSKqO.

This caused multiple production outages over the last 2 weeks due to someone deciding to unexpectedly hand us a utf8 User-Agent :|

@richvdh
Copy link
Member

richvdh commented Jul 2, 2018

For added confusion, the logcontext on the error is misleading, because the error occurs when the log message is formatted, which happens in batches and can happen when processing any request.

@richvdh
Copy link
Member

richvdh commented Jul 2, 2018

the failure mode here is specifically attempting to write a log line with a mix of unicode and str (aka bytes) params:

logger.info("%s %s", u"foo", b"\xe2")

the presence of the unicode param means that the str params will be decoded with the default (ascii) codec, which then fails.

The proximal solution here is of course to make sure that everything that goes to a logger is already decoded to a unicode string, which the python 3 work will help with anyway.

The reason it then causes stack overflows and OOMs is thanks to an interaction of the stdlib memoryhandler and the fact that we redirect stderr to the logs. MemoryHandler basically goes:

if len(buffer) >= cap:
    for record in buffer:
        log_to_disk(record)
    buffer = []

If the log_to_disk throws an exception, that is caught and written to stderr, which goes through the redirection, so adds another log record to the MemoryHandler's buffer, and runs the code above again.

We should do one of:

  • Not redirect stderr to the logs (and instead fix stderr goes to /dev/null when we run with --daemonize #1539)
  • Use something other than MemoryHandler and make logging properly asynchronous
  • Ensure that the redirected stderr does not go via MemoryHandler. One way to do this would be to configure the twisted stdlib logger to go direct to the StreamHandler rather than going via the MemoryHandler.

@richvdh
Copy link
Member

richvdh commented Aug 9, 2018

we've now worked around this with option 3 (configure the twisted stdlib logger to go direct to the StreamHandler). I still think it's a bit rubbish that we're redirecting stderr to the logs, but I guess that's a separate problem.

@richvdh
Copy link
Member

richvdh commented Oct 2, 2020

This is now fixed a bit better with #8268. We could potentially remove the special-case for the twisted logger.

@richvdh
Copy link
Member

richvdh commented Apr 29, 2022

This is now fixed a bit better with #8268. We could potentially remove the special-case for the twisted logger.

done in #12589

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants