You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
fix: Lua m.setvar() returned -1, handing the script stack garbage - #3732
Fixes three problems in Lua::setvar() (src/engine/lua.cc):
Error paths return 0 instead of -1. This covers the wrong number of arguments and a name with no collection. The script now gets nil.
luaL_checkstring() is called before the std::string locals are constructed. It raises a Lua error with longjmp on a non-string argument, which would skip their destructors. This makes the NULL check after it unreachable, so that check is removed.
The lua_pop(L, 2) is removed. It popped the value argument while var_value still pointed into it. A lua_CFunction's stack is cleared on return anyway.
Typo fixed in the debug message: "funtion must has" is now "function must have".
why
A lua_CFunction returns the number of values it pushed. With -1, Lua returned whatever was on the stack. With the two new test scripts on v3/master, m.setvar("novar", "x") returned the __transaction pointer (userdata: 0x…), and m.setvar("tx.a") returned a stray string.
tests
Two new cases in collection-lua.json, with the scripts setvar-error-nodot.lua and setvar-error-onearg.lua, check that the script gets nil. Both fail on v3/master and pass with this change.
The other Lua regression files pass: action-exec, directive-sec_rule_script, operator-inpectFile and issue-2427.
make check (macOS, Lua 5.5.1, PCRE2): 5139 total, 0 fail.
Invalid calls to set a variable—including missing arguments, missing collection syntax, or non-string values—now return no values instead of an error code.
Unknown collections are logged and handled without changing a variable. Valid transaction-variable updates continue to work and return no values.
Tests
Added regression coverage for valid and invalid variable-setting calls.
Lua::setvar() returned -1 on its error paths (wrong number of
arguments, no collection in the name). A lua_CFunction returns the
number of values it pushed, so Lua returned whatever was on the stack:
the script got the __transaction pointer or a stray string. Return 0 so
the script gets nil.
Also call luaL_checkstring() before the std::string locals exist,
since it raises a Lua error with longjmp on a non-string argument,
drop the NULL check it makes unreachable, and stop popping the
arguments while var_value still points into them.
Fixesowasp-modsecurity#3731
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RiUJuqXNvvpytiGRiDFyTy
No actionable comments were generated in the recent review.
Walkthrough
Lua::setvar now returns zero Lua values on handled errors and validates argument types before constructing local strings. It logs unknown collections. New regression cases cover these paths and successful TX assignment.
Changes: Lua setvar error handling
Layer / File(s)
Summary
Argument checks and return handling src/engine/lua.cc
setvar checks the argument count and string types before constructing local strings. It returns zero values for invalid arguments and names without a collection separator. It logs unknown collection names.
#3737 concerns the same luaL_checkstring() and C++ destructor issue in getvar() and getvars(). Those call sites are not changed here.
#3655 lists Lua setvar return values as one scope item. This change addresses the setvar return handling; its other items remain separate.
Suggested reviewers:airween
Merge Risk: Minimal · up to 9dfe9
Lua m.setvar() now returns no values on handled errors instead of exposing unrelated stack contents, and regression tests cover these cases. No actionable merge-blocking risk remains.
Pre-merge checks: 4
Check name
Status
Explanation
Description Check
Check skipped - CodeRabbit’s high-level summary is enabled.
Title check
The title names the main change: Lua m.setvar() error paths returned -1, which left garbage on the Lua stack. The changeset replaces those -1 returns with zero return values in src/engine/lua.cc and a…
Linked Issues check
Directly linked issue [#3731] has four coding requirements. Each is met at the reviewed head (9dfe9a1), per the whole-PR diff against the merge base 9d45c6d.
1. Error paths must not return -1. The w…
Out of Scope Changes check
All changes in src/engine/lua.cc relate to #3731. The error-return changes, the argument-check reordering, the lua_pop removal and the typo fix are direct requirements. The new else branch logs "m.set…
Full details: Title check
Explanation
The title names the main change: Lua m.setvar() error paths returned -1, which left garbage on the Lua stack. The changeset replaces those -1 returns with zero return values in src/engine/lua.cc and adds regression cases for the error paths. The 'fix:' prefix states the change type. The title is specific and matches the linked issue and PR objectives.
Full details: Linked Issues check
Explanation
Directly linked issue [#3731] has four coding requirements. Each is met at the reviewed head (9dfe9a1), per the whole-PR diff against the merge base 9d45c6d.
Error paths must not return -1. The wrong-argument-count path (nargs != 2) and the no-dot path now return 0. A new NULL-argument path also returns 0. Lua then gives the script nil.
Argument checks must run before the std::string locals exist. The diff moves the std::string locals below the argument checks. It replaces luaL_checkstring() with lua_tostring(), so a non-string argument cannot longjmp out of the C++ frame. The NULL check is kept and now logs a debug message. A table argument returns NULL from lua_tostring(), so the test case for a table value covers this path.
The lua_pop(L, 2) that removed the value before var_value was used is removed.
The debug typo is fixed: "function must have 2 arguments".
Regression coverage: collection-lua.json adds five cases with scripts setvar-error-nodot.lua, setvar-error-onearg.lua, setvar-error-unknown-collection.lua, setvar-error-table.lua and setvar-tx.lua. Each case expects nil from m.setvar and a debug message. The TX case checks that tx.a is set to x. The issue asks for a case that checks nil. These cases cover it.
Open point: a reviewer reported Windows segfaults. The provided comments do not include a Windows retest. This affects build verification only. I did not find a code requirement in #3731 that is unmet. The result is not affected by this point.
Full details: Out of Scope Changes check
Explanation
All changes in src/engine/lua.cc relate to #3731. The error-return changes, the argument-check reordering, the lua_pop removal and the typo fix are direct requirements. The new else branch logs "m.setvar: Unknown collection". It is a debug message only, and it supports the unknown-collection regression case that the PR author and reviewer discussed. It does not change any return value or TX/IP/other collection behavior. The test files are regression fixtures for #3731 behavior. The collection-lua.json entries cover only the setvar paths. I found no unrelated source or test changes in the reviewed diff.
Finishing Touches
Generate unit tests (beta)
Create a new PR
Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
File: No configuration file from this repository applied
Commit: Unavailable
Layers: defaults
Review profile: CHILL
Plan: Advanced
Run ID: 87dca497-caac-44c9-a1a1-611cdf934d04
Commits
Reviewing files that changed from the base of the PR and between 3b81dca and 9dfe9a1.
Files selected for processing: 3
src/engine/lua.cc
test/test-cases/data/setvar-error-table.lua
test/test-cases/regression/collection-lua.json
Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 6 remain after this review.
The reason will be displayed to describe this comment to others. Learn more.
🟢 Approval recommended
No active review issues remain, and the changes include targeted validation and regression coverage for the corrected invalid-call behavior.
No open issues 🎉
What changed in this PR
This pull request fixes Lua::setvar() so invalid calls return no Lua values instead of exposing stale stack data, while improving argument validation and adding regression coverage.
Changes:
Return 0 for incorrect argument counts and variable names without collections.
Validate Lua string arguments before constructing C++ strings.
Remove unsafe stack popping and correct the debug-message typo.
Add regression cases verifying invalid calls evaluate to nil.
File
Description
test/test-cases/regression/collection-lua.json
Adds regression cases for invalid m.setvar() calls.
The reason will be displayed to describe this comment to others. Learn more.
An unknown collection, e.g. m.setvar("FOO.bar", "x"), still falls through all the branches below without a message. Could you add a final else after the USER branch (after line 404), with a level 8 message like the one above, and the name escaped as in #3730?
I also started to work on your issue #3731, and here are the test cases for that. They follow your two cases, so they can go at the end of collection-lua.json:
The first one needs the new else branch, so it fails without it. The second one passes with and without this PR, it's only there to show that the success path still works and returns nil.
m.setvar("FOO.bar", "x") fell through every collection branch and was
ignored without a message. Log it at level 8, like the other m.setvar()
errors, with the name escaped.
Tests: assert the debug message on each error path as well as the nil
return, since m.setvar() also returns nil on success. Add cases for an
unknown collection, a successful TX set (both from @airween), and a
non-string value, which must fail the script with a Lua error.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RiUJuqXNvvpytiGRiDFyTy
Thanks @airween. I added both of your cases as they are in 3b81dca, with the new else branch. I also:
made the two original cases check the error debug message as well as the nil return, because m.setvar() returns nil on success too, so nil alone can't tell the paths apart;
added a case for a non-string value, m.setvar("tx.a", {}). It must fail the script with Lua's bad argument #2 to 'setvar', which covers the reordering of luaL_checkstring().
collection-lua.json now has 12 cases and they all pass, and the full make check gives 5142 total, 0 fail (macOS, Lua 5.5.1).
v2's l_setvar() has the same return -1 and lua_pop() problem, so I'm opening a separate v2 PR for it.
luaL_checkstring() raises a Lua error, which longjmps out of the C++
Lua::setvar() frame. The MSVC build segfaults on that path. Check the
arguments with lua_tostring() and return nil with a debug message, like
the other m.setvar() error paths.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
what
Fixes three problems in
Lua::setvar()(src/engine/lua.cc):0instead of-1. This covers the wrong number of arguments and a name with no collection. The script now getsnil.luaL_checkstring()is called before thestd::stringlocals are constructed. It raises a Lua error withlongjmpon a non-string argument, which would skip their destructors. This makes theNULLcheck after it unreachable, so that check is removed.lua_pop(L, 2)is removed. It popped the value argument whilevar_valuestill pointed into it. Alua_CFunction's stack is cleared on return anyway.why
A
lua_CFunctionreturns the number of values it pushed. With-1, Lua returned whatever was on the stack. With the two new test scripts on v3/master,m.setvar("novar", "x")returned the__transactionpointer (userdata: 0x…), andm.setvar("tx.a")returned a stray string.tests
collection-lua.json, with the scriptssetvar-error-nodot.luaandsetvar-error-onearg.lua, check that the script getsnil. Both fail on v3/master and pass with this change.action-exec,directive-sec_rule_script,operator-inpectFileandissue-2427.make check(macOS, Lua 5.5.1, PCRE2): 5139 total, 0 fail.references
🤖 Generated with Claude Code
Summary by CodeRabbit