!standard A.18.2(97/2) 11-12-16 AI05-0265-1/02 !standard A.18.2(137/2) !standard A.18.2(139/2) !standard A.18.2(141/2) !standard A.18.2(145/2) !standard A.18.2(147/2) !standard A.18.2(228/2) !standard A.18.2(230/2) !standard A.18.3(69/2) !standard A.18.3(83/2) !standard A.18.3(85/2) !standard A.18.3(86/2) !standard A.18.3(142/2) !standard A.18.3(144/2) !standard A.18.4(15/2) !standard A.18.4(38/2) !standard A.18.4(40/2) !standard A.18.4(41/2) !standard A.18.4(75/2) !standard A.18.5(61/2) !standard A.18.6(94/2) !standard A.18.7(14/2) !standard A.18.7(36/2) !standard A.18.7(86/2) !standard A.18.7(95/2) !standard A.18.7(96/2) !standard A.18.8(85/2) !standard A.18.9(113/2) !standard A.18.10(0) !standard A.18.18(0) !standard A.18.19(0) !standard A.18.20(0) !standard A.18.21(0) !standard A.18.22(0) !standard A.18.23(0) !standard A.18.24(0) !standard A.18.25(0) !class binding interpretation 11-10-27 !status Amendment 2012 11-10-27 !status ARG Approved 8-0-1 11-11-12 !status work item 11-10-27 !status received 10-10-02 !priority Low !difficulty Medium !qualifier Omission !subject The location of tampering checks should be specified !summary Tampering checks occur whenever an operation of a container is called that is defined to tamper with the container. !question Wording like A.18.2(147.7/3): Program_Error is propagated if any operation tampers with the elements of Container while the object returned by Constant_Reference exists and has not been finalized. does not say when the exception is raised or at what point. This should be clarified. !wording Add the following paragraph after A.18.2(97/2), A.18.3(69/2), A.18.4(15/2), A.18.7(14/2), A.18.10(88/3), A.18.18(34/3): When tampering with cursors is *prohibited* for a particular object , Program_Error is propagated by a call of any language-defined subprogram that is defined to tamper with the cursors of . Similarly, when tampering with elements is *prohibited* for a particular object , Program_Error is propagated by a call of any language-defined subprogram that is defined to tamper with the elements of (or tamper with the cursors of ), leaving unmodified. is a letter, appropriate for each container (M for maps, V for vectors, and so on). Modify A.18.2(139/3), A.18.3(83/3), A.18.4(38/3), A.18.7(36/3), A.18.10(117/3): [Program_Error is propagated if Process.all tampers]{Tampering} with the elements of the that contains the element designated by Position {is prohibited during the execution of the call on Process.all}. Modify A.18.2(137/2), A.18.2(141/2), A.18.2(145/2), A.18.3(85/3), A.18.4(40/3), A.18.7(95/2), A.18.10(118/3), A.18.18(48/3), A.18.18(50/3): [Program_Error is propagated if Process.all tampers]{Tampering} with the elements of Container {is prohibited during the execution of the call on Process.all}. Modify A.18.10(152/3), A.18.10(211/3), A.18.10(215/3): [Program_Error is propagated if Process.all tampers]{Tampering} with the cursors of the that contains the element designated by Position {is prohibited during the execution of a call on Process.all}. Modify A.18.2(228/2), A.18.3(142/2), A.18.4(75/2), A.18.7(86/2), A.18.10(151/3): [Program_Error is propagated if Process.all tampers]{Tampering} with the cursors of Container {is prohibited during the execution of a call on Process.all}. Modify A.18.2(147.14/3), A.18.2(147.17/3), A.18.3(86.7/3), A.18.3(86.10/3), A.18.4(41.7/3), A.18.4(41.10/3), A.18.7(36.6/3), A.18.7(96.11/3), A.18.10(126/3), A.18.10(129/3), A.18.18(57/3), A.18.18(60/3): [Program_Error is propagated if any operation tampers with the elements of Container]{Tampering with the elements of Container is prohibited} while the object returned by exists and has not been finalized. Modify A.18.2(230.2/3), A.18.2(230.4/3), A.18.3(144.2/3), A.18.3(144.4/3), A.18.5(61.2/3), A.18.6(94.2/3), A.18.8(85.2/3), A.18.9(113.2/3), A.18.10(155/3), A.18.10(157/3), A.18.10(217/3): {Tampering with the cursors of Container is prohibited while the iterator object exists} [Program_Error is propagated if any operation] (in particular, {in} the sequence_of_statements of the loop_statement whose iterator_specification denotes this object) [tampers with the cursors of Container while the iterator object exists]. Replace A.18.19(10/3), A.18.20(14/3), A.18.21(15/3), A.18.22(12/3), A.18.23(15/3), A.18.24(12/3), A.18.25(14/3): It is a bounded error to assign from a bounded object while tampering with elements Redundant[or cursors] of that object is prohibited. Either Program_Error is raised by the assignment, execution proceeds with the target object prohibiting tampering with elements Redundant[or cursors], or execution proceeds normally. Erroneous Execution When a bounded object is finalized, if tampering with cursors is prohibited for other than due to an assignment from another , then execution is erroneous. AARM Reason: This is a tampering event, but since the implementation is not allowed to use Ada.Finalization, it is not possible in a pure Ada implementation to detect this error. (There is no Finalize routine that will be called that could make the check.) Since the check probably cannot be made, the bad effects that could occur (such as an iterator going into an infinite loop or accessing a non-existent element) cannot be prevented and we have to allow anything. We do allow re-assigning an object that only prohibits tampering because it was copied from another object as that cannot cause any negative effects. !discussion Ada 2005 wording like A.18.2(137/2) - "Program_Error is propagated if Process.all tampers with the elements of Container." is even worse in this regard, since it seems to imply that Process.all (a user-written routine) does this check. By changing the wording to effectively make tampering a container state, it is much simpler to explain who makes the check and when it is going to happen. Since this matches the intended implementation, it should make the model clearer and reduce implementation mistakes. We added an erroneous execution case to bounded containers because it is impossible to detect a tampering event caused by an assignment or other finalization. For example: for C in My_List.Iterator loop ... My_List := Your_List; -- !! ... end loop; For unbounded container forms, the assignment statement is required to raise Program_Error as My_List prohibits tampering of cursors, and the finalization of the target of the assignment is a tampering event. The same is true for the bounded container forms, except that this cannot be implemented in Standard Ada. We do not allow bounded containers to depend on Ada.Finalization, so there will not be a call to some Finalize routine when My_List is finalized. Thus, there is no way to make the check to raise Program_Error. As such, a typical implementation will fail to raise Program_Error here. That is OK, as we've defined execution to be erroneous in this case. That's necessary as the surrounding iterator probably will malfunction after this assignment, generating cursors that don't point at elements, possibly causing a hardware trap for a bad address or overwriting some other object's memory, or even going into an infinite loop. !corrigendum A.18.2(97/2) @dinsa @xbullet, that is, it calls the Replace_Element, Reverse_Elements, or Swap procedures or the Sort or Merge procedures of an instance of Generic_Sorting with @i as a parameter.> @dinss When tampering with cursors is @i for a particular vector object @i, Program_Error is propagated by a call of any language-defined subprogram that is defined to tamper with the cursors of @i, leaving @i unmodified. Similarly, when tampering with elements is @i for a particular vector object @i, Program_Error is propagated by a call of any language-defined subprogram that is defined to tamper with the elements of @i (or tamper with the cursors of @i), leaving @i unmodified. !corrigendum A.18.2(137/2) @drepl @xindent with the element at position Index as the argument. Program_Error is propagated if Process.@b tampers with the elements of Container. Any exception raised by Process.@b is propagated.> @dby @xindent with the element at position Index as the argument. Tampering with the elements of Container is prohibited during the execution of the call on Process.@b. Any exception raised by Process.@b is propagated.> !corrigendum A.18.2(139/2) @drepl @xindent with the element designated by Position as the argument. Program_Error is propagated if Process.@b tampers with the elements of Container. Any exception raised by Process.@b is propagated.> @dby @xindent with the element designated by Position as the argument. Tampering with the elements of the vector that contains the element designated by Position is prohibited during the execution of the call on Process.@b. Any exception raised by Process.@b is propagated.> !corrigendum A.18.2(141/2) @drepl @xindent with the element at position Index as the argument. Program_Error is propagated if Process.@b tampers with the elements of Container. Any exception raised by Process.@b is propagated.> @dby @xindent with the element at position Index as the argument. Tampering with the elements of Container is prohibited during the execution of the call on Process.@b. Any exception raised by Process.@b is propagated.> !corrigendum A.18.2(145/2) @drepl @xindent with the element designated by Position as the argument. Program_Error is propagated if Process.@b tampers with the elements of Container>. Any exception raised by Process.@b is propagated.> @dby @xindent with the element designated by Position as the argument. Tampering with the elements of Container is prohibited during the execution of the call on Process.@b. Any exception raised by Process.@b is propagated.> !corrigendum A.18.2(147/2) @dinsa Force a conflict; the real text is found in the conflict file. @dinst Nothing. !corrigendum A.18.2(228/2) @drepl @xindent with a cursor that designates each element in Container, in index order. Program_Error is propagated if Process.all tampers with the cursors of Container. Any exception raised by Process.@b is propagated.> @dby @xindent with a cursor that designates each element in Container, in index order. Tampering with the cursors of Container is prohibited during the execution of a call on Process.@b. Any exception raised by Process.@b is propagated.> !corrigendum A.18.2(230/2) @drepl Force a conflict; the real text is found in the conflict file. @dby Nothing. !corrigendum A.18.3(69/2) @dinsa @xbullet, that is, it calls the Replace_Element or Swap procedures with @i as a parameter.> @dinst When tampering with cursors is @i for a particular list object @i, Program_Error is propagated by a call of any language-defined subprogram that is defined to tamper with the cursors of @i, leaving @i unmodified. Similarly, when tampering with elements is @i for a particular list object @i, Program_Error is propagated by a call of any language-defined subprogram that is defined to tamper with the elements of @i (or tamper with the cursors of @i), leaving @i unmodified. !corrigendum A.18.3(83/2) @drepl @xindent with the element designated by Position as the argument. Program_Error is propagated if Process.@b tampers with the elements of Container. Any exception raised by Process.@b is propagated.> @dby @xindent with the element designated by Position as the argument. Tampering with the elements of the list that contains the element designated by Position is prohibited during the execution of the call on Process.@b. Any exception raised by Process.@b is propagated.> !corrigendum A.18.3(85/2) @drepl @xindent with the element designated by Position as the argument. Program_Error is propagated if Process.@b tampers with the elements of Container. Any exception raised by Process.@b is propagated.> @dby @xindent with the element designated by Position as the argument. Tampering with the elements of Container is prohibited during the execution of the call on Process.@b. Any exception raised by Process.@b is propagated.> !corrigendum A.18.3(86/2) @dinsa Force a conflict; the real text is found in the conflict file. @dinst Nothing. !corrigendum A.18.3(142/2) @drepl @xindent with a cursor that designates each node in Container, starting with the first node and moving the cursor as per the Next function. Program_Error is propagated if Process.all tampers with the cursors of Container. Any exception raised by Process.@b is propagated.> @dby @xindent with a cursor that designates each node in Container, starting with the first node and moving the cursor as per the Next function. Tampering with the cursors of Container is prohibited during the execution of a call on Process.@b. Any exception raised by Process.@b is propagated.> !corrigendum A.18.3(144/2) @drepl Force a conflict; the real text is found in the conflict file. @dby Nothing. !corrigendum A.18.4(15/2) @dinsa @xbullet, that is, it calls the Replace or Replace_Element procedures with @i as a parameter.> @dinst When tampering with cursors is @i for a particular map object @i, Program_Error is propagated by a call of any language-defined subprogram that is defined to tamper with the cursors of @i, leaving @i unmodified. Similarly, when tampering with elements is @i for a particular map object @i, Program_Error is propagated by a call of any language-defined subprogram that is defined to tamper with the elements of @i (or tamper with the cursors of @i), leaving @i unmodified. !corrigendum A.18.4(38/2) @drepl @xindent with the key and element from the node designated by Position as the arguments. Program_Error is propagated if Process.@b tampers with the elements of Container. Any exception raised by Process.@b is propagated.> @dby @xindent with the key and element from the node designated by Position as the arguments. Tampering with the elements of the map that contains the element designated by Position is prohibited during the execution of the call on Process.@b. Any exception raised by Process.@b is propagated.> !corrigendum A.18.4(40/2) @drepl @xindent with the key and element from the node designated by Position as the arguments. Program_Error is propagated if Process.@b tampers with the elements of Container. Any exception raised by Process.@b is propagated.> @dby @xindent with the key and element from the node designated by Position as the arguments. Tampering with the elements of Container is prohibited during the execution of the call on Process.@b. Any exception raised by Process.@b is propagated.> !corrigendum A.18.4(41/2) @dinsa Force a conflict; the real text is found in the conflict file. @dinst Nothing. !corrigendum A.18.4(75/2) @drepl @xindent with a cursor that designates each node in Container, starting with the first node and moving the cursor according to the successor relation. Program_Error is propagated if Process.all tampers with the cursors of Container. Any exception raised by Process.@b is propagated.> @dby @xindent with a cursor that designates each node in Container, starting with the first node and moving the cursor according to the successor relation. Tampering with the cursors of Container is prohibited during the execution of a call on Process.@b. Any exception raised by Process.@b is propagated.> !corrigendum A.18.5(61/2) @drepl Force a conflict; the real text is found in the conflict file. @dby Nothing. !corrigendum A.18.6(94/2) @drepl Force a conflict; the real text is found in the conflict file. @dby Nothing. !corrigendum A.18.7(14/2) @dinsa @xbullet.> @dinst When tampering with cursors is @i for a particular set object @i, Program_Error is propagated by a call of any language-defined subprogram that is defined to tamper with the cursors of @i, leaving @i unmodified. Similarly, when tampering with elements is @i for a particular set object @i, Program_Error is propagated by a call of any language-defined subprogram that is defined to tamper with the elements of @i (or tamper with the cursors of @i), leaving @i unmodified. !corrigendum A.18.7(36/2) @dinsa Force a conflict; the real text is found in the conflict file. @dinst Nothing. !corrigendum A.18.7(86/2) @drepl @xindent with a cursor that designates each element in Container, starting with the first element and moving the cursor according to the successor relation. Program_Error is propagated if Process.all tampers with the cursors of Container. Any exception raised by Process.@b is propagated.> @dby @xindent with a cursor that designates each element in Container, starting with the first element and moving the cursor according to the successor relation. Tampering with the cursors of Container is prohibited during the execution of a call on Process.@b. Any exception raised by Process.@b is propagated.> !corrigendum A.18.7(95/2) @drepl @xindent of the element designated by Position. Update_Element_Preserving_Key then calls Process.@b with that element as the argument. Program_Error is propagated if Process.@b tampers with the elements of Container. Any exception raised by Process.@b is propagated. After Process.@b returns, Update_Element_Preserving_Key checks if @i determines the same equivalence class as that for the new element; if not, the element is removed from the set and Program_Error is propagated.> @dby @xindent of the element designated by Position. Update_Element_Preserving_Key then calls Process.@b with that element as the argument. Tampering with the elements of Container is prohibited during the execution of the call on Process.@b. Any exception raised by Process.@b is propagated. After Process.@b returns, Update_Element_Preserving_Key checks if @i determines the same equivalence class as that for the new element; if not, the element is removed from the set and Program_Error is propagated.> !corrigendum A.18.7(96/2) @dinsa Force a conflict; the real text is found in the conflict file. @dinst Nothing. !corrigendum A.18.8(85/2) @drepl Force a conflict; the real text is found in the conflict file. @dby Nothing. !corrigendum A.18.9(113/2) @drepl Force a conflict; the real text is found in the conflict file. @dby Nothing. !corrigendum A.18.10(0) @dinsc Force a conflict; the real text is found in the conflict file. !corrigendum A.18.18(0) @dinsc Force a conflict; the real text is found in the conflict file. !corrigendum A.18.19(0) @dinsc [A placeholder to cause a conflict; the real wording is found in the conflict file.] !corrigendum A.18.20(0) @dinsc [A placeholder to cause a conflict; the real wording is found in the conflict file.] !corrigendum A.18.21(0) @dinsc [A placeholder to cause a conflict; the real wording is found in the conflict file.] !corrigendum A.18.22(0) @dinsc [A placeholder to cause a conflict; the real wording is found in the conflict file.] !corrigendum A.18.23(0) @dinsc [A placeholder to cause a conflict; the real wording is found in the conflict file.] !corrigendum A.18.24(0) @dinsc [A placeholder to cause a conflict; the real wording is found in the conflict file.] !corrigendum A.18.25(0) @dinsc [A placeholder to cause a conflict; the real wording is found in the conflict file.] !ACATS Test None needed. !ASIS No change needed. !appendix From: Randy Brukardt Sent: Wednesday, October 12, 2011 9:17 PM Erhard has the following in his review: ... > 36.6.3 says as part of the semantics of function Constant_Reference: > > Program_Error is propagated if any operation tampers with the > > elements of Container while the object returned by > > Constant_Reference exists and has not been finalized. > > Not good enough. It doesn't say when and where it is raised (upon > tampering, after tampering upon use of the returned value, or by > Current_Reference which has mystical powers to know the future?) I'm in favor of the mystical powers. ;-) > To fix, and I presume that is the intent, "if" should be replaced by > "when". I'm not completely convinced that is enough, but it does seem to be an (small) improvement. I worry that "any operation" seems to require user subprograms to make such a check, which is obvious nonsense. It might be better to say Program_Error is propagated [if]{by} any operation {of Container that} tampers with the elements of Container while the object returned by Constant_Reference exists and has not been finalized. maybe it would be better to name the package in question, but we can't do that for Maps and Sets (there are multiple packages involved). Perhaps ...operation {of a set package that} tampers although then someone will bitch that formally it is an instance that we're talking about: ...operation {of an instance of a set package that} tampers But I'm not sure this wording captures the dynamism necessary. > I did not pick up on this earlier, because in other contexts "if" and > "when" can be semantically interchangeable. But, here and elsewhere, > when the semantics of function F say: > Constraint_Error is raised if the value of XYZ is null. > Programm_Error is raised if ... > then I really assume that it is F that raises the exception, not some > other subprogram later on. > > "when" solves the issue somewhat. Putting the rule elsewhere entirely > would be better. Maybe even "collect" all the cursor types to which > this rule applies and describe the tampering exception for all of them > together. That's probably how the tampering checks will get implemented, but I don't see how to do that in a way that makes sense. > [somewhat similar comment for 86/2, but it is not so bad there] That of course is existing wording, so in theory it is out of bounds. But it seems to me to be *worse* there, as it only talks about Process.all, but really the exception will be raised by some call to a set operation that is (dynamically) inside of Process.all. It's never going to be raised by Process.all (which is user-written, so that would be an impossible requirement). There is a similar problem with 36/2 (Query_Element). And all of the iterators. If we make the changes suggested above, then we ought to make similar changes to all of these other places. For Query_Element, we would have something like: Program_Error is propagated by any operation of an instance of a set container that is called (directly or indirectly) from Process.all and that tampers with the elements of Container. This is getting wordy (and widespread). Better suggestions are welcome. **************************************************************** From: Erhard Ploedereder Sent: Thursday, October 13, 2011 1:12 PM >> > To fix, and I presume that is the intent, "if" should be replaced >> > by "when". > I'm not completely convinced that is enough, but it does seem to be an > (small) improvement. I worry that "any operation" seems to require > user subprograms to make such a check, which is obvious nonsense. Why would that be the case? How do I tamper inside a user program without using a tampering operation of the container package? > It might be better to say > > Program_Error is propagated [if]{by} any operation {of Container that} > tampers with the elements Fine by me. Or "any operation defined in this International Standard"? or "in this Clause". In any case, I'd rather get the "when" without this additional chance than no change at all. **************************************************************** From: Randy Brukardt Sent: Thursday, October 13, 2011 1:47 PM > > I'm not completely convinced that is enough, but it does seem to be > > an > > (small) improvement. I worry that "any operation" seems to require > > user subprograms to make such a check, which is obvious nonsense. > > Why would that be the case? How do I tamper inside a user program > without using a tampering operation of the container package? Because I'm applying the same sort of unfriendly reading of the text that you are when you say "if" needs to be replaced by "when". If you say the exception needs to be raised "when any operation tampers", and mean it to specify which operation is raising the exception [which is my understanding of the complaint], I could read that as saying that some user operation that tampers needs to raise the exception - possibly even before the inner call that actually does the tampering. It's the same vaguely twisted logic that you use when you make the claim that you need to know who raises the exception (there's only one practical possibility, after all). > > It might be better to say > > > > Program_Error is propagated [if]{by} any operation {of Container > > that} tampers with the elements > > Fine by me. Or "any operation defined in this International Standard"? > or "in this Clause". > > In any case, I'd rather get the "when" without this additional chance > than no change at all. My problem with that is that it doesn't really fix anything in this case (the wording still tells you nothing about which operation actually makes the check - which is the important point, isn't it?). And if there is a real problem here (which I can believe), the existing Ada 2005 wording is many times worse. Consider: "Program_Error is propagated if Process.all tampers with the elements of Container." which is the wording used by Query_Element. Applying the same logic that you did to the new wording, this clearly seems to say that Query_Element itself is raising the exception. But that would too late to raise it (the damage to the parameter to Process.all occurs as soon as any tampering happens, and we don't want any possiblity to access the parameter after that happens), and it would be hard to implement as well. The intent is that the call to some operation that would tamper raises the exception, but this doesn't say this at all. I don't know if we left this purposely vague for some reason, or if we just botched the wording. In any case, it seems to me that if your comment is right, there are very serious problems with the wording of all of the tampering checks. But this is not a critical problem, in that there is only one sensible implementation, so fixing the wording is unlikely to have any effect on implementations (while it might be confusing for users - but I don't think they could take any real advantage of an unfriendly reading). Because the wording isn't going to change implementations, there is no rush to get it right. And your suggestion of overhauling the descriptions of the tampering check to make the part about where it gets raised a global statement seems like it might be the best plan -- so we're talking about a lot of rewriting. That should not be done as an "editorial review", so I think it would be best to defer this (including your original comment) to an upcoming BI. **************************************************************** From: Erhard Ploedereder Sent: Friday, October 14, 2011 9:02 AM > If you say the > exception needs to be raised "when any operation tampers", and mean it > to specify which operation is raising the exception [which is my > understanding of the complaint] That is NOT my complaint. My complaint is that when a subprogram description says: Constraint_Error is raised if ... Mode_Error is raised if ... Set_Error is raised if ... Program_Error is raised if ... then I immediately expect that all these exceptions are raised by that subprogram if the "if..." is true, not by some other subprogram SOMETIMES LATER. The proposal of using "when" at least raises the attention level a bit, the "if" does not. Admittedly, a much better solution would be to drop that statement altogether in this place and add a general statement somewhere, that in the presence of "active cursors" (is there a term for it?) all tampering operations on the "cursed container" raise Program_Error. But really, I don't want the best be an enemy of the better. **************************************************************** From: Randy Brukardt Sent: Friday, October 14, 2011 3:43 PM > > If you say the > > exception needs to be raised "when any operation tampers", and mean > > it to specify which operation is raising the exception [which is my > > understanding of the complaint] > > That is NOT my complaint. My complaint is that when a subprogram > description says: > > Constraint_Error is raised if ... > Mode_Error is raised if ... > Set_Error is raised if ... > Program_Error is raised if ... > > then I immediately expect that all these exceptions are raised by that > subprogram if the "if..." is true, not by some other subprogram > SOMETIMES LATER. The proposal of using "when" at least raises the > attention level a bit, the "if" does not. OK, but this is almost the same thing -- in the former case the text is implicitly stating which routine is raising the exception; in this case, we're not saying at all (in this wording or in the other existing wording) which routine raises the exception. And that is a bad idea on the face of it. > Admittedly, a much better solution would be to drop that statement > altogether in this place and add a general statement somewhere, that > in the presence of "active cursors" > (is there a term for it?) all tampering operations on the "cursed > container" raise Program_Error. > > But really, I don't want the best be an enemy of the better. My concern here is it's become pretty obvious to me that the complaint that I thought you were making is a real problem here. It would take me a couple of hours to make the "if" => "when" change in all of the places that are affected, and I'd rather spend that time on a real fix. So let me outline a real fix, and if you find it acceptable, I'll create an AI out of it and ballot it for immediate inclusion. [Delaying the standard a couple of days is better than having a problem that will generate an immediate NB comment or possibly worse.] That is, I want to go for "best", because I don't believe in what you say is "better". (It's "better", but not enough better for the effort.) [Aside: To answer the inevitable Duff rule complaint, I would say that the new situations make the rules even muddier than they were, and show that the old wording was too vague. So let's fix it completely if we need to hack around with the new wording anyway.] ============================ Add the following paragraph after the definition of "tampering with elements", etc. (in each container): If tampering with cursors is *prohibited* for a particular object , Program_Error is propagated by any language-defined subprogram that is defined to tamper with the cursors of . Similarly, if tampering with elements is *prohibited* for a particular object , Program_Error is propagated by any language-defined subprogram that is defined to tamper with the elements of . [Note: The letter here is appropriate for the container kind: M for maps, V for vectors, etc.] Then, replace each place that currently talks about Program_Error for a tampering check with something that says tampering is prohibited for that container. For instance, Query_Element currently says: Program_Error is propagated if Process.all tampers with the elements of Container. Replace that with: Tampering with the elements of Container is prohibited during the execution of Process.all. Similarly, the sentence that caused the complaint says: Program_Error is propagated if any operation tampers with the elements of Container while the object returned by Constant_Reference exists and has not been finalized. Replace that with: Tampering with the elements of Container is prohibited while the object returned by Constant_Reference exists and has not been finalized. And the iterator wording: Program_Error is propagated if any operation (in particular, the sequence_of_statements of the loop_statement whose iterator_specification denotes this object) tampers with the cursors of Container while the iterator object exists. Tampering with the elements of Container is prohibited while the iterator object exists (in particular, during the execution of the sequence_of_statements of the loop_statement whose iterator_specification denotes this object). Is this better? (Has to be :-), it matches the intended implementation.) Any suggestions for improvement? **************************************************************** Wording proposed Saturday, November 12, 2011 3:21 PM during Denver ARG meeting. This was generated by the subgroup of Randy, Steve, and Tucker during the extended lunch break. Add an AARM note after A.18.2(93.1/3): AARM Ramification: We don't need to explicitly mention assignment_statement, because that finalizes the target parameter as part of the operation, and finalization is already defined as tampering. [Make a similar change in the tampering with cursors rules for all other containers.] Add in A.18.19: Bounded Errors It is a bounded error to assign from an object while tampering with elements [or cursors] of that object is prohibited. Either Program_Error is raised by the assignment, the target object prohibits tampering with elements [or cursors], or execution proceeds normally. Erroneous Execution When a bounded vector object V is finalized, if tampering with cursors is prohibited for V, other than due to an assignment from another vector, then execution is erroneous. AARM Reason: This is a tampering event, but since the implementation is not allowed to use Ada.Finalization, it is not possible in a pure Ada implementation to detect this error. (There is no Finalize routine that will be called to make the check.) Since the check probably cannot be made, the bad effects that could occur (such as an iterator going into an infinite loop or accessing a non-existent element) cannot be prevented and we have to allow anything. We do allow re-assigning an object that only prohibits tampering because it was copied from another object as that cannot cause any negative effects. [Add similar text to every bounded container.] =============== How we got to the above wording: We don't need to mention assignment_statements in the tampering rules for the reasons described in the new AARM note. We wasted a lot of time on this one. We do need to make tampering on assignment to be erroneous for the bounded containers, because there is no Finalize routine that will be called in that case to make the check. Steve has suggested that since we can now describe the state, we could simply say that the state might be copied. And not a bounded error. Tucker thought that was bad for some reason that I [Randy] don't recall. This led to a suggestion that there really isn't a problem; it's possible to tell between "real" tampering and "copied" tampering. The container could include a self-identification associated with the tampering state. This could be checked whenever the tampering check occurs, and if it doesn't identify the container object involved, then the tampering is not real and should be cleared. That would fix the problem. Well, almost all cases of the problem: T := S; Deallocate S; Allocate new which ends up in the same memory as S; S := T; This could not be detected. So we really do need the bounded error, and it is rather expensive anyway. Tucker would like the assignment to be able to raise Program_Error if detected. So: It is a bounded error to assign from an object while tampering with elements [or cursors] of that object is prohibited. Either Program_Error is raised by the assignment, the target object prohibits tampering with elements [or cursors], or execution proceeds normally. What about re-assignment? That would be erroneous because of the previous rule. Yuck. Add: "If the target object prohibits tampering as the result of the assignment, it is not erroneous to assign to the target object, notwithstanding the general rule for finalizing objects in this state." Better to change the previous rule: Erroneous Execution When a bounded vector object V is finalized, if tampering with cursors is prohibited for V, other than due to an assignment from another vector, then execution is erroneous. AARM Reason: This is a tampering event, but since the implementation is not allowed to use Ada.Finalization, it is not possible in a pure Ada implementation to detect this error. (There is no Finalize routine that will be called to make the check.) Since the check probably cannot be made, the bad effects that could occur (such as an iterator going into an infinite loop or accessing a non-existent element) cannot be prevented and we have to allow anything. We do allow re-assigning an object that only prohibits tampering because it was copied from another object as that cannot cause any negative effects. ***************************************************************