diff --git a/BasiliskII/src/Unix/video_vosf.h b/BasiliskII/src/Unix/video_vosf.h index dae9c8b5..fd3d43da 100644 --- a/BasiliskII/src/Unix/video_vosf.h +++ b/BasiliskII/src/Unix/video_vosf.h @@ -350,6 +350,39 @@ static bool Screen_fault_handler_init() * Update display for Windowed mode and VOSF */ +/* How can we deal with array overrun conditions ? + + The state of the framebuffer pages that have been touched are maintained + in the dirtyPages[] table. That table is (pageCount + 2) bytes long. + +Terminology + + "Last Page" denotes the pageCount-nth page, i.e. dirtyPages[pageCount - 1]. + "CLEAR Page Guard" refers to the page following the Last Page but is always + in the CLEAR state. "SET Page Guard" refers to the page following the CLEAR + Page Guard but is always in the SET state. + +Rough process + + The update routines must determine which pages have to blitted to the + screen. This job consists in finding the first_page that was touched. + i.e. find the next page that is SET. Then, finding how many pages were + touched starting from first_page. i.e. find the next page that is CLEAR. + +Two cases + + - Last Page is CLEAR: find_next_page_set() will reach the SET Page Guard + but it is beyond the valid pageCount value. Therefore, we exit from the + update routine. + + - Last Page is SET: first_page equals (pageCount - 1) and + find_next_page_clear() will reach the CLEAR Page Guard. We blit the last + page to the screen. On the next iteration, page equals pageCount and + find_next_page_set() will reach the SET Page Guard. We still safely exit + from the update routine because the SET Page Guard position is greater + than pageCount. +*/ + static inline void update_display_window_vosf(void) { int page = 0; diff --git a/BasiliskII/src/Unix/video_x.cpp b/BasiliskII/src/Unix/video_x.cpp index 886f8aa3..55802a1f 100644 --- a/BasiliskII/src/Unix/video_x.cpp +++ b/BasiliskII/src/Unix/video_x.cpp @@ -264,8 +264,6 @@ static inline int find_next_page_clear(int page) char *match = strchr(mainBuffer.dirtyPages + page, PFLAG_CLEAR_VALUE); return match ? match - mainBuffer.dirtyPages : mainBuffer.pageCount; #else - // NOTE: the loop is bound to terminate because the last - // page in mainBuffer.dirtyPages[] shall be set to CLEAR while (PFLAG_ISSET_4(page)) page += 4; while (PFLAG_ISSET(page)) @@ -945,7 +943,7 @@ bool VideoInitBuffer() if (mainBuffer.dirtyPages != 0) free(mainBuffer.dirtyPages); - mainBuffer.dirtyPages = (char *) malloc(mainBuffer.pageCount + 1); + mainBuffer.dirtyPages = (char *) malloc(mainBuffer.pageCount + 2); if (mainBuffer.pageInfo != 0) free(mainBuffer.pageInfo); @@ -956,12 +954,10 @@ bool VideoInitBuffer() return false; PFLAG_CLEAR_ALL; - - // Make sure there is at least one page marked, so the - // loops in the update routine will terminate - // gb-- Set the last page as cleared because the update - // routine finally searches for a page that was not touched + // Safety net to insure the loops in the update routines will terminate + // See a discussion in for further details PFLAG_CLEAR(mainBuffer.pageCount); + PFLAG_SET(mainBuffer.pageCount+1); uint32 a = 0; for (int i = 0; i < mainBuffer.pageCount; i++) { @@ -1955,7 +1951,7 @@ static void update_display_static(void) // We suggest the compiler to inline the next two functions so that it // may specialise the code according to the current screen depth and -// display type. A clever compiler would that job by itself though... +// display type. A clever compiler would do that job by itself though... // NOTE: update_display_vosf is inlined too