问题描述
Borland的BGI图形库(GRAPHICS.LIB,GRAPHICS.TPU)有一个错误
,这可能导致Floodfill例程崩溃。当使用小数据(64K)内存模型编译时,它最有可能发生在C
应用程序中。
要查看操作中的错误,编译下面提供的C演示程序。确保
确保目标设置为DOS且使用中小型内存模型。
对于洪水填充而言,需要满足两个条件:
- 填充足够复杂以填充泛滥堆栈
- 分配空闲内存时返回的指针(通常是
段/偏移对) )没有偏移值= 0.
第一个条件可以在任何目标中发生(例如,在具有许多对象的
屏幕上执行''外部填充'' )。
第二种情况通常发生在小型内存模型上。我还没有找到Pascal或C大内存模型崩溃,这表明他们的内存分配方案会返回一个偏移量为0的指针。但是否是
这是*总是*案例是问题(?)
为什么错误发生如下。当启动图形模式时,它将4096字节的图形缓冲区分配给b
。从堆。在进行填充之前,堆栈
切换到图形缓冲区。相关的库代码(模块graph.obj)是:
_floodfill:
...
les si,dword_10025
mov di,es:[si + 0Ch]; buffer addr(offset)
mov dx,es:[si + 0Eh]; buffer addr(segment)
add di,es:[si + 10h];缓冲区大小默认= 4096
sub di,2
cli
xchg sp,di
mov bp,ss
mov ss,dx
sti
push di
push bp
mov si,44
来电dword ptr ds:__ DDO_ADD;洪水填充
pop bx
pop ax
cli
mov ss,bx
mov sp,ax
sti
...
实际的洪水填充是在BGI驱动程序中完成的。随着项目的增加,洪水堆向下建立
。 Floodfill假设内存扩展到SSEG:0000。
给定上面的堆栈初始化例程,只有当图形缓冲区指针的偏移部分为/ b $ b为0000h时才会出现这种情况。在小型内存模型中,很少会出现这种情况,导致溢出溢出其边界并破坏其他分配的内存(因此崩溃)。
修复是使SSEG:0000始终驻留在图形缓冲区内。
合适的代码可能是:
; mov di,es:[si + 0Ch]
; mov dx,es:[si + 0Eh]
; add di,es:[si + 10h]
; sub di,2
mov dx,es:[si + 0Ch]
shr dx,1
shr dx,1
shr dx,1
shr dx,1
inc dx;圆形起来是安全的
添加dx,es:[si + 0Eh]
mov di,es:[si + 10h]
sub di,16 + 2;调整汇总
应该说虽然bug存在,但并不一定需要修复。
只会发生bug的影响一旦图形缓冲区已经填满。
无论如何,拥有一个完整的缓冲区是致命的。因此,无论是否填充
都会导致内存不足错误消息或崩溃,它会警告
程序员增加图形缓冲区大小。
以下是我使用的洪水填充测试程序(C和Pascal中的版本)。
祝你好运。
-------------------------------------------------- --------------------
/ *展示洪水填充和内存不足情况* /
/ *需要EGAVGA.BGI * /
int svga = 0; / * BGI驱动程序:0 = EGAVGA,1 = SVGA * /
int size = 16; / *使这个更小的结果导致更多的对象
在屏幕上* /
#include< graphics.h>
#include< stdlib.h>
#include< stdio.h>
#include< conio.h>
void box(x1,y1,x2,y2)
int x1,y1,x2,y2;
{
moveto(x1 ,y1);
lineto(x1,y2); lineto(x2,y2);
lineto(x2,y1); lineto(x1,y1);
}
int main(无效)
{
int gdriver,gmode,errorcode;
int maxx,maxy,i,j,wid,dia,offs;
if(svga)
{gdriver =(installuserdriver(" SVGA",NULL)); gmode = 1; } / * SVGA.BGI * /
else
{gdriver = 9; gmode = 2; } / *使用EGAVGA.BGI * /
;
initgraph(& gdriver,& gmode,"");
/ *读取初始化结果* /
errorcode = graphresult();
if(errorcode!= grOk)
/ *发生了错误* /
{
printf(" Graphics init error \ n");
getch( );
退出(1);
/ *以错误代码终止* /
}
maxx = getmaxx(); maxy = getmaxy();
setcolor(1);
wid = size * 2;
dia =(wid / 2)-2;
offs =(wid / 2)-dia;
for(j = 0; j<(maxy- wid + 1); j = j + wid){
for(i = 0; i<(maxx-wid + 1); i = i + wid){
/ * circle(wid / 2 + i,wid / 2 + j,dia); * /
盒子(i + offs,j + offs,i + offs + dia,j + offs + dia);
}
}
getch();
setfillstyle(1,3);
/ *填写有界区域* /
floodfill(0,0,1);
if(graphresult()!= grOk){
setcolor(15);
outtextxy(0,0,错误:溢出内存!);
}
getch();
closegraph();
返回0;
}
---- -------------------------------------------------- ----------------
(*显示洪水填充和内存不足情况*)
( *需要EGAVGA.BGI *)
程序Floodtest;
使用Graph,Crt;
程序BOX(var x1,y1,x2,y2:整数);
开始
moveto(x1,y1);
lineto( X1,Y2); lineto(x2,y2);
lineto(x2,y1); lineto(x1,y1);
end;
var gdriver,gmode:integer;
var errorcode,maxx,maxy ,i,j,wid,dia,offs,a,b,c,d:整数;
var svga,size:integer;
var ch:char;
开始
svga:= 0; (* BGI驱动程序:0 = EGAVGA,1 = SVGA *)
size:= 16; (*使这个更小的结果更多的对象
在屏幕上*)
wid:= size * 2;
dia :=(wid div 2)-2;
offs:=(wid div 2)-dia;
if(svga<> 0)then
开始
gdriver:=(installuserdriver(''SVGA'',nil)); gmode:= 1; (* SVGA.BGI *)
结束
其他
开始gdriver:= 9; gmode:= 2;结束; (*使用EGAVGA.BGI *)
initgraph(gdriver,gmode,'''');
errorcode:= GraphResult;
如果错误代码<> grOk然后
开始
WriteLn(''图形初始化错误'');
ch:= Readkey;
退出;
结束;
maxx:= getmaxx; maxy:= getmaxy;
setcolor(1);
j:= 0;
而j< (maxy-wid)做
开始
i:= 0;
而我< (maxx-wid)做
开始
a:=(wid div 2)+ i; b:=(wid div 2)+ j;
a:= i + offs; b:= j + offs; c:= i + offs + dia; d:= j + offs + dia;
框(a,b,c,d);
i:= i + wid;
结束;
j:= j + wid
结束;
ch:= Readkey;
setfillstyle(1,3);
FloodFill(0,0,1);
如果GraphResult<> grOk然后
开始
setcolor(15);
outtextxy(0,0,''错误:洪水记忆!'') ;
结束;
ch:= Readkey;
CloseGraph;
end。
---------------------------------------- ------------------------------
comp.lang.c不合适论坛,尝试与你的环境一起交易
。
-
Ian Collins。
comp.lang.c不适合这个,尝试与您的环境进行交易
。
你能建议吗?我在发布之前做了一些检查,发现
Borland新闻组针对特定(和当前)产品。
查看Google的comp.lang.c档案我看到与产品特定主题相关的大量帖子
而没有人抱怨它们。
comp.lang.c不合适论坛,尝试与您的环境进行交易
。
你能建议吗?我在发布之前做了一些检查,发现Borland新闻组针对的是特定(和当前)产品。
在浏览Google的comp.lang.c档案时,我看到了很多帖子
与产品特定主题相关,没有人抱怨它们。
我不知道,搜索谷歌群组是否显示?常客
这里的产品特定帖子往往会变得粗糙。
-
Ian Collins。
Borland''s BGI graphics library (GRAPHICS.LIB, GRAPHICS.TPU) has a bug
which can cause the floodfill routine to crash. It''s most likely to occur in C
applications when compiled using the small data (64K) memory models.
To see the bug in action, compile the C demo program supplied below. Make
sure the target is set for DOS and the small or medium memory model is used.
For floodfill to crash requires two conditions be met:
- the fill is complex enough that it fills the flood stack
- the pointer returned when free memory is allocated (usually a
segment/offset pair) does not have the "offset" value = 0.
The first condition can occur in any target (e.g. by doing an ''outside fill'' on a
screen that has many objects).
The second condition typically occurs on small memory models. I''ve yet
to find Pascal or the C large memory models crashing which suggests their
memory allocation schemes returns a pointer with offset = 0. But whether
this is *always* the case is the question (?)
Why the bug happens is as follows. When a graphic mode is initiated, it allocates
a 4096 byte "graphics buffer" from the heap. Prior to doing a floodfill, the stack
is switched to the graphics buffer. The relevent library code (module graph.obj) is:
_floodfill:
...
les si, dword_10025
mov di, es:[si+0Ch] ; buffer addr (offset)
mov dx, es:[si+0Eh] ; buffer addr (segment)
add di, es:[si+10h] ; buffer size default = 4096
sub di, 2
cli
xchg sp, di
mov bp, ss
mov ss, dx
sti
push di
push bp
mov si, 44
call dword ptr ds:__DDO_ADD ; do floodfill
pop bx
pop ax
cli
mov ss, bx
mov sp, ax
sti
...
The actual floodfill is done in the BGI driver. The flood stack builds downwards
as items are added. Floodfill assumes that memory extends down to SSEG:0000.
Given the stack initialization routine above, this can only be true if the offset part
of graphics buffer pointer is 0000h. In small memory models that''s rarely the
case, resulting in floodfill overflowing its bounds and corrupting other allocated
memory (hence the crash).
The fix is to make SSEG:0000 always reside within the graphics buffer.
Suitable code might be:
; mov di, es:[si+0Ch]
; mov dx, es:[si+0Eh]
; add di, es:[si+10h]
; sub di, 2
mov dx, es:[si+0Ch]
shr dx,1
shr dx,1
shr dx,1
shr dx,1
inc dx ; round up to be safe
add dx, es:[si+0Eh]
mov di, es:[si+10h]
sub di, 16+2 ; adjust for roundup
It should be said that while the bug exists, it doesn''t necessarily need fixing.
The bug''s effect only occurs once the graphics buffer has filled up.
Having a full buffer is a fatal condition anyway. So whether floodfill
results in an out of memory error message or a crash, it''s warning the
programmer to increase the graphics buffer size.
Below is the floodfill test program I used (versions in C and Pascal).
Good luck.
----------------------------------------------------------------------
/* Demonstrate floodfill and out-of-memory condition */
/* needs EGAVGA.BGI */
int svga = 0; /* BGI driver: 0=EGAVGA, 1=SVGA */
int size = 16; /* making this smaller results in more objects
on the screen */
#include <graphics.h>
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
void box(x1,y1,x2,y2)
int x1,y1,x2,y2;
{
moveto(x1,y1);
lineto(x1,y2); lineto(x2,y2);
lineto(x2,y1); lineto(x1,y1);
}
int main(void)
{
int gdriver, gmode, errorcode;
int maxx, maxy, i, j, wid, dia, offs;
if (svga)
{ gdriver = (installuserdriver("SVGA", NULL)); gmode = 1; } /* SVGA.BGI */
else
{ gdriver = 9; gmode = 2; } /* use EGAVGA.BGI */
;
initgraph(&gdriver, &gmode, "");
/* read result of initialization */
errorcode = graphresult();
if (errorcode != grOk)
/* an error occurred */
{
printf("Graphics init error\n");
getch();
exit(1);
/* terminate with an error code */
}
maxx = getmaxx(); maxy = getmaxy();
setcolor(1);
wid = size*2;
dia = (wid/2)-2;
offs = (wid/2)-dia;
for( j=0; j<(maxy-wid+1); j=j+wid){
for( i=0; i<(maxx-wid+1); i=i+wid){
/* circle(wid/2+i, wid/2+j, dia); */
box(i+offs, j+offs, i+offs+dia, j+offs+dia);
}
}
getch();
setfillstyle(1,3);
/* fill in bounded region */
floodfill(0, 0, 1);
if (graphresult() != grOk) {
setcolor(15);
outtextxy(0,0,"Error: Out of flood memory!");
}
getch();
closegraph();
return 0;
}
----------------------------------------------------------------------
(* Demonstrate floodfill and out-of-memory condition *)
(* needs EGAVGA.BGI *)
program Floodtest;
uses Graph, Crt;
procedure BOX (var x1,y1,x2,y2: integer);
begin
moveto(x1,y1);
lineto(x1,y2); lineto(x2,y2);
lineto(x2,y1); lineto(x1,y1);
end;
var gdriver, gmode: integer;
var errorcode, maxx, maxy, i, j, wid, dia, offs, a, b, c, d: integer;
var svga, size: integer;
var ch: char;
begin
svga := 0; (* BGI driver: 0=EGAVGA, 1=SVGA *)
size := 16; (* making this smaller results in more objects
on the screen *)
wid := size*2;
dia := (wid div 2)-2;
offs := (wid div 2)-dia;
if (svga<>0) then
begin
gdriver := (installuserdriver(''SVGA'', nil)); gmode := 1; (* SVGA.BGI *)
end
else
begin gdriver := 9; gmode := 2; end; (* use EGAVGA.BGI *)
initgraph(gdriver, gmode, '' '');
errorcode := GraphResult;
if errorcode <> grOk then
begin
WriteLn(''Graphics init error'');
ch := Readkey;
exit;
end;
maxx := getmaxx; maxy := getmaxy;
setcolor(1);
j := 0;
while j < (maxy-wid) do
begin
i := 0;
while i < (maxx-wid) do
begin
a := (wid div 2)+i; b := (wid div 2)+j;
a := i+offs; b := j+offs; c := i+offs+dia; d := j+offs+dia;
box(a, b, c, d);
i := i+wid;
end;
j := j+wid
end;
ch := Readkey;
setfillstyle(1,3);
FloodFill(0,0,1);
if GraphResult <> grOk then
begin
setcolor(15);
outtextxy(0,0,''Error: Out of flood memory!'');
end;
ch := Readkey;
CloseGraph;
end.
----------------------------------------------------------------------
comp.lang.c isn''t the appropriate forum for this, try a group the deals
with your environment.
--
Ian Collins.
comp.lang.c isn''t the appropriate forum for this, try a group the deals
with your environment.
Can you suggest one? I did some checking before posting and found
the Borland newsgroups were aimed at specific (and current) products.
In looking through Google''s comp.lang.c archive I see voluminous posts
related to product-specific topics and no-one complained about them.
comp.lang.c isn''t the appropriate forum for this, try a group the deals
with your environment.
Can you suggest one? I did some checking before posting and found
the Borland newsgroups were aimed at specific (and current) products.
In looking through Google''s comp.lang.c archive I see voluminous posts
related to product-specific topics and no-one complained about them.
I don''t know, does a search of google groups show any? The regulars
here tend to get stroppy with product specific posts.
--
Ian Collins.
这篇关于Borland BGI洪水填充bug的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!