Fix crash when monotone_constraints_method is set without monotone_constraints#7203
Fix crash when monotone_constraints_method is set without monotone_constraints#7203Shreyas-S-809 wants to merge 7 commits intolightgbm-org:masterfrom
Conversation
…notone_constraints
jameslamb
left a comment
There was a problem hiding this comment.
Thanks for attempting this! Please see my initial suggestions.
| @@ -0,0 +1,28 @@ | |||
| import lightgbm as lgb | |||
There was a problem hiding this comment.
We don't want totally new test file here. Please, add a new test case around the existing monotone constraints tests here:
LightGBM/tests/python_package_test/test_engine.py
Line 2186 in 8e7f3dc
When you do that, please:
- follow the conventions you see in that file (e.g. using one of the dataset fixtures or other approaches that provides enough data to train a real model)
- expand the test to check that
monotone_constraints_methodis still preserved in the Booster'sparams - check that the expected warning is emitted
- example:
LightGBM/tests/python_package_test/test_engine.py
Line 4690 in 8e7f3dc
- example:
There was a problem hiding this comment.
Ohh, sorry for that,
Removed standalone test file and integrate test into existing
test_engine.py following project conventions.
| monotone_constraints_method.c_str()); | ||
|
|
||
| monotone_constraints_method = "basic"; | ||
| } |
There was a problem hiding this comment.
CheckParamConflict() seems like a good place to do a check like this, but I don't understand how changing this to "basic" avoids the error.
Can you please links to the place(s) in the code where the segfault originates? I think seeing the root cause of the problem will help us to evaluate possible fixes.
There was a problem hiding this comment.
Thanks for the detailed feedback!
I've updated the tests to add a new test case in test_engine.py, following the existing structure and dataset utilities. The test verifies that:
- a warning is emitted when
monotone_constraints_methodis set withoutmonotone_constraints - training completes without crashing
- the method falls back to
"basic"
I've also run pre-commit run --all-files locally and fixed the linting issues.
Regarding the segfault: my understanding is that when monotone_constraints_method is set to "advanced" or "intermediate" but monotone_constraints is empty, later stages of training (in the tree learner logic) assume that constraints are available and attempt to access them. This leads to invalid memory access and causes a segmentation fault.
Falling back to "basic" avoids those code paths that rely on non-empty monotone constraints.
I will continue investigating to identify the exact location in the code where this invalid access occurs and will update the PR with more precise references.
There was a problem hiding this comment.
Thanks for this, but yes I think you'll need to go a bit deeper and find the root cause of the segfaults. There may be other codepaths to reach that code, and we should fix this problem at the root (e.g., maybe we need to check some that some pointers are non-null or something).
If you're not confident that you can do that, then let me know and I can try to help when I have time.
There was a problem hiding this comment.
Thanks, that makes sense — I agree we should fix this at the root.
I’ll start tracing where monotone_constraints is accessed during training to identify the exact source of the segfault.
Just to make sure I’m looking in the right place: would you expect the issue to originate in the tree learner logic (e.g., histogram construction or split finding), or somewhere earlier in parameter handling?
Also, are there any specific files or components you’d recommend focusing on for this?
Thanks again — this is really helpful.
There was a problem hiding this comment.
You will have to figure that out.
A good place to start:
git grep -i monotone
git grep -i constraintsThere was a problem hiding this comment.
It looks to me like your new commit added new code but didn't remove this parameter-manipulation or update the tests. Please, do those things.
And if you are using LLMs to help you that's fine, but please review the code yourself and please write comments in these discussion threads yourself.
There was a problem hiding this comment.
It looks to me like your new commit added new code but didn't remove this parameter-manipulation or update the tests. Please, do those things.
And if you are using LLMs to help you that's fine, but please review the code yourself and please write comments in these discussion threads yourself.
Thanks for the feedback. @jameslamb
I’m planning to:
- Remove the override of
monotone_constraints_method = "basic"in config.cpp - Skip creating and using constraints entirely in the tree learner when
monotone_constraintsis empty (using nullptr guards) - Update tests to reflect that
monotone_constraints_methodis preserved but ignored
Does this align with your expectation of avoiding all constraints-related code paths?
There was a problem hiding this comment.
yes
Thanks for the feedback @jameslamb .
I’ve updated the PR to avoid mutating monotone_constraints_method and instead skip all monotone-constraint-related code paths when monotone_constraints is empty.
Specifically:
- removed the fallback logic in
config.cpp - ensured constraints are not initialized when not needed
- added guards to avoid accessing constraints when they are not present
- updated the test to check that the parameter is preserved and only ignored internally
Let me know if this approach aligns with what you had in mind, or if you'd like it handled differently.
There was a problem hiding this comment.
yes
hey @jameslamb , just checking if any changes are needed from my side. or waiting to be reviewed.
|
Please do also run the linting / autoformatting locally before pushing commits. pre-commit run --all-filesDocs on |
…onstraints Add test case in test_engine.py to verify that setting monotone_constraints_method without monotone_constraints: - emits a warning - does not crash training - falls back to 'basic' Follows existing test structure and dataset utilities.
Remove standalone test file and integrate test into existing test_engine.py following project conventions. Also add coverage for monotone_constraints_method without monotone_constraints to ensure warning is emitted and fallback to 'basic' occurs.
Thanks for the review, i have updated the PR, please take a look and let me know if any changes are required. |
… is empty When monotone_constraints is empty, the constraints factory still created AdvancedLeafConstraints or IntermediateLeafConstraints based on monotone_constraints_method. These implementations assume valid constraint data and can lead to invalid memory access. This change updates LeafConstraintsBase::Create() to return BasicLeafConstraints when no monotone constraints are provided, effectively disabling constraint-specific logic without modifying user parameters. This avoids unintended side effects from mutating configuration while ensuring safe execution paths.
Ensure that monotone constraints logic is completely bypassed when monotone_constraints is not provided, instead of mutating monotone_constraints_method or falling back to 'basic'. Changes: - Avoid initializing constraint structures when no monotone constraints are set in serial_tree_learner.cpp - Guard all constraint-related calls to prevent null dereferencing - Remove parameter mutation logic from config.cpp that overwrote monotone_constraints_method - Ensure monotone_constraints_method is preserved as provided by the user - Update tests in est_engine.py to verify: - warnings are emitted - parameter is preserved - training completes without errors This approach eliminates unintended side effects and ensures that constraint-specific logic is only executed when explicitly requested.
Summary
This PR fixes a crash that occurs when
monotone_constraints_methodis set to
"intermediate"or"advanced"whilemonotone_constraintsis not provided.Previously, this configuration could lead to a segmentation fault
during training when monotone constraint logic attempted to access
an empty constraints vector.
Fix
A validation check has been added in
Config::CheckParamConflict()to detect this configuration and gracefully handle it by:
"basic"monotone constraints methodThis ensures that training proceeds safely without crashing.
Tests
A new unit test has been added to verify that training completes
successfully when
monotone_constraints_methodis provided withoutmonotone_constraints.All existing Python package tests pass locally.
Example