-
-
Notifications
You must be signed in to change notification settings - Fork 972
Reject invalid databinding indexes #15804
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
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -333,13 +333,19 @@ class SimpleDataBinder implements DataBinder { | |
| } | ||
|
|
||
| if (propertyType.isArray()) { | ||
| def index = Integer.parseInt(indexedPropertyReferenceDescriptor.index) | ||
| Integer index = parseIndexedPropertyIndex(obj, indexedPropertyReferenceDescriptor, val, listener, errors) | ||
| if (index == null) { | ||
| return | ||
| } | ||
| def array = initializeArray(obj, propName, propertyType.componentType, index) | ||
| if (array != null) { | ||
| addElementToArrayAt(array, index, val) | ||
| } | ||
| } else if (Collection.isAssignableFrom(propertyType)) { | ||
| def index = Integer.parseInt(indexedPropertyReferenceDescriptor.index) | ||
| Integer index = parseIndexedPropertyIndex(obj, indexedPropertyReferenceDescriptor, val, listener, errors) | ||
| if (index == null) { | ||
| return | ||
| } | ||
| Collection collectionInstance = initializeCollection(obj, propName, propertyType) | ||
| def indexedInstance = null | ||
| if (!(Set.isAssignableFrom(propertyType))) { | ||
|
|
@@ -394,6 +400,22 @@ class SimpleDataBinder implements DataBinder { | |
| } | ||
| } | ||
|
|
||
| protected Integer parseIndexedPropertyIndex(obj, IndexedPropertyReferenceDescriptor indexedPropertyReferenceDescriptor, | ||
| val, DataBindingListener listener, errors) { | ||
|
|
||
| try { | ||
| Integer index = Integer.parseInt(indexedPropertyReferenceDescriptor.index) | ||
| if (index < 0) { | ||
| throw new NumberFormatException(indexedPropertyReferenceDescriptor.index) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since this path binds untrusted request data, the reported binding error must stay generic - indistinguishable from the malformed-index case - so the source cannot tell we handle negative indexes explicitly. The current shape achieves that, but only by accident of throwing |
||
| } | ||
| index | ||
| } | ||
| catch (NumberFormatException e) { | ||
| addBindingError(obj, indexedPropertyReferenceDescriptor.toString(), val, e, listener, errors) | ||
| null | ||
| } | ||
| } | ||
|
|
||
| @CompileStatic(TypeCheckingMode.SKIP) | ||
| protected initializeArray(obj, String propertyName, Class arrayType, int index) { | ||
| Object[] array = obj[propertyName] | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -434,6 +434,10 @@ class GrailsWebDataBinder extends SimpleDataBinder { | |
| if (referencedType != null && isDomainClass(referencedType)) { | ||
| needsBinding = false | ||
| if (Set.isAssignableFrom(metaProperty.type)) { | ||
| Integer index = parseIndexedPropertyIndex(obj, indexedPropertyReferenceDescriptor, val, listener, errors) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This changes documented behavior that the JavaBeans rationale does not cover in either direction: spec indexed properties are array-typed with |
||
| if (index == null) { | ||
| return | ||
| } | ||
| def collection = initializeCollection(obj, propName, metaProperty.type) | ||
| def instance | ||
| if (collection != null) { | ||
|
|
@@ -448,7 +452,7 @@ class GrailsWebDataBinder extends SimpleDataBinder { | |
| Exception e = new IllegalArgumentException(message) | ||
| addBindingError(obj, propName, idValue, e, listener, errors) | ||
| } else { | ||
| addElementToCollectionAt(obj, propName, collection, Integer.parseInt(indexedPropertyReferenceDescriptor.index), instance) | ||
| addElementToCollectionAt(obj, propName, collection, index, instance) | ||
| } | ||
| } | ||
| if (instance != null) { | ||
|
|
@@ -459,8 +463,11 @@ class GrailsWebDataBinder extends SimpleDataBinder { | |
| } | ||
| } | ||
| } else if (Collection.isAssignableFrom(metaProperty.type)) { | ||
| Integer idx = parseIndexedPropertyIndex(obj, indexedPropertyReferenceDescriptor, val, listener, errors) | ||
| if (idx == null) { | ||
| return | ||
| } | ||
| def collection = initializeCollection(obj, propName, metaProperty.type) | ||
| def idx = Integer.parseInt(indexedPropertyReferenceDescriptor.index) | ||
| if ('null' == idValue) { | ||
| if (idx < collection.size()) { | ||
| def element = collection[idx] | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rejecting negative indexes is the correct behavior: the JavaBeans specification (v1.01, section 7.2) defines indexed properties as array-typed properties with paired
int-indexed accessors, where an invalid index may throwArrayIndexOutOfBoundsException. Grails' indexed binding to collections is an extension of that model, and this change aligns the extension with the spec's array semantics - the prior[-1]behavior was Groovy list semantics leaking through, never valid under the beans model. Please reference the spec section in this method's groovydoc and in the PR description so the rationale is on record.