debugging print statements cause of trouble.

9 posts / 0 new
Last post
JosDuchIt
JosDuchIt's picture
Offline
Last seen: 7 years 4 months ago
Joined: 2012-01-08 20:57
debugging print statements cause of trouble.

Maybe now that DBG is said to be operational again i will encounter less problems.
However i have lost hours(days really) on finding a bug that was just a print statement in
a backfill hook function.

I also had trouble with printstatements (PutStr) in the library and interface closing code.

In code using the pipe functions i learned that PutStr() is safe, and Printf freezes the system. How about the experience of old hands?

salass00
salass00's picture
Offline
Last seen: 1 year 1 month ago
Joined: 2011-02-03 11:27
@JosDuchIt Better use

@JosDuchIt

Better use DebugPrintF() always for debug output because it can also be used in cases where you can't use dos.library functions.

salass00
salass00's picture
Offline
Last seen: 1 year 1 month ago
Joined: 2011-02-03 11:27
In code using the pipe


In code using the pipe functions i learned that PutStr() is safe, and Printf freezes the system. How about the experience of old hands?

Not sure what you are doing here but the main difference between Printf() and PutStr() apart from the obvious one that Printf() allows formatting options while PutStr() doesn't is that Printf() is a buffered i/o call (like FWrite() f.e.) while PutStr() isn't (like Write()). The buffering means obviously that data is not necessarily written to the Output() filehandle immediately (you can use FFlush() to force it to be written).

JosDuchIt
JosDuchIt's picture
Offline
Last seen: 7 years 4 months ago
Joined: 2012-01-08 20:57
Not sure what you are doing

Not sure what you are doing here

Checking what i did use : it was not PutStr but the function
PrintStr() suggested to me by Joerg van de Loo (bareEd author)

  1. SAVEDS void PrintStr( const STRPTR text)
  2. {
  3. Write( Output(), text, mystrlen( text));
  4. }
  5.  
  6. ///ULONG mystrlen( const TEXT *text)
  7. ULONG mystrlen( const char *text)
  8. {
  9. ULONG len = 0;
  10. /// const TEXT *strt;
  11. const char *strt;
  12.  
  13. if (text)
  14. {
  15. strt = text;
  16. while (*text)
  17. text ++;
  18.  
  19. len = text - strt;
  20. }
  21.  
  22. return len;
  23. }

I am not able to comment on why this one behaves better

JosDuchIt
JosDuchIt's picture
Offline
Last seen: 7 years 4 months ago
Joined: 2012-01-08 20:57
Better use DebugPrintF()

Better use DebugPrintF() always for debug output because it can also be used in cases where you can't use dos.library functions.

Thanks for the suggestion.

Starting from code i borrowed from D Keletsekis
i did also use the following include debug.h

You can add more defines similar to MYDEBUGA & B

The idea is to taylor the debugging output to problem at hand

When compiling debugged code, i either do not include debug.h

or modify below
#define MYDEBUG 1
and all others to 0 (if leave some of them to you just get some warnings)

(I do check first if Da( Db( do not appear in the code to debug.)

  1. #define MYDEBUGA 0
  2. #define MYDEBUGB 1
  3. #define MYDEBUG0 0
  4.  
  5. #if MYDEBUGA
  6. #define Da(x) (x)
  7. #endif
  8.  
  9. #if MYDEBUGB
  10. #define Db(x) (x)
  11. #endif
  12.  
  13. #if MYDEBUG0
  14. #define Da(x) ;
  15. #define Db(x) ;
  16. #endif
salass00
salass00's picture
Offline
Last seen: 1 year 1 month ago
Joined: 2011-02-03 11:27
@JosDuchIt Actually checking

@JosDuchIt

Actually checking the autodoc again I was wrong and PutStr() is buffered too (your PrintStr() function isn't though).

TBH unless you post some code of how you use Printf() and how you replaced it with PrintStr() function it's pretty hard to guess what exactly you are trying to do and what you are doing wrong. F.e. it could be as simple as the fact that your PrintStr() is able to "handle" a NULL value of "text" parameter thanks to mystrlen() function. IMHO though if you have a string pointer you want to print which may or may not be NULL your better off doing something like this:

PutStr(text ? text : "(null)");
PutStr("\n");

or more advanced:

Printf("Text: %s\n", text ? text : "(null)");

In this case you are not dependant on how the function used to print text handles a NULL value, which is usually not documented, and especially bad to do if your code uses an ansi function like printf() where implementation will vary depending on what compiler and C library is used.

JosDuchIt
JosDuchIt's picture
Offline
Last seen: 7 years 4 months ago
Joined: 2012-01-08 20:57
@salass00 Thanks for the

@salass00
Thanks for the suggestions, especially the warning for printf
In fact i did expect reactions to be more like " o yes don't use print statements of any kind here and there, because of sideffects, race conditions and the like"

So i will give successive examples of print statements that generated crashes and were not trying to print a NULL pointer

For sure i did an overkill of debug prints in the closing of libraries below, but why the PutStr generated systematic freezes remains unclear to me. I indeed had to comment out the print stements in sequence, the crashings were displaced from one DropInterface to the next, whera the print output just before the drop never succeeded.

  1. if (CxBase) CloseLibrary (CxBase);
  2. if (ICommodities)
  3. { //Db(PutStr("IComm present\n")); // Not printed
  4. DropInterface( (struct Interface *) ICommodities); // crash at closing
  5. }
  6.  
  7. if (GfxBase) CloseLibrary (GfxBase); //changed
  8. if (IGraphics)
  9. { //Db(PutStr("Gr present\n"));
  10. DropInterface( (struct Interface *) IGraphics); // now crash here
  11. }
  12. if (DiskfontBase) CloseLibrary (DiskfontBase); //changed
  13. if (IDiskfont)
  14. { //Db(PutStr("DF present\n"));
  15. DropInterface( (struct Interface *) IDiskfont); //others not compilabel
  16. }
  17. if (AslBase) CloseLibrary (AslBase);
  18. if (IAsl)
  19. { //Db(PutStr("ASl present\n"));
  20. DropInterface( (struct Interface *) IAsl);
  21. }
  22. if (RexxSysBase) CloseLibrary (RexxSysBase); //changed
  23. if (IRexxSys)
  24. { //Db(PutStr("RS present\n"));
  25. DropInterface( (struct Interface *) IRexxSys);
  26. }
  27. if (GadToolsBase) CloseLibrary (GadToolsBase);
  28. if (IGadTools)
  29. { //Db(PutStr("GT present\n"));
  30. DropInterface( (struct Interface *) IGadTools);
  31. }
  32. if (UtilityBase) CloseLibrary (UtilityBase);
  33. if (IUtility)
  34. { //Db(PutStr("Ut present\n"));
  35. DropInterface( (struct Interface *) IUtility);
  36. }
  37. if (INTUIisopen) CloseLibrary (IntuitionBase);
  38. if (IIntuition)
  39. { //Db(PutStr("Int present\n"));
  40. DropInterface( (struct Interface *) IIntuition);
  41. }
  42. if (IconBase) CloseLibrary (IconBase);
  43. if (IIcon)
  44. { //Db(PutStr("Ic present\n"));
  45. DropInterface( (struct Interface *) IIcon);
  46. }
  47. if (WorkbenchBase) CloseLibrary (WorkbenchBase);
  48. if (IWorkbench)
  49. { //Db(PutStr("Wb present\n"));
  50. DropInterface( (struct Interface *) IWorkbench);
  51. }
  52. if (DOSBase) //changed
  53. { //Db(PutStr("DOSBase present\n"));
  54. CloseLibrary (DOSBase);
  55. }
  56.  
  57. if (IDOS) DropInterface( (struct Interface *) IDOS);
  58.  
  59.  
  60. exit (ProgRET);
  61.  
  62. } // * END OF MAIN * /
JosDuchIt
JosDuchIt's picture
Offline
Last seen: 7 years 4 months ago
Joined: 2012-01-08 20:57
I had trouble also with print

I had trouble also with print statements in trying to fix a piper() function that is the heart of the implementation of an xPIPE event in Gui4Cli
In Gui4Cli language the program would have some lines like

xPIPE MyPipe ON // or off
;// now here, the internal var $$PIPE.TXT has a line of text ir somebody wrote to the pipe
;// ready for us. We can output it to the Gui4Cli output console with
Say $$PIPE.TXT

In the original (SAS compilable pre-OS4) source The function looked like this

  1. __saveds
  2. void piper(void)
  3. {
  4. struct Process *myself;
  5. struct LaunchMessage *mess;
  6. struct MsgPort *host=NULL, *pipeport=NULL; // 2 ports
  7. struct gcmsg gmsg, *repmsg; // the message structure
  8. UBYTE *inbuff = NULL; // buffer pointer
  9. UBYTE pname[100]; // full name of pipe
  10. struct Event *bt;
  11. UBYTE g;
  12. BPTR fp = NULL;
  13. LONG c, ret, buffsize, bufflimit, d;
  14. ULONG sig;
  15.  
  16. // ------------- get start-up message
  17.  
  18. myself = (struct Process *)FindTask(NULL); // this process
  19. pipeport = &myself->pr_MsgPort; // and it's port
  20. WaitPort(pipeport);
  21. mess = (struct LaunchMessage *)GetMsg(pipeport); // the message from G4C
  22. host = mess->rm_Node.mn_ReplyPort; // Gui4Cli message port
  23. bt = mess->bt; // the calling event
  24. buffsize = mess->ID; // size of input buffer
  25. strncpy (pname, mess->comline, 95); // get the pipe name
  26. pname[95] = 0;
  27. mess->task = NULL; // ==NULL if pipe not opened
  28.  
  29. // ------------- open pipe & get buffer
  30.  
  31. // initiate pipe
  32. if (fp = Open (pname, MODE_NEWFILE))
  33. { Write (fp, "\n", 1);
  34. Close (fp);
  35. }
  36.  
  37. if (!(fp = Open (pname, MODE_OLDFILE)))
  38. goto endprog;
  39.  
  40. if (!(inbuff = (char *)AllocVec (buffsize, MEMF_ANY)))
  41. goto endprog;
  42. bufflimit = buffsize - 100;
  43.  
  44. // ------------ all ok - store task address to pass to G4C
  45. // stored in bt->xt by gui.c
  46.  
  47. mess->task = &myself->pr_Task;
  48. ReplyMsg((struct Message *)mess); // #### CAUSES ENFORCER HIT - WHY??
  49. // null msg pointer so we know we sent the 1st one
  50. mess = NULL;
  51.  
  52. // ------------ initialise the message
  53.  
  54. gmsg.rm_Node.mn_Node.ln_Type = NT_MESSAGE;
  55. gmsg.rm_Node.mn_Length = sizeof (struct gcmsg);
  56. gmsg.rm_Node.mn_ReplyPort = pipeport;
  57. gmsg.dummy = (APTR)bt; // calling xPipe event (=0 to signal end)
  58. gmsg.data = inbuff; // this is where the data will go
  59. gmsg.rm_Action = MM_PIPE_DATA; // magic number
  60. gmsg.num = buffsize; // for changing buffer size
  61.  
  62. // ------------- clean pipe
  63.  
  64. while ((Read(fp, &g, 1)) > 0);
  65.  
  66. // ------------- read in lines & pass them to G4C
  67.  
  68. while (1) // do for ever
  69. {
  70. // ---------- wait
  71.  
  72. // the stuff in here will not be done if pipe is full
  73. while ((Read(fp, &g, 1)) < 1)
  74. { sig = SetSignal (0, 0);
  75. // ctrl-C from freefile(), ctrl-D from setgad OFF
  76. if ((sig & SIGBREAKF_CTRL_C) || (sig & SIGBREAKF_CTRL_D))
  77. goto endprog;
  78. Delay (10);
  79. }
  80.  
  81. inbuff[0] = g;
  82. c = 1;
  83.  
  84. // ---------- read in a line - length shorter than buffsize for safety
  85. while (((ret = Read (fp, &g, 1)) > 0) && (g != '\n') && (g != '\r') && (c<bufflimit))
  86. {
  87. // deal with tabs here - lvadd does not expand it
  88. if (g == '\t')
  89. { for (d=0; d < gd->tab; ++d) inbuff[c+d] = ' ';
  90. c += gd->tab;
  91. }
  92. // if ((g < 32) || (g > 126)) g = '.'; - no need to textify ?..
  93. else
  94. { inbuff[c] = g;
  95. ++c;
  96. }
  97. }
  98. inbuff[c] = 0;
  99.  
  100. if (ret == -1) // error in reading
  101. goto endprog;
  102.  
  103. // ---------- get & deal with signals
  104.  
  105. sig = SetSignal (0, 0);
  106. // signal from freefile() - die immediate (to print&die use ctrl-d)
  107. if (sig & SIGBREAKF_CTRL_C)
  108. goto endprog;
  109. // signal from setgad CLEAN - stop & flush pipe
  110. else if (sig & SIGBREAKF_CTRL_F)
  111. { while ((Read(fp, &g, 1)) > 0);
  112. SetSignal (0L, SIGBREAKF_CTRL_F); // reset signal
  113. goto skippipe;
  114. }
  115.  
  116. // sanity check- g4c+gui may have quit
  117. if (bt->gf->magic != MM_GFILE)
  118. goto endprog;
  119.  
  120. // ----------- send the message
  121.  
  122. gmsg.num = buffsize; // for buffer size change
  123. PutMsg (host, &gmsg.rm_Node); // #### CAUSES ENFORCER ERROR - WHY?????
  124.  
  125. // wait for reply
  126. WaitPort (pipeport);
  127. repmsg = (struct gcmsg *)GetMsg(pipeport);
  128. // the buffer we sent was exchanged with gd->membuff[4]
  129. inbuff = gmsg.data;
  130. buffsize = gmsg.num; // new buffer size
  131. bufflimit = buffsize - 100;
  132.  
  133. // they told us to quit - from gui.c main loop
  134. if (repmsg->dummy == NULL) // should normally be *bt
  135. goto endprog;
  136.  
  137. skippipe: ;
  138. }
  139.  
  140. // ---------------------- clean up & exit
  141. endprog :
  142.  
  143. // empty pipe & close the file if still open
  144. if (fp)
  145. { while ((Read(fp, &g, 1))>0);
  146. Close (fp);
  147. fp = NULL;
  148. }
  149.  
  150. // free buffer
  151. if (inbuff) FreeVec (inbuff);
  152.  
  153. // empty the port
  154. Forbid();
  155. if (mess) // if yes, its the 1st message
  156. ReplyMsg((struct Message *)mess);
  157. while (mess = (struct LaunchMessage *)GetMsg(pipeport))
  158. ReplyMsg((struct Message *)mess);
  159.  
  160. // end of process
  161. }

Compiling for OS4 (with (__USE_INLINE__) there were no crashes but the xPIPE event did no longer produce the expected output. When you tried to direct the lines put into the MyPipe from CLI with
>> More <PIPE:MyPipe
there seemed to be an output of empty lines, but repositioning the cursor in the shell those 'lines' disappeared.
After you quitted the program (without quitting Gui4Cli) the same shell command did show what had been written to the pipe.
(Quitting Gui4Cli without having emptied the pipe is not possible)

Using some kind of print statement in the source code produced output only before the line
// ---------- read in a line - length shorter than buffsize for safety

This output was directed not to the Gui4Cli console but to another output window.
As the goal of the function is to direct output to the latter there may be some interaction i don't understand whch is preventing this.
Since i came (today) to this insight, i removed all kind of print statements in the function.
To no avail.

I have followed advice using (buffered) FOpen instead of Open and still have the same problem.

I am out of ideas how to tackle this one.
Any help much appreciated (also on how maybe GDB could be used here)

Oh yes: at a certain moment playing with MyPipe as well from shell as from the program (you can CLEN (empty) the pipe, set it of or on, the pipe output appeared where it was expected.
I was unable to replicate that however.

hypex
hypex's picture
Offline
Last seen: 1 month 2 weeks ago
Joined: 2011-09-09 16:20
I know that PrintF() will

I know that PrintF() will crash if you don't pass it a format arguments table pointer even if your string has no formatting or arguments.

Log in or register to post comments