What happened. A method index outside the range the manual documents was converted into one inside it, and then acted on. An index of −1 reached method 65535 and an index of 65537 reached method 1 — defining, printing, calling and deleting methods the caller never named.
(defgeneric process)
(defmethod process 65535 ((?x INTEGER)) (printout t "the highest" crlf))
(defmethod process 1 ((?x FLOAT)) (printout t "one" crlf))
(call-specific-method process -1 7) ; printed "the highest"
(undefmethod process 65537) ; deleted method 1
(get-method-restrictions process -1) answered with method 65535's restrictions. (ppdefmethod process -1) printed method 65535. And (defmethod process -1 ()) defined a method at index 65535, which (get-defmethod-list process) then reported as being there.
(defmethod process 0 ()) was refused, which is what hides it: 0 is the one out-of-range value the conversion leaves alone.
Why it is a fix and not a preference. Appendix F documents GENRCPSR6 as "A method index cannot be greater than the maximum value of an integer or less than 1", and GENRCCOM2 as an invalid index passed to undefmethod, naming a negative integer as an example. Section 8.4.2 says a method is identified by its name and index. Deleting a method on being handed a negative index is not identifying it.
Where it came from. Defmethod.index in genrcfun.h is an unsigned short, and six places converted to it before deciding whether the value was usable. The C standard says an unsigned conversion adds or subtracts one more than the maximum until the value fits, so −1 becomes 65535 and 65537 becomes 1, and a test applied after that is asking about a different number.
ParseMethodNameAndIndex in genrcpsr.c converted and then rejected a result below 1. UndefmethodCommand in genrccom.c converted and then rejected a result of exactly 0. PPDefmethodCommand and GetMethodRestrictionsCommand in the same file, and CallSpecificMethod in genrcexe.c, converted and searched. DefmethodWatchSupport tested the original value against 0 but not against the top of the field.
The change. MethodIndexInRange in genrcfun.c answers whether an index read as a long long is between 1 and MAX_DEFMETHOD_INDEX, reporting GENRCPSR6 with the function's name when it is not. MAX_DEFMETHOD_INDEX is declared in genrcfun.h beside the field whose width it describes.
The three lookups and the dispatch ask it before converting. The definition path tests both ends itself, because it reports before a generic function is even in hand. UndefmethodCommand tests both ends itself too, because Appendix F gives that function its own message. DefmethodWatchSupport gained the upper bound it was missing.
What was checked. Five indices the manual places out of range are refused at definition — −1, 65537, 0, 65536, and the most negative integer — and 1 and 65535 still define and still dispatch. Then each of the lookups and undefmethod with each of those two values, against a generic that has methods at exactly 1 and 65535, so an off-by-the-field-width error has something to hit. Each outcome is printed on its own named line, so a method being reached is distinguishable from one not being. Then the same lookups with valid indices, which still answer.
Anonymous
Present in 7.0? Not checked.