-
Notifications
You must be signed in to change notification settings - Fork 160
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Lack of Input Validation in Solver Parameters Allows Arbitrary Key-Value Pairs #3968
Comments
Thanks for the note on this -- I agree this is a challenge, and have wrangled with such parameter errors many times. However, our parameter dictionaries are really just providing a "pass-through" service to the PETSc options database, and dont' actually know what the list of valid parameters are. It also depends on what options PETSc was configured with. To validate, we would need each PETSc object (including third-party extensions!) to provide a list of what available options and their types/value ranges are supported. I think this is actually a quite hard problem that may be mostly beyond Firedrake's control? At any rate, PETSc's |
Thank you so much, @rckirby, for your prompt response! I now have a much clearer understanding of the issue.
Can this parameter be enabled directly from within Firedrake, or does it require calling PETSc explicitly? Additionally, would you happen to know if there’s a way to call a PETSc function solely for input validation prior to creating Firedrake objects and running the simulation? If yes, that would be really helpful. |
I think I believe that it is enabled by default but only for command line options. Running a Firedrake script
produces
I think this only works at the outermost level and does not propagate through to the solver options dictionaries.
Almost certainly not. The instantiation of Firedrake objects dynamically declares a lot of these parameters before which validation can't work. |
This is a bugbear of mine too. I would really love PETSc to fix this but it's a huge job so it's unlikely to happen, sadly. |
@JHopeCollins realised why |
Would it help to just not pop the options after the solve?
On 14 Jan 2025, at 16:04, David A. Ham ***@***.***> wrote:
This is a bugbear of mine too. I would really love PETSc to fix this but it's a huge job so it's unlikely to happen, sadly.
—
Reply to this email directly, view it on GitHub<#3968 (comment)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/ABOSV4SOA7QWWKDXLVLJ2BT2KUYSPAVCNFSM6AAAAABVC5WSLSVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDKOJQGM2TENBQGE>.
You are receiving this because you are subscribed to this thread.Message ID: ***@***.***>
|
Could we perform the unused check on the options at the time that we pop them? |
There's a number of questions/thoughts I had about the way the options manager handles options.
|
This is a good idea, and should be relatively easy to do. If the option hasn't been used we could keep it in the global dictionary so it still gets picked up in PETSc Finalize. |
But this pollutes the global state in potentially quite a strange way. |
Could keep a |
In principle I might be ok with "polluting" global state (which we would also do if we don't pop the options after each solve) because I don't think PETSc expects/wants you to ever have multiple objects with the same prefix but different options. |
By default, every new solver in firedrake has a unique prefix. If you never pop the options out of the database after running the solve then it grows unboundedly -> BAD (used to be really bad because the options database was fixed size, so you would get a crash). Now you just get a hard-to-diagnose memory leak. You could solve that by changing the firedrake defaults so that every solver by default has the same (empty) prefix. But now, a solve with options specifies pollutes another solve without options |
What you could do is implement a per-solve options_left with https://petsc.org/release/manualpages/Sys/PetscOptionsUsed/, which you can use to query if a particular solve used all the options specified in the solver_parameters dictionary. Unfortunately, this isn't quite perfect, because for reasons (I think it could be fixed), any PETSc option that is only inspected via petsc4py doesn't get marked as used (or at least it didn't used to) |
Oh yes, I knew there was something else I had about the options manager. If you don't provide the manager a prefix then it generates that unique one, and then also ignores any command line options - this makes sense because the unique prefix isn't stable if you later modify the code. However, last time I checked, if you do try to pass a command line option to that unique prefix, then it is both ignored by the options manager, and also doesn't show up in What if the options manager only inserted options permanently into the global options if you also provide a prefix? If you don't provide a prefix then it generates the unique one and does the insertion/removal as it currently does. |
A per-solve options_left could be really handy for dealing with the parameters dictionary though, if the petsc4py bug is/can be easily fixed. |
Great to see solutions being suggested. Thank you.
Is this solution something to be implemented within firedrake or is it something that the users of firedrake can apply? |
As far as I can see, |
Ah great, so I could contact the petsc4py maintainers, right? |
Yes you could create an issue on PETSc GitLab (and please link to it here). Adding new bindings is usually straightforward. I would be interested in getting the PETSc devs insights on how difficult it would be to address the issue of petsc4py not marking options as used. |
While creating a minimal reproducer for the petsc issue, I noticed the options that are inspected (i.e. read) in Python are actually considered used (at least they don't show up in the list of unused parameters). @wence- this is what you were referring to, right? Can we consider that particular issue of petsc4py fixed now? from petsc4py import PETSc
snes = PETSc.SNES().create()
options = PETSc.Options()
solver_parameters = {
"snes_max_it": 10, # valid option
"read_param": "55", # inspected option
"unread_param": 33 # uninspected option
}
for key, value in solver_parameters.items():
options[key] = value
c1 = options['read_param'] # reading/inspecting
snes.setFromOptions()
# > WARNING! There are options you set that were not used!
# > WARNING! could be spelling mistake, etc!
# > There is one unused database option. It is:
# > Option left: name:-unread_param value: 33 source: code The version of petsc4py I use is 3.22.2
|
I think that might be good enough. But what about if you use the programmatic interface from python |
I just tried that, it behaves the same as reading it via index access. from petsc4py import PETSc
snes = PETSc.SNES().create()
options = PETSc.Options()
solver_parameters = {
"snes_max_it": 10, # valid option
"read_param": "55", # inspected option
"unread_param": 33 # uninspected option
}
for key, value in solver_parameters.items():
options[key] = value
read_value = options.getString("read_param")
snes.setFromOptions()
# OUTPUT:
# > WARNING! There are options you set that were not used!
# > WARNING! could be spelling mistake, etc!
# > There is one unused database option. It is:
# > Option left: name:-unread_param value: 33 source: code |
Here is the petsc issue: https://gitlab.com/petsc/petsc/-/issues/1704 |
I see Matt Knepley seems to have implemented it immediately. Does his fix work for you? |
I confirm it does work fine. The new from petsc4py import PETSc
snes = PETSc.SNES().create()
options = PETSc.Options()
solver_parameters = {
"snes_max_it": 10, # valid option
"read_param": "55", # inspected option
"unread_param": 33 # uninspected option
}
for key, value in solver_parameters.items():
options[key] = value
read_value = options.getString("read_param")
print(f"read_param is used?: {options.used('read_param')}") # prints true
print(f"unread_param is used?: {options.used('unread_param')}") # prints false
snes.setFromOptions()
# > WARNING! There are options you set that were not used!
# > WARNING! could be spelling mistake, etc!
# > There is one unused database option. It is:
# > Option left: name:-unread_param value: 33 source: code
# NOTE: these results are not affected after calling options.used(). |
The change is merged to petsc 🎉 Looking forward to the new Firedrake bindings. |
https://github.com/firedrakeproject/firedrake/tree/warn_unused_options is a completely untested implementation of the Firedrake part of the change. We need to merge PETSc main into our PETSc fork in order to test it (or externally build PETSc main). |
Describe the current issue
Happy New Year! 🎉
Thank you for developing and maintaining Firedrake—it’s an exceptional tool. We’ve noticed an issue that could enhance its robustness and usability.
Currently, the code snippet below runs without any errors, even with invalid or nonsensical
solver_parameters
. For example:"snes_rtolx"
instead of"snes_rtol"
is silently ignored, potentially causing incorrect solver behavior.None
instead of a boolean likeFalse
, also doesn’t raise an error, leading to undefined behavior.This lack of validation can result in unnoticed configuration errors, wasted resources, or incorrect results, particularly when such mistakes persist for extended periods.
Would it be possible to validate parameter names and types before creating the solver object? This improvement would greatly enhance reliability and help users avoid subtle but critical mistakes. Thank you!
Describe the solution you'd like
To address this issue, input validation should be implemented for solver parameters:
Key Validation:
Type Validation:
For example, the following input should raise an error:
Additional info
This issue is a classic example of improper input validation, a vulnerability listed by CWE MITRE as CWE-20: Improper Input Validation. Addressing this not only improves user experience but also aligns Firedrake with best practices for software reliability.
The text was updated successfully, but these errors were encountered: