a976@mindlink.UUCP (Ron Tarrant) (01/09/91)
> m0154@tnc.UUCP writes: > > * Quick way to test for outstanding files or memory allocation - run > your program several times in succession. Use Avail and note the > amount of free memory after each one. The first time you run your > program, any needed libraries will be loaded into RAM. After that, > you should get the same amount of free ram each time. Beware if the > amount goes down by the same amount each time! > > Wildstar There's another way to do this and you only have to run your program once. When you start up WorkBench with the loadwb command, give it an argument of "-debug". This enables an "invisible" menu to the right of all others on the WB screen. This menu (accessed by holding down the right mouse button and moving the pointer to the right of the last labeled menu) has two items: debug (which sends debug info to the serial port) and flushlibs (which dumps any currently unused libraries from the system. Make note of the amount of free ram listed in the menubar of the WB screen. Then, making sure you don't resize your CLI window, run your program, do whatever with your program, then quit. Select "flushlibs", then recheck the amount of free ram in the menubar. It should be the same as what you noted before running the program. I found this tidbit in an issue of AmigaMail, I think. -Ron
rcs91900@zach.fit.edu ( Charles Stockman /ADVISOR-Clutterham) (01/09/91)
First of all I wanted to thank everyone who answered my question about how I could descrease the number of times the guru appeared. However, I would like to continue this discussion, so could someone tell me how to do safe coding (coding that protects you from the guru). ex : One technique that I know is to make sure that all files and resourses that were allocated to a program are released by the programmer. My next problem is that I am looking for the BNF of C++ . Could someone please mail it to me Once again --> Thanks a lot for your help
dave@cs.arizona.edu (Dave P. Schaumann) (01/09/91)
In article <1806@winnie.fit.edu> rcs91900@zach.fit.edu ( Charles Stockman /ADVISOR-Clutterham) writes: >First of all I wanted to thank everyone who answered my question about how >I could descrease the number of times the guru appeared. However, I would >like to continue this discussion, so could someone tell me how to do safe >coding (coding that protects you from the guru). One thing you certainly want to watch is how you use memory you get from malloc. I recently had a bug where I said 'malloc(foo)', when I really wanted 'malloc(foo * sizeof(int)'. Naturally, in the first version, subsequent code stomped all over the memory past the allocated block. Unfortunately, this contained information vital to the integrety of the free memory list. The result of this is at some time later (usually shortly after my program quit) my Amiga would crash and burn. Usually with the 'memory freed twice' guru. Dave Schaumann | My folks went to uunet.uu.net, but all dave@cs.arizona.edu | they got me was this lousy .sig...
m0154@tnc.UUCP (GUY GARNETT) (01/09/91)
In article <1806@winnie.fit.edu> rcs91900@zach.fit.edu ( Charles Stockman /ADVISOR-Clutterham) writes: >First of all I wanted to thank everyone who answered my question about how >I could descrease the number of times the guru appeared. However, I would >like to continue this discussion, so could someone tell me how to do safe >coding (coding that protects you from the guru). > >ex : One technique that I know is to make sure that all files and > resourses that were allocated to a program are released by the > programmer. > >My next problem is that I am looking for the BNF of C++ . Could someone please >mail it to me > >Once again --> Thanks a lot for your help Sorry, I don't have the BNF for C++ ... but I do have some basic tips for defensive programming. I realize that most of the readers already know most of these, but repetition never hurts. * Check all return values - Most library functions return a special value for error conditions. Test for them. I realize that this is basic stuff, but at some point that AllocMem of 32 bytes that "can't fail" will fail, and then its off to see the GURU. This also includes testing file opens & locks, and so on. If it returns a value, check it before you go on. * Pay attention to pointer usage - there have been commercially released programs which reference a null pointer, and thereby trash AbsExecBase. All it takes is one, buried somewhere in your code (cleanup and terminate routines are especially prone to this). One of the indicators of this problem is that the machine Guru's *after* you have exited your program (ie: when you try to do something else). * Quick way to test for outstanding files or memory allocation - run your program several times in succession. Use Avail and note the amount of free memory after each one. The first time you run your program, any needed libraries will be loaded into RAM. After that, you should get the same amount of free ram each time. Beware if the amount goes down by the same amount each time! * There are several good PD system and memory monitors around. If they suit your needs, use them ... Almost all of them will let you spot outstanding file allocations, and others are useful for detecting the null pointer problem. * Plan your program (even if you "don't do designs") - Planned in advance, your program can have efficient ways of performing its internal tests, and can recover or exit gracefully. Some of the best have an "exit module" which closes files, deallocates memory, and closes libraries for the whole program on exit. Grafting this kind of stuff onto an existing program is harder. Wildstar
markv@kuhub.cc.ukans.edu (01/10/91)
> * Check all return values - Most library functions return a special > value for error conditions. And pay attention to what the return value should be. Sometimes a 0 is failure, sometimes -1, sometimes 0 is success, etc. If using C lib functions also check errors. You can use _OSERR, _error, and IoErr() for more detailed info. And try to handle errors well. Some failures are critical, some aren't. If you cant open a requester, then use an Alert so the user knows what is going on. An alert will *almost* always work because it only needs a few 100 bytes. > * Pay attention to pointer usage - there have been commercially > released programs which reference a null pointer, and thereby trash > AbsExecBase. Another no-no is referenceing a pointer after it has been free, or range errors scribbling off the end of an array. On things like an array always include memory for an extra element to errors of 1 (ie referecing element index 20 in a 20 element array), or hold a NULL in a string. AllocRemember()/FreeRemember() can help with long chains of allocations. Also, when you run AVAIL, it will walk the whole system memory list, so any errors/corruption will be found. And when using things like realloc(), ParentDir(), etc (functions that "swap" data structures), dont assume the new pointer is the same as the old. > * There are several good PD system and memory monitors around. If > they suit your needs, use them ... Almost all of them will let you > spot outstanding file allocations, and others are useful for detecting > the null pointer problem. Enforcer is good for catching bad pointer refs, but needs a MMU. Mungwall munges memory around your allocations and all free RAM to increase the chance that bounds errors or RAM problems will hit (you cant find a bug you dont have). > internal tests, and can recover or exit gracefully. Some of the best > have an "exit module" which closes files, deallocates memory, and > closes libraries for the whole program on exit. Grafting this kind of > stuff onto an existing program is harder. This is the way I work. Have your pointers to things like windows, screens, etc be global. Initialize them to NULL, and set them to NULL when you free them. Then when your program exits, you can allocate all that you have freed. Ie: struct Window *OurWindow; /* Static data is NULL by default */ int DoExit(int foo) { if (OurWindow) { CloseWindow(OurWindow); } OurWindow=NULL; } This way the function can be called anywhere in your program and work pretty well. Also if using C, use the ANSI function atexit() or SAS/Lattice onexit() to install your function as an exit trap, so it gets called even if your program aborts beyond your control. > Wildstar -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Mark Gooderum Only... \ Good Cheer !!! Academic Computing Services /// \___________________________ University of Kansas /// /| __ _ Bix: markgood \\\ /// /__| |\/| | | _ /_\ makes it Bitnet: MARKV@UKANVAX \/\/ / | | | | |__| / \ possible... Internet: markv@kuhub.cc.ukans.edu ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
jesup@cbmvax.commodore.com (Randell Jesup) (01/10/91)
In article <629@caslon.cs.arizona.edu> dave@cs.arizona.edu (Dave P. Schaumann) writes: >One thing you certainly want to watch is how you use memory you get from >malloc. I recently had a bug where I said 'malloc(foo)', when I really >wanted 'malloc(foo * sizeof(int)'. Naturally, in the first version, subsequent >code stomped all over the memory past the allocated block. Unfortunately, >this contained information vital to the integrety of the free memory list. > >The result of this is at some time later (usually shortly after my program >quit) my Amiga would crash and burn. Usually with the 'memory freed twice' >guru. Ah, you need MungWall! Mungwall would catch that, and show you the trashing (as well as mostly insulate the system from the error, unless you went _way_ out of bounds). -- Randell Jesup, Keeper of AmigaDos, Commodore Engineering. {uunet|rutgers}!cbmvax!jesup, jesup@cbmvax.commodore.com BIX: rjesup The compiler runs Like a swift-flowing river I wait in silence. (From "The Zen of Programming") ;-)
dave@cs.arizona.edu (Dave P. Schaumann) (01/10/91)
In article <1806@winnie.fit.edu> rcs91900@zach.fit.edu ( Charles Stockman /ADVISOR-Clutterham) writes: >My next problem is that I am looking for the BNF of C++ . Could someone >please mail it to me > If you have access to ftp, check out the FAQ list in comp.compilers. That lists a sight that has a yacc grammar for C++ (which is not the same as BNF, but the differences are minor). If this is not satisfactory, you might have better success with your request if you posted it to comp.lang.c++. >Once again --> Thanks a lot for your help No problem. Dave Schaumann | You are in a twisty maze of little dave@cs.arizona.edu | C statements, all different.
jap@convex.cl.msu.edu (Joe Porkka) (01/11/91)
a976@mindlink.UUCP (Ron Tarrant) writes: >> m0154@tnc.UUCP writes: >There's another way to do this and you only have to run your program once. >screen. Then, making sure you don't resize your CLI window, run your program, >do whatever with your program, then quit. Select "flushlibs", then recheck the >amount of free ram in the menubar. It should be the same as what you noted >before running the program. I dunno if this takes into account libs opening libs. I have a program that does the following y=AvailMem(0) do { x=y; t=AllocMem(1<<31); /* Should fial :-) */ if(t!=0) {FreeMem(t,1<<31); break;} y=AvailMem(0); } while(x<y); printf("%d %d\n", x, y); This makes as much free mem as possible, even if open lib opens other libs.
rg20+@andrew.cmu.edu (Rick Francis Golembiewski) (01/11/91)
A Few trick that I have found to be very helpful in dealing with pointers, is that you should initalize all pointers to NULL, and also EXPECT all pointers that you deal with to be NULL. (ie make loops like while (foo != NULL) {..} (and be sure that foo will at some point be NULL) Also if you have pointers to pointers, like: foo->bar->var, be sure that foo and bar are NOT NULL. before doing foo->bar->var=value; Also watch when passing constant arguments, for instance calling: foo(A,B,0,D) for int foo(A,B,C,D) double A,B,C,D; { } is wrong, it should be foo(A,B,0.0,D) ^ | This a a FP argument while 0 is interpreted as an integer argument, so the values for C & D will be mangled (I've been bitten on this one with Lattice a few times). Another thing, if you have an array like: char foo[MAXLEN]; When you do loops include, i=0; while( i<MAXLEN) {foo[i++]='\0'....} That way you don't overrun the size of the array, this is especially important when doing string functions, as there might be some without proper '\0' terminations. In general it's a good idea to initiallize ALL of your variables, as some compilers initalize vars to 0 while others may not. Try not to have lots of global variables, but if a variable gets passed to most every function it is probabily a good idea to make it globa (things like window & screen pointers are things that come to mind). Try to break down your code into small modules so that they are easier to debug, (and so that the smaller lower level modules may be used in other programs without rewriting them). Don't make allocations (of memory, or any ofther resource ie [ports, audio chanels]) unless you need them, adnd then FREE THEM UP WHEN YOU ARE DONE! (ie fclose(file), free(memory) etc.). There are certainly several other good programming practices, but I think that this post is long enough already. I'm sure that if I've made any mistakes in the above I'll get plenty of flames for it... // Rick Golembiewski rg20+@andrew.cmu.edu \\ \\ #include stddisclaimer.h // \\ "I never respected a man who could spell" // \\ -M. Twain //
mykes@zorch.SF-Bay.ORG (Mike Schwartz) (01/11/91)
I use Manx 'C' 3.6, so my advise may be limited to this environment. Manx supplies a routine called _abort() in the library which can be used to make programs that EASILY clean up after themselves. The routine is automatically called by the Manx debuggers anytime you want to abort the program in the middle of a debug session. The routine is also called when you hit ^C while the program is running. By supplying your own _abort() routine, you can override the one in the library and use it to your advantage. Consider the following code (I have something like it in every one of my 'C' programs): struct IntuitionBase *IntuitionBase = 0; struct GfxBase *GfxBase = 0; /* other libraries can be opened as well... */ struct Screen *screen = 0; struct Window *window = 0; int _abort_code = 0; _abort() { struct IntuiMessage *m; if (window) { while (m = (struct IntuiMessage *)GetMsg(window->UserPort)) ReplyMsg(m); CloseWindow(window); window = 0; } if (screen) { CloseScreen(screen); screen = 0; } if (GfxBase) { CloseLibrary(GfxBase); GfxBase = 0; } if (IntuitionBase) { CloseLibrary(IntuitionBase); IntuitionBase = 0; } exit(_abort_code); } panic(s, a1,a2,a3,a4,a5,a6,a7,a8) ULONG s,a1,a2,a3,a4,a5,a6,a7,a8; /* who cares what type they were... */ { printf(s, a1,a2,a3,a4,a5,a6,a7,a8); _abort_code = 999; _abort(); } panic0(v, s, a1,a2,a3,a4,a5,a6,a7,a8) ULONG s,a1,a2,a3,a4,a5,a6,a7,a8; /* ULONG can be int,short,byte, etc. */ { if (v) return; /* only panic if v is zero */ printf(s, a1,a2,a3,a4,a5,a6,a7,a8); _abort_code = 999; _abort(); } main() { IntuitionBase = (struct IntuitionBase *)OpenLibrary( "intuition.library", 0); panic0(IntuitionBase, "Can't open intuition\n"); GfxBase = ... /* application goes here */ _abort(); /* _abort instead of exit */ } The code for panic shows how (using 32-bit INT model of Manx) you can make a printf() like routine without a lot of ugly looking code. The drawback is that you are pushing a lot of parameters in a lot of places. The code for panic0 shows a way to eliminate a lot of "if" statements from your source code, making a much more brief and readable program. The reason I set the things that _abort() cleans up back to zero is so that if I am using a debugger, or I make a bug that calls _abort() twice somehow, I can use the debugger to execute _abort() again without cleaning up things twice (it may not be too clear from my explanaition, so): You are in your debugger. You can just say "modify register PC = " _abort() and then GO and your program cleans up and exits. Some more tips... You should look at the fields in the Task structure. There are ways to eliminate most GURUs from happening if you install your own exception handler. The vast majority of GURUs are recoverable (merely an odd address or illegal instruction). If you make an exception handler, you can force the program to use your _abort() routine instead of the default "GURU" handlers which force you to reboot. I hate typing Intuition because I constantly misspell it (Intutition, etc.). I hate typing (struct anything *) to cast. I hate typing struct anything period. So what I did was to make an include file called "host.h" that looks something like this: typedef struct IntuitionBase IBASE; typedef struct GfxBase GBASE; typedef struct RastPort RPORT; typedef struct MessagePort MPORT; typedef struct Message MSG; typedef struct IntuiMessage IMSG; etc. I put all kinds of things in this file that I used to retype in many many times/programs. Now I can do: IBASE *IntuitionBase; msg = (MSG *)malloc(sizeof(MSG)); etc. Which is much easier to read and type. Another candidate for the host.h file is function declarations like: UBYTE *malloc(); and another is parameters to open() which I hate to type as well: #define O_READ O_RDONLY #define O_WRITE (O_WRONLY|O_CREAT|O_TRUNC) If you don't have powerwindows, get it. It is the fastest and most interactive way I've found to generate all those nasty intuition structures a program needs. I hope this is some help. Mykes
dillon@overload.Berkeley.CA.US (Matthew Dillon) (01/14/91)
In article <1991Jan11.073543.16293@zorch.SF-Bay.ORG> mykes@zorch.SF-Bay.ORG (Mike Schwartz) writes: >I use Manx 'C' 3.6, so my advise may be limited to this environment. > >Manx supplies a routine called _abort() in the library which can be Under ANSI C you can use atexit(). This will be MUCH more portable then _abort() which is MANX specific. main() { atexit(myexitrt); ... } myexirt() is called when the program exits, whether it be a normal exit or an abnormal exit. >The code for panic shows how (using 32-bit INT model of Manx) you can >make a printf() like routine without a lot of ugly looking code. The >drawback is that you are pushing a lot of parameters in a lot of places. Additionally, under ANSI C, there are var-args printing calls, vprintf(), vsprintf(), and vfprintf(). These make it easy to write your own error-printing routines without having to hack large variable lists: /* * Example use var-args [v]*printf() orutines * get the math pfmt. */ #include <stdio.h> #include <stdarg.h> void gagprint(char *, ...); main() { gagprint("%d %d %d\n", 1, 2, 3); return(0); } void gagprint(ctl, ...) char *ctl; { va_list va; int n; va_start(va, ctl); n = vprintf(ctl, va); printf("%d chars written\n", n); va_end(va); } > >Mykes -- -Matt Matthew Dillon dillon@Overload.Berkeley.CA.US 891 Regal Rd. uunet.uu.net!overload!dillon Berkeley, Ca. 94708 USA
dillon@overload.Berkeley.CA.US (Matthew Dillon) (01/14/91)
In article <8bXHP_y00VIFALti1O@andrew.cmu.edu> rg20+@andrew.cmu.edu (Rick Francis Golembiewski) writes: > >Also watch when passing constant arguments, for instance calling: >foo(A,B,0,D) >for >int foo(A,B,C,D) >double A,B,C,D; >{ >} >is wrong, it should be >foo(A,B,0.0,D) > ^ > | > This a a FP argument while 0 is interpreted as an integer argument, This is one of things that prototypes will do for you... argument converesion. If you had the prototype: int foo(double, double, double, double); then foo(A,B,0,D); will work just fine. >In general it's a good idea to initiallize ALL of your variables, as >some compilers initalize vars to 0 while others may not. Not true, you can rely on static's and global's being initialized to 0, assuming you go through the normal startup obj for the compiler. auto's (stack variables) are NOT initialized (i.e. contain garbage until you initialize them) >Try not to have lots of global variables, but if a variable gets >passed to most every function it is probabily a good idea to make it >globa (things like window & screen pointers are things that come to >mind). Try to break down your code into small modules so that they are >easier to debug, (and so that the smaller lower level modules may be >used in other programs without rewriting them). Don't make >allocations (of memory, or any ofther resource ie [ports, audio >chanels]) unless you need them, adnd then FREE THEM UP WHEN YOU ARE >DONE! (ie fclose(file), free(memory) etc.). There are certainly >several other good programming practices, but I think that this post >is long enough already. I'm sure that if I've made any mistakes in >the above I'll get plenty of flames for it... Those are good points. The term you are looking for 'Modularity'. I have found that by dividing procedures in a logical manner and not using globals for variables that really ought to be locals (like a loop counter) you generally wind up with much better code no matter what kind of programmer you are. >// Rick Golembiewski rg20+@andrew.cmu.edu \\ >\\ #include stddisclaimer.h // > \\ "I never respected a man who could spell" // > \\ -M. Twain // -- -Matt Matthew Dillon dillon@Overload.Berkeley.CA.US 891 Regal Rd. uunet.uu.net!overload!dillon Berkeley, Ca. 94708 USA
andrew@teslab.lab.OZ (Andrew Phillips) (01/24/91)
In article <1991Jan11.073543.16293@zorch.SF-Bay.ORG> mykes@zorch.SF-Bay.ORG (Mike Schwartz) writes: >Manx supplies a routine called _abort() in the library which can be >used to make programs that EASILY clean up after themselves. ... For portability you would be better off using the ANSI routine onexit(), which allows you to register routines to be called when exit() is called. This has the advantage of allowing reusable routines to have this facility without _abort() having to know how they work internally. >panic(s, a1,a2,a3,a4,a5,a6,a7,a8) >ULONG s,a1,a2,a3,a4,a5,a6,a7,a8; /* who cares what type they were... */ >{ > printf(s, a1,a2,a3,a4,a5,a6,a7,a8); >... >The code for panic shows how (using 32-bit INT model of Manx) you can >make a printf() like routine without a lot of ugly looking code. The >drawback is that you are pushing a lot of parameters in a lot of places. Why not use vprintf() which is neater and is also ANSI, from memory. The above also won't work if you have too many parameters to panic. >panic0(v, s, a1,a2,a3,a4,a5,a6,a7,a8) --------^------- >ULONG s,a1,a2,a3,a4,a5,a6,a7,a8; /* ULONG can be int,short,byte, etc. */ >{ >... > panic0(IntuitionBase, "Can't open intuition\n"); This is a really good idea but, shouldn't "v" be declared to be a "void *" rather than defaulting to int. -- Andrew Phillips (andrew@teslab.lab.oz.au) Phone +61 (Aust) 2 (Sydney) 289 8712
andrew@teslab.lab.OZ (Andrew Phillips) (01/24/91)
In article <8bXHP_y00VIFALti1O@andrew.cmu.edu> rg20+@andrew.cmu.edu (Rick Francis Golembiewski) writes:
]int foo(A,B,C,D)
]double A,B,C,D;
]{
]...
]foo(A,B,0,D)
]is wrong, it should be
]foo(A,B,0.0,D)
] ^
] |
] This a a FP argument while 0 is interpreted as an integer argument,...
This is why function prototypes were invented, use them!
]In general it's a good idea to initiallize ALL of your variables, as
]some compilers initalize vars to 0 while others may not.
This is not true.
Uninitialised static variables are *always* guaranteed to be zero.
Uninitialised auto variables are *never* guaranteed to be anything.
--
Andrew Phillips (andrew@teslab.lab.oz.au) Phone +61 (Aust) 2 (Sydney) 289 8712