Worked out the issue, and it was a little odd. As expected, error on my part. Also, visual trickery by the debugger.
In all cases, retval was not modified. Using values other than "" resulted in the exact same behavior. Using show_debug_message after every other line of code exhibited the same behavior. Here's what went on:
I was so intent on resetting position p in cases where retval did
not evaluate to "" that I neglected to un-set p in cases where retval *
does* evaluate to "". Since p is still holding the value of the previous string_pos, the loop was continuing to execute.
The primary reason for the confusion was actually a red herring. Tracing the code to follow the value of p, I came across the weird jumping behavior I showed above. It appeared that the code was
skipping a line that resets the value of p, leading me to believe that the error with p's value came from that. In reality, this appears to be just a quirky, odd way that the debugger shows that it has hit the end of a looping code block.
Testing on other code blocks, the debugger visually jumps to the last line of code before the }'s that end a loop, even if that line is inside a code block that isn't being executed. (And then it jumps back to the top of the loop. If the exit condition is true, it then skips the loop.)
Fun times
For a brief, crazy moment there, it seemed that all of my loops had started to break!