Some code notes for anyone interested. I thought about starting a new thread in the dev section, but I'm just going to put it all here.
Main problem I found stems from the logic around viewport_step_size, which assumes viewport width (viewport_width_proper, meaning image pixels, not buffer) is either 720 or 960. In current CHDK, this doesn't hold for a lot of cases: Aspect ratios that aren't full screen width, digic 6 cams that are 4:3, old cameras where the real used viewport is 704 instead of 720, stitch. viewport_width_proper is also assumed to be evenly divisible by 24, which also doesn't hold.
If actual width doesn't fit the assumptions, then the code that reads pixel values can get out of alignment, so the wrong bytes are used for the YUV components. Additionally, the check to skip over unused letterboxing can fail, causing 0 or garbage values to be sampled, as well as sampling many more pixels than it should.
Another issue is that the total pixels sampled should be less than 64k (since shorts are used to count) which wouldn't hold for FHD HDMI and possibly OVF.
When the assumptions are met, the current code samples every 8th pixel in vertical columns, skipping every other row if vid_get_viewport_yscale is 2.
My current plan for this issue is to get rid of the optimization around viewport_step_size, and use a nested loop to step over the desired rows, with the x step set to meet the alignment requirements and avoid exceeding 64k samples.
Other issues:
On digic 6, the range of Y values is less than the 0-255 (on g7x, I saw 16 to 235. Need to review
https://en.wikipedia.org/wiki/YCbCr to figure out how to deal with it), so the EV grid is wrong, especially toward the edges, and over / under warning don't work correctly
The EV grid is drawn at a fixed scale, so it's meaningless if auto-magnify is enabled. (edit: incorrect, auto magnify is in the other axis, so should be ok)