there is no OP_ENDIF anywhere after OP_IF
Not sure, but I think OP_ENDIF is not exactly mandatory unlike the case with conventional scripting languages and there is a chance for such scripts to pass.
as far as i can tell from the source code, whenever any of these "ifs" are executed they must end with an OP_ENDIF otherwise the script evaluation will fail hence these output scripts can not be spent with existing consensus rules.
Not exactly true. The input script is processed sequentially:
There is no pre-processing. When the processor encounters OP_IF it checks the value (boolean) on top of the stack if it is False (0) it ignores the next statement(s) up to a breakpoint and if it is not FALSE (any value other than 0), it continues executing the statements up to the next breakpoint, in both cases, we remember that we are in
IF-Block-Processing mode and in the latter case reaching to a breakpoint means meeting
one of the following conditions:
1- An Error occurs.
2-
The script ends and the result is to be found on the top of the stack as a boolean. (surprise!)3- An OP_ElSE is fetched. Now that we are processing a satisfied IF statement, we behave just like when there is a FLASE on top of the stack: ignoring the script up to the next breakpoint.
4- An OP_ENDIF is fetched: NOW we will end our
IF-Block-Processing mode and go normal. For the sake of not triggering an error and failing, we need TO BE in
IF-Block-Processing mode, hence a matching IF/NOT_IF clause should be under processing right now.
For nested IF clauses we do everything recursively.
From this, one could conclude that
OP_IF can proceed without a matching OP_ENDIF! The opposite is not true tho, OP_ENDIF would fail without a matching OP_IF/OP_NOT_IF being visited already.