From adam.sotona at oracle.com Tue Sep 5 09:17:17 2023 From: adam.sotona at oracle.com (Adam Sotona) Date: Tue, 5 Sep 2023 09:17:17 +0000 Subject: Attribute safety In-Reply-To: <744677dd-82aa-1330-8baa-01ed7fc1ed60@oracle.com> References: <744677dd-82aa-1330-8baa-01ed7fc1ed60@oracle.com> Message-ID: I?ve updated https://github.com/openjdk/jdk/pull/15101 so it filters on read and write based on the Classfile.AttributesProcessingOption context option. Or I can prepare a patch with filtering transformations (as proposed below). Or is there any other way? Thanks, Adam From: Brian Goetz Date: Wednesday, 23 August 2023 19:26 To: Adam Sotona , classfile-api-dev at openjdk.org Subject: Re: Attribute safety Just a further thought on this: we can further focus our lens on _bound_ attributes, because these are the ones that have come from another classfile. If the user creates a RVAA during a transform, we should assume that is fine, just as we do with writing. On 8/7/2023 6:46 AM, Adam Sotona wrote: That makes perfect sense, attribute safety is more exactly an attribute transformation safety. I agree that introduction of special read/write filters (in a form of context options) is confusing and non-systematic. When we focus on the implementation of the attributes transformation safety, I think the safety switch is less of a global context option but rather individual transformation immediate feature (a filtering feature). If we implement it as a global context option, we would have to insert a filtering layer before each transformation (on read side) or after (on write side) of each transformation. I think it would be pretty much the same as filtering on read/write, except for the fact it will affect transformations only (so maybe even more confusing). Classfile::transform would then behave differently than its expanded form using Classfile::build. However if we implement attribute transformation safety as specific transformations (doing the filtering job) ? it should work in harmony with the rest of the API. For example in addition to ClassTransform.ACCEPT_ALL we can add ClassTransform.ACCEPT_ALL_KNOWN_ATTRIBUTES (dropping UNKNOWN) and ClassTransform.ACCEPT_ALL_SAFE_ATTRIBUTES (dropping HAZMAT). As an interesting expansion of the ClassfileTransform features we can provide factories like for example ClassfileTransform::dropingAll(Predicate filter) ? where the ?All? (or ?Deep? or similar suffix) should indicate forced expansion of the whole tree, so the filter is really applied on all levels and filtered element never appears in the target class. It can be used to implement the global filtering transformations. I propose to add following set of filtering transformations: 1. ClassTransform.ACCEPT_ALL_KNOWN_ATTRIBUTES 2. ClassTransform.ACCEPT_ALL_SAFE_ATTRIBUTES 3. FieldTransform.ACCEPT_ALL_KNOWN_ATTRIBUTES 4. FieldTransform.ACCEPT_ALL_SAFE_ATTRIBUTES 5. MethodTransform.ACCEPT_ALL_KNOWN_ATTRIBUTES 6. MethodTransform.ACCEPT_ALL_SAFE_ATTRIBUTES 7. CodeTransform.ACCEPT_ALL_KNOWN_ATTRIBUTES 8. CodeTransform.ACCEPT_ALL_SAFE_ATTRIBUTES Thanks, Adam From: Brian Goetz Date: Saturday, 5 August 2023 3:01 To: Adam Sotona , classfile-api-dev at openjdk.org Subject: Re: Attribute safety OK, I thought about this some more while sitting in the sauna ... I think the locus of attribute safety is not reading or writing, but transforming. If I am just going to read a classfile, there is no need to drop anything, if I find an attribute I don't recognize, I'll just skip over it and keep going -- that's how attributes are designed to work. No need to drop anything on read, ever. WHen the library finds an unknown attribute, it wraps it with an UnknownAttribute element, whose understanding to the attribute is limited to name, size, and byte[] of the payload. Nothing so dangerous here that the user needs protection. Similarly, if a user is _writing_ a classfile, again, we should trust them that the classfile they are putting together is sensible. We shouldn't second guess at "oh, that's a type annotations attribute, those are so brittle, please sign here." Where there is potentially a problem is when we are _transforming_ a classfile, because for a HAZMAT or UNKNOWN attribute, we can't guarantee its integrity if we've changed anything else about the classfile (including reordering the constant pool.) So the "what do we do with brittle attributes" question applies only to transformation, where we are taking an attribute from one classfile (a bound attribute) and writing it to another. This is where the user can shoot themselves in the foot, because they might change something else about the classfile and subtly (or not subtly) undermine the integrity of the annotation they don't understand. And this is why we want to classify attributes according to their sensitivity to environmental change: - A stateless attribute is sensitive to no environmental changes. A transform can always safely bulk-copy the attribute directly. - An attribute with CP dependencies is sensitive to restructuring of the constant pool (no CP sharing), but the mapper contains enough information to survive CP restructuring. A transform can safely bulk-copy the attribute directly if the CP is shared between the original and new classfile, and can otherwise safely copy the attribute by inflating it and deflating it via the readAttribute/writeAttribute behavior of the mapper. - An attribute with label dependencies is sensitive to changes to the contents or structure of the bytecode array. A transform can safely bulk-copy the attribute directly if code array is unchanged, and can otherwise safely copy the attribute by inflating it and deflating it via the readAttribute/writeAttribute behavior of the mapper. However, there are currently no attributes that have label dependencies only but are not already treated specially by the classfile API, so this category may not be that interesting. - An attribute with unpredictable dependencies is sensitive to any change to the contents of the entity of which it is an attribute. It can be safely bulk-copied if nothing else in that entity has changed, but otherwise there is no safe way to copy it. - An unknown attribute is sensitive to all of the above, and so takes on the union of the copying risks of all of the above. So I think the Option we want governs what to do with various attributes when _transforming_ a CompoundElement in which they appear. And the problematic cases are those with unpredictable dependencies, and unknowns. So I think the options we want are: - When transforming, always keep HAZMAT and UNKNOWN attributes; for safety, lift and lower HAZMAT attributes. - When transforming, keep HAZMAT attributes (lifting and lowering), but always drop UNKNOWN attributes. - When transforming, always drop HAZMAT and UNKNOWN attributes. -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Tue Sep 5 12:40:53 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 5 Sep 2023 12:40:53 +0000 Subject: Attribute safety In-Reply-To: References: <744677dd-82aa-1330-8baa-01ed7fc1ed60@oracle.com> Message-ID: <12B85AFE-EA45-4685-B34C-F29134B23EEB@oracle.com> Some review comments on this patch. Attributes with the LABELS stability need only be exploded and rewritten when the Code array is perturbed. In practicality, LABELS attributes will also contain CP refs, so the doc should really suggest ?labels *and* CP refs?. HAZMAT can be renamed to UNSTABLE (yeah, I know HAZMAT is a cool name.) Doc on AttributeProcessingOPtion should make it clear that this is only during _transformation_; during reading/writing, all attributes are passed normally. What should be the default here? PASS, or DROP_UNSTABLE? Now that the choices are simpler, I think you can add (constant) transforms for {CLASS,METHOD,FIELD,CODE}_drop{Unknown,Unstable}, and compose these in when the user calls transform() and the option setting is not PASS_ALL? On Sep 5, 2023, at 5:17 AM, Adam Sotona > wrote: I?ve updated https://github.com/openjdk/jdk/pull/15101 so it filters on read and write based on the Classfile.AttributesProcessingOption context option. Or I can prepare a patch with filtering transformations (as proposed below). Or is there any other way? Thanks, Adam From: Brian Goetz > Date: Wednesday, 23 August 2023 19:26 To: Adam Sotona >, classfile-api-dev at openjdk.org > Subject: Re: Attribute safety Just a further thought on this: we can further focus our lens on _bound_ attributes, because these are the ones that have come from another classfile. If the user creates a RVAA during a transform, we should assume that is fine, just as we do with writing. On 8/7/2023 6:46 AM, Adam Sotona wrote: That makes perfect sense, attribute safety is more exactly an attribute transformation safety. I agree that introduction of special read/write filters (in a form of context options) is confusing and non-systematic. When we focus on the implementation of the attributes transformation safety, I think the safety switch is less of a global context option but rather individual transformation immediate feature (a filtering feature). If we implement it as a global context option, we would have to insert a filtering layer before each transformation (on read side) or after (on write side) of each transformation. I think it would be pretty much the same as filtering on read/write, except for the fact it will affect transformations only (so maybe even more confusing). Classfile::transform would then behave differently than its expanded form using Classfile::build. However if we implement attribute transformation safety as specific transformations (doing the filtering job) ? it should work in harmony with the rest of the API. For example in addition to ClassTransform.ACCEPT_ALL we can add ClassTransform.ACCEPT_ALL_KNOWN_ATTRIBUTES (dropping UNKNOWN) and ClassTransform.ACCEPT_ALL_SAFE_ATTRIBUTES (dropping HAZMAT). As an interesting expansion of the ClassfileTransform features we can provide factories like for example ClassfileTransform::dropingAll(Predicate filter) ? where the ?All? (or ?Deep? or similar suffix) should indicate forced expansion of the whole tree, so the filter is really applied on all levels and filtered element never appears in the target class. It can be used to implement the global filtering transformations. I propose to add following set of filtering transformations: 1. ClassTransform.ACCEPT_ALL_KNOWN_ATTRIBUTES 2. ClassTransform.ACCEPT_ALL_SAFE_ATTRIBUTES 3. FieldTransform.ACCEPT_ALL_KNOWN_ATTRIBUTES 4. FieldTransform.ACCEPT_ALL_SAFE_ATTRIBUTES 5. MethodTransform.ACCEPT_ALL_KNOWN_ATTRIBUTES 6. MethodTransform.ACCEPT_ALL_SAFE_ATTRIBUTES 7. CodeTransform.ACCEPT_ALL_KNOWN_ATTRIBUTES 8. CodeTransform.ACCEPT_ALL_SAFE_ATTRIBUTES Thanks, Adam From: Brian Goetz Date: Saturday, 5 August 2023 3:01 To: Adam Sotona , classfile-api-dev at openjdk.org Subject: Re: Attribute safety OK, I thought about this some more while sitting in the sauna ... I think the locus of attribute safety is not reading or writing, but transforming. If I am just going to read a classfile, there is no need to drop anything, if I find an attribute I don't recognize, I'll just skip over it and keep going -- that's how attributes are designed to work. No need to drop anything on read, ever. WHen the library finds an unknown attribute, it wraps it with an UnknownAttribute element, whose understanding to the attribute is limited to name, size, and byte[] of the payload. Nothing so dangerous here that the user needs protection. Similarly, if a user is _writing_ a classfile, again, we should trust them that the classfile they are putting together is sensible. We shouldn't second guess at "oh, that's a type annotations attribute, those are so brittle, please sign here." Where there is potentially a problem is when we are _transforming_ a classfile, because for a HAZMAT or UNKNOWN attribute, we can't guarantee its integrity if we've changed anything else about the classfile (including reordering the constant pool.) So the "what do we do with brittle attributes" question applies only to transformation, where we are taking an attribute from one classfile (a bound attribute) and writing it to another. This is where the user can shoot themselves in the foot, because they might change something else about the classfile and subtly (or not subtly) undermine the integrity of the annotation they don't understand. And this is why we want to classify attributes according to their sensitivity to environmental change: - A stateless attribute is sensitive to no environmental changes. A transform can always safely bulk-copy the attribute directly. - An attribute with CP dependencies is sensitive to restructuring of the constant pool (no CP sharing), but the mapper contains enough information to survive CP restructuring. A transform can safely bulk-copy the attribute directly if the CP is shared between the original and new classfile, and can otherwise safely copy the attribute by inflating it and deflating it via the readAttribute/writeAttribute behavior of the mapper. - An attribute with label dependencies is sensitive to changes to the contents or structure of the bytecode array. A transform can safely bulk-copy the attribute directly if code array is unchanged, and can otherwise safely copy the attribute by inflating it and deflating it via the readAttribute/writeAttribute behavior of the mapper. However, there are currently no attributes that have label dependencies only but are not already treated specially by the classfile API, so this category may not be that interesting. - An attribute with unpredictable dependencies is sensitive to any change to the contents of the entity of which it is an attribute. It can be safely bulk-copied if nothing else in that entity has changed, but otherwise there is no safe way to copy it. - An unknown attribute is sensitive to all of the above, and so takes on the union of the copying risks of all of the above. So I think the Option we want governs what to do with various attributes when _transforming_ a CompoundElement in which they appear. And the problematic cases are those with unpredictable dependencies, and unknowns. So I think the options we want are: - When transforming, always keep HAZMAT and UNKNOWN attributes; for safety, lift and lower HAZMAT attributes. - When transforming, keep HAZMAT attributes (lifting and lowering), but always drop UNKNOWN attributes. - When transforming, always drop HAZMAT and UNKNOWN attributes. -------------- next part -------------- An HTML attachment was scrubbed... URL: From adam.sotona at oracle.com Tue Sep 5 14:59:05 2023 From: adam.sotona at oracle.com (Adam Sotona) Date: Tue, 5 Sep 2023 14:59:05 +0000 Subject: Attribute safety In-Reply-To: <12B85AFE-EA45-4685-B34C-F29134B23EEB@oracle.com> References: <744677dd-82aa-1330-8baa-01ed7fc1ed60@oracle.com> <12B85AFE-EA45-4685-B34C-F29134B23EEB@oracle.com> Message-ID: I probably bgought a bit of confusion here. The pr/15101 is the original ?global context option? proposal (just updated with the latest changes). It filters the attributes on read and on write based on the context option. I found hard to determine when to write an attribute based on its bound or unbound origin. We cannot determine if user pass down the transformation a bound attribute intentionally or unintentionally (and so we should or should not write it to the class). Filtering at transformation would be an alternative way, where we don?t need any Classfile.AttributeProcessingOption at all. Parsed and written will be always everything and specific transformations will always explode and filter respective attributes at all class model levels. For example ClassTransform.ACCEPT_ALL_SAFE_ATTRIBUTES will always explode class model down to the code and filter out all TypeAnnotations (while ClassTransform.ACCEPT_ALL does not need to explode anything). From: Brian Goetz Date: Tuesday, 5 September 2023 14:40 To: Adam Sotona Cc: classfile-api-dev at openjdk.org Subject: Re: Attribute safety Some review comments on this patch. Attributes with the LABELS stability need only be exploded and rewritten when the Code array is perturbed. In practicality, LABELS attributes will also contain CP refs, so the doc should really suggest ?labels *and* CP refs?. HAZMAT can be renamed to UNSTABLE (yeah, I know HAZMAT is a cool name.) Doc on AttributeProcessingOPtion should make it clear that this is only during _transformation_; during reading/writing, all attributes are passed normally. What should be the default here? PASS, or DROP_UNSTABLE? Now that the choices are simpler, I think you can add (constant) transforms for {CLASS,METHOD,FIELD,CODE}_drop{Unknown,Unstable}, and compose these in when the user calls transform() and the option setting is not PASS_ALL? On Sep 5, 2023, at 5:17 AM, Adam Sotona > wrote: I?ve updated https://github.com/openjdk/jdk/pull/15101 so it filters on read and write based on the Classfile.AttributesProcessingOption context option. Or I can prepare a patch with filtering transformations (as proposed below). Or is there any other way? Thanks, Adam From: Brian Goetz > Date: Wednesday, 23 August 2023 19:26 To: Adam Sotona >, classfile-api-dev at openjdk.org > Subject: Re: Attribute safety Just a further thought on this: we can further focus our lens on _bound_ attributes, because these are the ones that have come from another classfile. If the user creates a RVAA during a transform, we should assume that is fine, just as we do with writing. On 8/7/2023 6:46 AM, Adam Sotona wrote: That makes perfect sense, attribute safety is more exactly an attribute transformation safety. I agree that introduction of special read/write filters (in a form of context options) is confusing and non-systematic. When we focus on the implementation of the attributes transformation safety, I think the safety switch is less of a global context option but rather individual transformation immediate feature (a filtering feature). If we implement it as a global context option, we would have to insert a filtering layer before each transformation (on read side) or after (on write side) of each transformation. I think it would be pretty much the same as filtering on read/write, except for the fact it will affect transformations only (so maybe even more confusing). Classfile::transform would then behave differently than its expanded form using Classfile::build. However if we implement attribute transformation safety as specific transformations (doing the filtering job) ? it should work in harmony with the rest of the API. For example in addition to ClassTransform.ACCEPT_ALL we can add ClassTransform.ACCEPT_ALL_KNOWN_ATTRIBUTES (dropping UNKNOWN) and ClassTransform.ACCEPT_ALL_SAFE_ATTRIBUTES (dropping HAZMAT). As an interesting expansion of the ClassfileTransform features we can provide factories like for example ClassfileTransform::dropingAll(Predicate filter) ? where the ?All? (or ?Deep? or similar suffix) should indicate forced expansion of the whole tree, so the filter is really applied on all levels and filtered element never appears in the target class. It can be used to implement the global filtering transformations. I propose to add following set of filtering transformations: 1. ClassTransform.ACCEPT_ALL_KNOWN_ATTRIBUTES 2. ClassTransform.ACCEPT_ALL_SAFE_ATTRIBUTES 3. FieldTransform.ACCEPT_ALL_KNOWN_ATTRIBUTES 4. FieldTransform.ACCEPT_ALL_SAFE_ATTRIBUTES 5. MethodTransform.ACCEPT_ALL_KNOWN_ATTRIBUTES 6. MethodTransform.ACCEPT_ALL_SAFE_ATTRIBUTES 7. CodeTransform.ACCEPT_ALL_KNOWN_ATTRIBUTES 8. CodeTransform.ACCEPT_ALL_SAFE_ATTRIBUTES Thanks, Adam From: Brian Goetz Date: Saturday, 5 August 2023 3:01 To: Adam Sotona , classfile-api-dev at openjdk.org Subject: Re: Attribute safety OK, I thought about this some more while sitting in the sauna ... I think the locus of attribute safety is not reading or writing, but transforming. If I am just going to read a classfile, there is no need to drop anything, if I find an attribute I don't recognize, I'll just skip over it and keep going -- that's how attributes are designed to work. No need to drop anything on read, ever. WHen the library finds an unknown attribute, it wraps it with an UnknownAttribute element, whose understanding to the attribute is limited to name, size, and byte[] of the payload. Nothing so dangerous here that the user needs protection. Similarly, if a user is _writing_ a classfile, again, we should trust them that the classfile they are putting together is sensible. We shouldn't second guess at "oh, that's a type annotations attribute, those are so brittle, please sign here." Where there is potentially a problem is when we are _transforming_ a classfile, because for a HAZMAT or UNKNOWN attribute, we can't guarantee its integrity if we've changed anything else about the classfile (including reordering the constant pool.) So the "what do we do with brittle attributes" question applies only to transformation, where we are taking an attribute from one classfile (a bound attribute) and writing it to another. This is where the user can shoot themselves in the foot, because they might change something else about the classfile and subtly (or not subtly) undermine the integrity of the annotation they don't understand. And this is why we want to classify attributes according to their sensitivity to environmental change: - A stateless attribute is sensitive to no environmental changes. A transform can always safely bulk-copy the attribute directly. - An attribute with CP dependencies is sensitive to restructuring of the constant pool (no CP sharing), but the mapper contains enough information to survive CP restructuring. A transform can safely bulk-copy the attribute directly if the CP is shared between the original and new classfile, and can otherwise safely copy the attribute by inflating it and deflating it via the readAttribute/writeAttribute behavior of the mapper. - An attribute with label dependencies is sensitive to changes to the contents or structure of the bytecode array. A transform can safely bulk-copy the attribute directly if code array is unchanged, and can otherwise safely copy the attribute by inflating it and deflating it via the readAttribute/writeAttribute behavior of the mapper. However, there are currently no attributes that have label dependencies only but are not already treated specially by the classfile API, so this category may not be that interesting. - An attribute with unpredictable dependencies is sensitive to any change to the contents of the entity of which it is an attribute. It can be safely bulk-copied if nothing else in that entity has changed, but otherwise there is no safe way to copy it. - An unknown attribute is sensitive to all of the above, and so takes on the union of the copying risks of all of the above. So I think the Option we want governs what to do with various attributes when _transforming_ a CompoundElement in which they appear. And the problematic cases are those with unpredictable dependencies, and unknowns. So I think the options we want are: - When transforming, always keep HAZMAT and UNKNOWN attributes; for safety, lift and lower HAZMAT attributes. - When transforming, keep HAZMAT attributes (lifting and lowering), but always drop UNKNOWN attributes. - When transforming, always drop HAZMAT and UNKNOWN attributes. -------------- next part -------------- An HTML attachment was scrubbed... URL: From adam.sotona at oracle.com Wed Sep 6 08:31:19 2023 From: adam.sotona at oracle.com (Adam Sotona) Date: Wed, 6 Sep 2023 08:31:19 +0000 Subject: Attribute safety In-Reply-To: <3F78A8DD-0E33-4C8E-AEC8-2EB8E44DAA62@oracle.com> References: <744677dd-82aa-1330-8baa-01ed7fc1ed60@oracle.com> <12B85AFE-EA45-4685-B34C-F29134B23EEB@oracle.com> <3F78A8DD-0E33-4C8E-AEC8-2EB8E44DAA62@oracle.com> Message-ID: OK, it makes sense, I?ll update pr/15101 to filter only bound attrs on write. Thanks, Adam From: Brian Goetz Date: Tuesday, 5 September 2023 19:08 To: Adam Sotona Cc: classfile-api-dev at openjdk.org Subject: Re: Attribute safety I probably bgought a bit of confusion here. The pr/15101 is the original ?global context option? proposal (just updated with the latest changes). It filters the attributes on read and on write based on the context option. I found hard to determine when to write an attribute based on its bound or unbound origin. We cannot determine if user pass down the transformation a bound attribute intentionally or unintentionally (and so we should or should not write it to the class). Yes, what I?m suggesting is not entirely precise, but the window of error is narrowed. We should filter nothing on read (since people ignore unsupported attributes). The remaining question is whether we are comfortable discriminating against attributes based on a two-dimensional filter ? Bound and ?below the stability threshold?. This is a little messy but seems OK, and less coarse than the other options? Filtering at transformation would be an alternative way, where we don?t need any Classfile.AttributeProcessingOption at all. Parsed and written will be always everything and specific transformations will always explode and filter respective attributes at all class model levels. For example ClassTransform.ACCEPT_ALL_SAFE_ATTRIBUTES will always explode class model down to the code and filter out all TypeAnnotations (while ClassTransform.ACCEPT_ALL does not need to explode anything). Now that I think about it, filtering at transformation vs filtering at write ? as long as we discriminate only against Bound attributes that are below the chosen stability threshold ? are equivalent. So whichever is easier for the implementation / API seems better, and filtering on write seems like it has both less runtime impact (no need to compose transformations) and less API impact (no new transform constants.) From: Brian Goetz > Date: Tuesday, 5 September 2023 14:40 To: Adam Sotona > Cc: classfile-api-dev at openjdk.org > Subject: Re: Attribute safety Some review comments on this patch. Attributes with the LABELS stability need only be exploded and rewritten when the Code array is perturbed. In practicality, LABELS attributes will also contain CP refs, so the doc should really suggest ?labels *and* CP refs?. HAZMAT can be renamed to UNSTABLE (yeah, I know HAZMAT is a cool name.) Doc on AttributeProcessingOPtion should make it clear that this is only during _transformation_; during reading/writing, all attributes are passed normally. What should be the default here? PASS, or DROP_UNSTABLE? Now that the choices are simpler, I think you can add (constant) transforms for {CLASS,METHOD,FIELD,CODE}_drop{Unknown,Unstable}, and compose these in when the user calls transform() and the option setting is not PASS_ALL? On Sep 5, 2023, at 5:17 AM, Adam Sotona > wrote: I?ve updated https://github.com/openjdk/jdk/pull/15101 so it filters on read and write based on the Classfile.AttributesProcessingOption context option. Or I can prepare a patch with filtering transformations (as proposed below). Or is there any other way? Thanks, Adam From: Brian Goetz > Date: Wednesday, 23 August 2023 19:26 To: Adam Sotona >, classfile-api-dev at openjdk.org > Subject: Re: Attribute safety Just a further thought on this: we can further focus our lens on _bound_ attributes, because these are the ones that have come from another classfile. If the user creates a RVAA during a transform, we should assume that is fine, just as we do with writing. On 8/7/2023 6:46 AM, Adam Sotona wrote: That makes perfect sense, attribute safety is more exactly an attribute transformation safety. I agree that introduction of special read/write filters (in a form of context options) is confusing and non-systematic. When we focus on the implementation of the attributes transformation safety, I think the safety switch is less of a global context option but rather individual transformation immediate feature (a filtering feature). If we implement it as a global context option, we would have to insert a filtering layer before each transformation (on read side) or after (on write side) of each transformation. I think it would be pretty much the same as filtering on read/write, except for the fact it will affect transformations only (so maybe even more confusing). Classfile::transform would then behave differently than its expanded form using Classfile::build. However if we implement attribute transformation safety as specific transformations (doing the filtering job) ? it should work in harmony with the rest of the API. For example in addition to ClassTransform.ACCEPT_ALL we can add ClassTransform.ACCEPT_ALL_KNOWN_ATTRIBUTES (dropping UNKNOWN) and ClassTransform.ACCEPT_ALL_SAFE_ATTRIBUTES (dropping HAZMAT). As an interesting expansion of the ClassfileTransform features we can provide factories like for example ClassfileTransform::dropingAll(Predicate filter) ? where the ?All? (or ?Deep? or similar suffix) should indicate forced expansion of the whole tree, so the filter is really applied on all levels and filtered element never appears in the target class. It can be used to implement the global filtering transformations. I propose to add following set of filtering transformations: 1. ClassTransform.ACCEPT_ALL_KNOWN_ATTRIBUTES 2. ClassTransform.ACCEPT_ALL_SAFE_ATTRIBUTES 3. FieldTransform.ACCEPT_ALL_KNOWN_ATTRIBUTES 4. FieldTransform.ACCEPT_ALL_SAFE_ATTRIBUTES 5. MethodTransform.ACCEPT_ALL_KNOWN_ATTRIBUTES 6. MethodTransform.ACCEPT_ALL_SAFE_ATTRIBUTES 7. CodeTransform.ACCEPT_ALL_KNOWN_ATTRIBUTES 8. CodeTransform.ACCEPT_ALL_SAFE_ATTRIBUTES Thanks, Adam From: Brian Goetz Date: Saturday, 5 August 2023 3:01 To: Adam Sotona , classfile-api-dev at openjdk.org Subject: Re: Attribute safety OK, I thought about this some more while sitting in the sauna ... I think the locus of attribute safety is not reading or writing, but transforming. If I am just going to read a classfile, there is no need to drop anything, if I find an attribute I don't recognize, I'll just skip over it and keep going -- that's how attributes are designed to work. No need to drop anything on read, ever. WHen the library finds an unknown attribute, it wraps it with an UnknownAttribute element, whose understanding to the attribute is limited to name, size, and byte[] of the payload. Nothing so dangerous here that the user needs protection. Similarly, if a user is _writing_ a classfile, again, we should trust them that the classfile they are putting together is sensible. We shouldn't second guess at "oh, that's a type annotations attribute, those are so brittle, please sign here." Where there is potentially a problem is when we are _transforming_ a classfile, because for a HAZMAT or UNKNOWN attribute, we can't guarantee its integrity if we've changed anything else about the classfile (including reordering the constant pool.) So the "what do we do with brittle attributes" question applies only to transformation, where we are taking an attribute from one classfile (a bound attribute) and writing it to another. This is where the user can shoot themselves in the foot, because they might change something else about the classfile and subtly (or not subtly) undermine the integrity of the annotation they don't understand. And this is why we want to classify attributes according to their sensitivity to environmental change: - A stateless attribute is sensitive to no environmental changes. A transform can always safely bulk-copy the attribute directly. - An attribute with CP dependencies is sensitive to restructuring of the constant pool (no CP sharing), but the mapper contains enough information to survive CP restructuring. A transform can safely bulk-copy the attribute directly if the CP is shared between the original and new classfile, and can otherwise safely copy the attribute by inflating it and deflating it via the readAttribute/writeAttribute behavior of the mapper. - An attribute with label dependencies is sensitive to changes to the contents or structure of the bytecode array. A transform can safely bulk-copy the attribute directly if code array is unchanged, and can otherwise safely copy the attribute by inflating it and deflating it via the readAttribute/writeAttribute behavior of the mapper. However, there are currently no attributes that have label dependencies only but are not already treated specially by the classfile API, so this category may not be that interesting. - An attribute with unpredictable dependencies is sensitive to any change to the contents of the entity of which it is an attribute. It can be safely bulk-copied if nothing else in that entity has changed, but otherwise there is no safe way to copy it. - An unknown attribute is sensitive to all of the above, and so takes on the union of the copying risks of all of the above. So I think the Option we want governs what to do with various attributes when _transforming_ a CompoundElement in which they appear. And the problematic cases are those with unpredictable dependencies, and unknowns. So I think the options we want are: - When transforming, always keep HAZMAT and UNKNOWN attributes; for safety, lift and lower HAZMAT attributes. - When transforming, keep HAZMAT attributes (lifting and lowering), but always drop UNKNOWN attributes. - When transforming, always drop HAZMAT and UNKNOWN attributes. -------------- next part -------------- An HTML attachment was scrubbed... URL: From adam.sotona at oracle.com Wed Sep 6 10:59:51 2023 From: adam.sotona at oracle.com (Adam Sotona) Date: Wed, 6 Sep 2023 10:59:51 +0000 Subject: Attribute safety In-Reply-To: References: <744677dd-82aa-1330-8baa-01ed7fc1ed60@oracle.com> <12B85AFE-EA45-4685-B34C-F29134B23EEB@oracle.com> <3F78A8DD-0E33-4C8E-AEC8-2EB8E44DAA62@oracle.com> Message-ID: I forgot about you last question: ?What should be the default here? PASS, or DROP_UNSTABLE? ? In this context it seems to be safer to drop unstable by default, as for example almost any touch of code array will break type annotations. However some use cases explode code only to remove some attributes and removing also something else would be an unexpected behavior. So PASS is more expected behavior and DROP_UNSTABLE is more safe. I would keep the PASS as default to keep the library behavior more predictable. From: classfile-api-dev on behalf of Adam Sotona Date: Wednesday, 6 September 2023 10:31 To: Brian Goetz Cc: classfile-api-dev at openjdk.org Subject: Re: Attribute safety OK, it makes sense, I?ll update pr/15101 to filter only bound attrs on write. Thanks, Adam From: Brian Goetz Date: Tuesday, 5 September 2023 19:08 To: Adam Sotona Cc: classfile-api-dev at openjdk.org Subject: Re: Attribute safety I probably bgought a bit of confusion here. The pr/15101 is the original ?global context option? proposal (just updated with the latest changes). It filters the attributes on read and on write based on the context option. I found hard to determine when to write an attribute based on its bound or unbound origin. We cannot determine if user pass down the transformation a bound attribute intentionally or unintentionally (and so we should or should not write it to the class). Yes, what I?m suggesting is not entirely precise, but the window of error is narrowed. We should filter nothing on read (since people ignore unsupported attributes). The remaining question is whether we are comfortable discriminating against attributes based on a two-dimensional filter ? Bound and ?below the stability threshold?. This is a little messy but seems OK, and less coarse than the other options? Filtering at transformation would be an alternative way, where we don?t need any Classfile.AttributeProcessingOption at all. Parsed and written will be always everything and specific transformations will always explode and filter respective attributes at all class model levels. For example ClassTransform.ACCEPT_ALL_SAFE_ATTRIBUTES will always explode class model down to the code and filter out all TypeAnnotations (while ClassTransform.ACCEPT_ALL does not need to explode anything). Now that I think about it, filtering at transformation vs filtering at write ? as long as we discriminate only against Bound attributes that are below the chosen stability threshold ? are equivalent. So whichever is easier for the implementation / API seems better, and filtering on write seems like it has both less runtime impact (no need to compose transformations) and less API impact (no new transform constants.) From: Brian Goetz > Date: Tuesday, 5 September 2023 14:40 To: Adam Sotona > Cc: classfile-api-dev at openjdk.org > Subject: Re: Attribute safety Some review comments on this patch. Attributes with the LABELS stability need only be exploded and rewritten when the Code array is perturbed. In practicality, LABELS attributes will also contain CP refs, so the doc should really suggest ?labels *and* CP refs?. HAZMAT can be renamed to UNSTABLE (yeah, I know HAZMAT is a cool name.) Doc on AttributeProcessingOPtion should make it clear that this is only during _transformation_; during reading/writing, all attributes are passed normally. What should be the default here? PASS, or DROP_UNSTABLE? Now that the choices are simpler, I think you can add (constant) transforms for {CLASS,METHOD,FIELD,CODE}_drop{Unknown,Unstable}, and compose these in when the user calls transform() and the option setting is not PASS_ALL? On Sep 5, 2023, at 5:17 AM, Adam Sotona > wrote: I?ve updated https://github.com/openjdk/jdk/pull/15101 so it filters on read and write based on the Classfile.AttributesProcessingOption context option. Or I can prepare a patch with filtering transformations (as proposed below). Or is there any other way? Thanks, Adam From: Brian Goetz > Date: Wednesday, 23 August 2023 19:26 To: Adam Sotona >, classfile-api-dev at openjdk.org > Subject: Re: Attribute safety Just a further thought on this: we can further focus our lens on _bound_ attributes, because these are the ones that have come from another classfile. If the user creates a RVAA during a transform, we should assume that is fine, just as we do with writing. On 8/7/2023 6:46 AM, Adam Sotona wrote: That makes perfect sense, attribute safety is more exactly an attribute transformation safety. I agree that introduction of special read/write filters (in a form of context options) is confusing and non-systematic. When we focus on the implementation of the attributes transformation safety, I think the safety switch is less of a global context option but rather individual transformation immediate feature (a filtering feature). If we implement it as a global context option, we would have to insert a filtering layer before each transformation (on read side) or after (on write side) of each transformation. I think it would be pretty much the same as filtering on read/write, except for the fact it will affect transformations only (so maybe even more confusing). Classfile::transform would then behave differently than its expanded form using Classfile::build. However if we implement attribute transformation safety as specific transformations (doing the filtering job) ? it should work in harmony with the rest of the API. For example in addition to ClassTransform.ACCEPT_ALL we can add ClassTransform.ACCEPT_ALL_KNOWN_ATTRIBUTES (dropping UNKNOWN) and ClassTransform.ACCEPT_ALL_SAFE_ATTRIBUTES (dropping HAZMAT). As an interesting expansion of the ClassfileTransform features we can provide factories like for example ClassfileTransform::dropingAll(Predicate filter) ? where the ?All? (or ?Deep? or similar suffix) should indicate forced expansion of the whole tree, so the filter is really applied on all levels and filtered element never appears in the target class. It can be used to implement the global filtering transformations. I propose to add following set of filtering transformations: 1. ClassTransform.ACCEPT_ALL_KNOWN_ATTRIBUTES 2. ClassTransform.ACCEPT_ALL_SAFE_ATTRIBUTES 3. FieldTransform.ACCEPT_ALL_KNOWN_ATTRIBUTES 4. FieldTransform.ACCEPT_ALL_SAFE_ATTRIBUTES 5. MethodTransform.ACCEPT_ALL_KNOWN_ATTRIBUTES 6. MethodTransform.ACCEPT_ALL_SAFE_ATTRIBUTES 7. CodeTransform.ACCEPT_ALL_KNOWN_ATTRIBUTES 8. CodeTransform.ACCEPT_ALL_SAFE_ATTRIBUTES Thanks, Adam From: Brian Goetz Date: Saturday, 5 August 2023 3:01 To: Adam Sotona , classfile-api-dev at openjdk.org Subject: Re: Attribute safety OK, I thought about this some more while sitting in the sauna ... I think the locus of attribute safety is not reading or writing, but transforming. If I am just going to read a classfile, there is no need to drop anything, if I find an attribute I don't recognize, I'll just skip over it and keep going -- that's how attributes are designed to work. No need to drop anything on read, ever. WHen the library finds an unknown attribute, it wraps it with an UnknownAttribute element, whose understanding to the attribute is limited to name, size, and byte[] of the payload. Nothing so dangerous here that the user needs protection. Similarly, if a user is _writing_ a classfile, again, we should trust them that the classfile they are putting together is sensible. We shouldn't second guess at "oh, that's a type annotations attribute, those are so brittle, please sign here." Where there is potentially a problem is when we are _transforming_ a classfile, because for a HAZMAT or UNKNOWN attribute, we can't guarantee its integrity if we've changed anything else about the classfile (including reordering the constant pool.) So the "what do we do with brittle attributes" question applies only to transformation, where we are taking an attribute from one classfile (a bound attribute) and writing it to another. This is where the user can shoot themselves in the foot, because they might change something else about the classfile and subtly (or not subtly) undermine the integrity of the annotation they don't understand. And this is why we want to classify attributes according to their sensitivity to environmental change: - A stateless attribute is sensitive to no environmental changes. A transform can always safely bulk-copy the attribute directly. - An attribute with CP dependencies is sensitive to restructuring of the constant pool (no CP sharing), but the mapper contains enough information to survive CP restructuring. A transform can safely bulk-copy the attribute directly if the CP is shared between the original and new classfile, and can otherwise safely copy the attribute by inflating it and deflating it via the readAttribute/writeAttribute behavior of the mapper. - An attribute with label dependencies is sensitive to changes to the contents or structure of the bytecode array. A transform can safely bulk-copy the attribute directly if code array is unchanged, and can otherwise safely copy the attribute by inflating it and deflating it via the readAttribute/writeAttribute behavior of the mapper. However, there are currently no attributes that have label dependencies only but are not already treated specially by the classfile API, so this category may not be that interesting. - An attribute with unpredictable dependencies is sensitive to any change to the contents of the entity of which it is an attribute. It can be safely bulk-copied if nothing else in that entity has changed, but otherwise there is no safe way to copy it. - An unknown attribute is sensitive to all of the above, and so takes on the union of the copying risks of all of the above. So I think the Option we want governs what to do with various attributes when _transforming_ a CompoundElement in which they appear. And the problematic cases are those with unpredictable dependencies, and unknowns. So I think the options we want are: - When transforming, always keep HAZMAT and UNKNOWN attributes; for safety, lift and lower HAZMAT attributes. - When transforming, keep HAZMAT attributes (lifting and lowering), but always drop UNKNOWN attributes. - When transforming, always drop HAZMAT and UNKNOWN attributes. -------------- next part -------------- An HTML attachment was scrubbed... URL: From mark.reinhold at oracle.com Tue Sep 26 12:35:38 2023 From: mark.reinhold at oracle.com (Mark Reinhold) Date: Tue, 26 Sep 2023 12:35:38 +0000 Subject: New candidate JEP: 457: Class-File API (Preview) Message-ID: <20230926123535.D1ED764934A@eggemoggin.niobe.net> https://openjdk.org/jeps/457 Summary: Provide a standard API for parsing, generating, and transforming Java class files. This is a preview API. - Mark From adam.sotona at oracle.com Tue Sep 26 12:55:42 2023 From: adam.sotona at oracle.com (Adam Sotona) Date: Tue, 26 Sep 2023 12:55:42 +0000 Subject: New candidate JEP: 457: Class-File API (Preview) In-Reply-To: <20230926123535.D1ED764934A@eggemoggin.niobe.net> References: <20230926123535.D1ED764934A@eggemoggin.niobe.net> Message-ID: Hi Mark, Thank you for posting this! I'm looking forward to moving from the internal library to the preview. Adam From: Mark Reinhold Date: Tuesday, 26 September 2023 14:35 To: Brian Goetz , Adam Sotona Cc: classfile-api-dev at openjdk.org , jdk-dev at openjdk.org Subject: New candidate JEP: 457: Class-File API (Preview) https://openjdk.org/jeps/457 Summary: Provide a standard API for parsing, generating, and transforming Java class files. This is a preview API. - Mark -------------- next part -------------- An HTML attachment was scrubbed... URL: