Skip to content

Fix crashes when viewing directory with sort=stack#128

Merged
noahp merged 5 commits intoHBehrens:masterfrom
avian2:fix-none-sum
Dec 3, 2025
Merged

Fix crashes when viewing directory with sort=stack#128
noahp merged 5 commits intoHBehrens:masterfrom
avian2:fix-none-sum

Conversation

@avian2
Copy link
Contributor

@avian2 avian2 commented Oct 6, 2025

This fixes crashes where code attempts to sum integers with None or an empty string "" when viewing a source directory with the url argument sort=stack_asc or sort=stack_desc.

How to reproduce:

  • View a single .c file,
  • click "Stack" column header to sort functions by stack usage,
  • click one of the parent directories
  • get an "Internal server error" with the following stack trace in the console:
[2025-10-06 11:25:51,611] ERROR in app: Exception on /path/[...]/ [GET]
Traceback (most recent call last):
  File "[...]/.venv/lib/python3.13/site-packages/flask/app.py", line 2529, in wsgi_app
    response = self.full_dispatch_request()
  File "[...]/.venv/lib/python3.13/site-packages/flask/app.py", line 1825, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "[...]/.venv/lib/python3.13/site-packages/flask/app.py", line 1823, in full_dispatch_request
    rv = self.dispatch_request()
  File "[...]/.venv/lib/python3.13/site-packages/flask/app.py", line 1799, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
  File "[...]/.venv/lib/python3.13/site-packages/flask/views.py", line 107, in view
    return current_app.ensure_sync(self.dispatch_request)(**kwargs)
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^
  File "[...]/puncover/puncover/renderers.py", line 349, in dispatch_request
    return self.render_template("folder.html.jinja", path)
           ~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "[...]/puncover/puncover/renderers.py", line 294, in render_template
    return render_template(template_name, **self.template_vars)
  File "[...]/.venv/lib/python3.13/site-packages/flask/templating.py", line 147, in render_template
    return _render(app, template, context)
  File "[...]/.venv/lib/python3.13/site-packages/flask/templating.py", line 130, in _render
    rv = template.render(context)
  File "[...]/.venv/lib/python3.13/site-packages/jinja2/environment.py", line 1295, in render
    self.environment.handle_exception()
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
  File "[...]/.venv/lib/python3.13/site-packages/jinja2/environment.py", line 942, in handle_exception
    raise rewrite_traceback_stack(source=source)
  File "[...]/puncover/puncover/templates/folder.html.jinja", line 2, in top-level template code
    {% import 'lists.html.jinja' as lists with context %}
    ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "[...]/puncover/puncover/templates/base.html.jinja", line 32, in top-level template code
    {% block content %}{% endblock %}
    ^^^^^^^^^^^^^^^^^
  File "[...]/puncover/puncover/templates/folder.html.jinja", line 6, in block 'content'
    {{ lists.directory(folder.sub_folders, folder.files) }}
    ^^^^^^^^^^^^^^^^^^^^^
  File "[...]/.venv/lib/python3.13/site-packages/jinja2/runtime.py", line 784, in _invoke
    rv = self._func(*arguments)
  File "[...]/puncover/puncover/templates/lists.html.jinja", line 39, in template
    {% for folder in (folders | sorted) %}
    ^^^^^^^^^^^^^
  File "[...]/puncover/puncover/renderers.py", line 273, in sorted_filter
    return list(sorted(symbols, key=key, reverse=(sort_order == "desc")))
                ~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "[...]/puncover/puncover/renderers.py", line 269, in <lambda>
    "stack": lambda e: to_num(symbol_stack_size_filter(context, e)),
                              ~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^
  File "[...]/puncover/puncover/renderers.py", line 108, in symbol_stack_size_filter
    result = traverse_filter_wrapper(
        value,
    ...<2 lines>...
        else None,
    )
  File "[...]/puncover/puncover/renderers.py", line 80, in traverse_filter_wrapper
    result = symbol_traverse(value, func)
  File "[...]/puncover/puncover/renderers.py", line 72, in symbol_traverse
    symbol_traverse(s, func)
    ~~~~~~~~~~~~~~~^^^^^^^^^
  File "[...]/puncover/puncover/renderers.py", line 72, in symbol_traverse
    symbol_traverse(s, func)
    ~~~~~~~~~~~~~~~^^^^^^^^^
  File "[...]/puncover/puncover/renderers.py", line 69, in symbol_traverse
    return sum([symbol_traverse(s, func) for s in s[collector.SYMBOLS]])
TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'

avian2 added 2 commits October 6, 2025 11:56
Fix crashes when we get a mix of None and int in sum(), because
symbol_traverse() uses none_sum() in one branch and sum() in other.
traverse_filter_wrapper() changes 0 to "", but we later use none_sum() to sum
the result, which will crash when trying to add str to int.

Instead use symbol_traverse() directly and only convert 0 to "" after none_sum().
@noahp noahp self-requested a review December 3, 2025 17:42
@noahp noahp self-assigned this Dec 3, 2025
@noahp
Copy link
Collaborator

noahp commented Dec 3, 2025

thanks! i added a test, i'll merge when it finishes testing.

@noahp noahp merged commit a4e0f73 into HBehrens:master Dec 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants