Another Sprite Bug (CreateRemoveAlpha)
Andy S (2979) 504 posts |
While coding the alpha mask / alpha channel features for the Paint bounty I was getting some nasty repeatable crashes. After a lot of digging, I believe I’ve tracked it down to a bug in SpriteExtend SprOp. The problem is that when using OS_SpriteOp 38 – Create/remove Alpha to add an alpha mask to a sprite, SpriteExtend seems to sometimes write past the end of the sprite area, despite making sure enough space has been reserved (I checked the calculation and even compared the sizes of sprite files with and without alpha masks to make sure). First, here’s a BASIC program that hopefully illustrates the issue (make sure you increase Next before running):
On my system, the last printed string appears blank, illustrating that the conversion to an alpha mask has overwritten the memory containing the text. Note also that modifying the code to use additional string variables has resulted in “unknown or missing variable” messages when trying to access them and even exceptions, suggesting the sprite has overflowed into the memory BASIC’s using for those variables. More diagnostic information to follow as well as what I believe is the actual underlying bug. |
Andy S (2979) 504 posts |
When I ran this code on a 16M 1024×768 sprite that had an alpha channel, to attempt to convert it to an alpha mask (after ensuring the sprite area has the right amount of space), Paint crashes.
It gets an abort on data transfer at the following location:
|
Andy S (2979) 504 posts |
It was apparently trying to move the mask memory (actually the memory that will need to follow after the new mask) by R0 = &C0000 = 786,432 bytes, and a 16M 1024×768 alpha mask sprite is 3932204 bytes in memory. With an alpha channel instead it’s 3145772. 3932204 – 3145772 = 786,432, so the value in R0 when it crashed was correct. The bit that’s obviously wrong in the above register dump is the value in R1, which is past the end of the sprite area (which is &615838). Here’s the SprExtend code leading up to the crash, with my (not very clear) comments added:
Then we branch into the move_memory_up routine inside SprAdjSize:
So the bug seems to be that the amount to grow the mask, given in R0, gets added to R10 twice when it should only be done once by move_memory_up. To prove it, if we subtract the growth amount from R1 twice, we get back the original start of free space in the sprite area: So a bug fix could be to subtract R0 from |
Andy S (2979) 504 posts |
Thanks very much for fixing this Jeffrey! I ran my BASIC repro against SpriteExtend 1.86 and am happy to confirm it wrote exactly the right number of bytes when converting to each of the mask types, including an extra test I added for on/off masks. :) |