Skip to content

[18.0][FIX] auditlog: prevent recursion on re-entrant write from compute/inverse - #3658

Open
midhlaj-nk wants to merge 1 commit into
OCA:18.0from
midhlaj-nk:18.0-fix-auditlog-recursion-on-write
Open

[18.0][FIX] auditlog: prevent recursion on re-entrant write from compute/inverse#3658
midhlaj-nk wants to merge 1 commit into
OCA:18.0from
midhlaj-nk:18.0-fix-auditlog-recursion-on-write

Conversation

@midhlaj-nk

Copy link
Copy Markdown

Problem

When an auditlog rule is active for a model that has compute or inverse methods that trigger write() on the same model (e.g. account.account with _compute_code / _inverse_code), a RecursionError: maximum recursion depth exceeded is raised.

Root cause: write_full and write_fast set auditlog_disabled=True via self = self.with_context(auditlog_disabled=True), which only modifies the local self. Compute/inverse methods triggered by the original write call write() on the model class using their own self, which does not carry the modified context. This causes the patched write_full/write_fast to re-enter indefinitely.

Closes #3512

Solution

Add an early-exit guard as the first statement of both write_full and write_fast:

if self.env.context.get("auditlog_disabled"):
    return write_full.origin(self, vals, **kwargs)

When a re-entrant write call arrives (already carrying auditlog_disabled=True), the closure immediately delegates to the origin and returns — no logging, no further recursion.

Tests

Added TestAuditlogRecursion with three test cases:

  • test_no_recursion_write_full_reentrant: company write syncs address to child partner (both audited, full log) — verifies no RecursionError
  • test_no_recursion_write_fast_reentrant: same scenario with fast log
  • test_write_full_guard_skips_logging: write with auditlog_disabled=True in context produces no log entry — verifies guard path is taken

…ute/inverse

write_full and write_fast set auditlog_disabled on a rebound local self via
with_context(), but compute/inverse methods triggered by the original write
(e.g. AccountAccount._compute_code / _inverse_code) call write() on the model
class using their own self, which does not carry the modified context. This
causes write_full/write_fast to re-enter indefinitely, hitting Python's
recursion limit.

Add an early-exit guard at the top of both closures: if auditlog_disabled is
already in context, delegate immediately to the origin write and return.

Closes OCA#3512

@StefanRijnhart StefanRijnhart left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for having a go at this. The added test fails, but also I fear this solution might undermine the situation in which the write of a tracked model triggers a write on another tracked model. The changes on the latter model might not be recorded due to the application of the context key. Furthermore, the semantics of this particular context key, which was somewhat unfortunately named I believe was to disable read logging in particular. All of this has been digested on #3646 which I think is in a pretty good shape now. Maybe you can test and review that version, and maybe try to cherry-pick its solution for 18.0?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Auditlog: Maximum recursion error when creating new accounts

3 participants