home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #26 / NN_1992_26.iso / spool / comp / sources / wanted / 4940 < prev    next >
Encoding:
Text File  |  1992-11-07  |  25.1 KB  |  679 lines

  1. Xref: sparky comp.sources.wanted:4940 comp.software-eng:4180 comp.sys.sun.apps:2393
  2. Newsgroups: comp.sources.wanted,comp.software-eng,comp.sys.sun.apps
  3. Path: sparky!uunet!nntp1.radiomail.net!fernwood!pure!hastings
  4. From: hastings@pure.com (Reed Hastings)
  5. Subject: Purify & Sentinel
  6. Message-ID: <1992Nov2.212558.28104@pure.com>
  7. Organization: Pure Software, Los Altos, CA
  8. Date: Mon, 2 Nov 1992 21:25:58 GMT
  9. Lines: 668
  10.  
  11.  
  12.  
  13. In several recent postings, the developers of Sentinel compared their
  14. product with standard malloc debug and Purify.
  15.  
  16. We realize that it is inappropriate for vendors to argue about their
  17. products on the net, and wish that Sentinel confined their postings to
  18. comp.newprod.  Given that Sentinel has posted, though, to a wide
  19. number of groups with a distorted product comparison we have been left
  20. with no choice but to respond.  Hopefully all further traffic will be
  21. from independent customers, and not from Sentinel or us.
  22.  
  23. In the following message, we clarify a number of points about Purify
  24. and indicate some critical memory errors that Purify detects that
  25. Sentinel can not.
  26.  
  27.  
  28. ******** Purify and Sentinel *********
  29.  
  30. Sentinel is a debugging version of malloc sold by Virtual
  31. Technologies.  Sentinel is based on the public domain dbmalloc
  32. package, with the improvement of commercial support and the ability to
  33. read symbol tables to print function names.  Standard malloc
  34. debuggers, which have been around for many years, print only the code
  35. addresses.
  36.  
  37. Sentinel operates by providing their own version of 29 selected libc
  38. functions, such as strcpy, in which they perform their memory error
  39. checks.  Sentinel's ONLY memory checking is through calls to these
  40. functions.  Every other function in your application runs unchecked.
  41.  
  42. Purify, in contrast, monitors and checks *every* memory access a
  43. program makes (such as those from statements like "int x = *y;";).  It
  44. detects memory errors just *before* they are about to happen, and
  45. stops the program with an error message at that point.
  46.  
  47. Purify's object code insertion is the key technology that allows
  48. Purify to check every memory access a program makes with very low
  49. overhead.  This includes all memory accesses from libc, all accesses
  50. from your application code, all memory accesses from system calls, and
  51. all memory accesses from third party libraries such as database
  52. libraries and Xt libraries.
  53.  
  54. In addition to checking every memory access, Purify's approach allows
  55. it to detect entire classes of serious errors that debugging mallocs
  56. such as Sentinel cannot detect.
  57.  
  58.  
  59. ********  Specific Functionality  *********
  60.  
  61. 1. Array bounds reads         Purify yes        Sentinel no
  62. 2. Array bounds writes         Purify yes        Sentinel partially
  63. 3. Free'd memory reads      Purify yes        Sentinel no
  64. 4. Free'd memory writes     Purify yes        Sentinel no
  65. 5. Uninitialized memory reads     Purify yes        Sentinel no
  66. 6. Memory leaks          Purify yes        Sentinel no
  67. 7. System call protection     Purify yes        Sentinel no
  68. 8. Shared Library support     Purify yes        Sentinel some
  69. 8. Stack corruption         Purify no        Sentinel partially
  70. 9. User memory manager support    Purify yes        Sentinel no
  71. 10.Watchpoints             Purify yes        Sentinel partially
  72.  
  73. ********  Array Bounds Reads *********
  74.  
  75. Unknowingly reading past the end of an array is a common cause of 
  76. program crashes.  
  77.  
  78. Here is an example:
  79.  
  80.     main() {
  81.      char* x = malloc(100);
  82.      get_sorted_data(x); /* fill x with 100 small integers sorted */
  83.      if (x[100] == MAX) { /* Is the biggest one too big? */
  84.         abort();
  85.      }
  86.     }  
  87.  
  88.  
  89. At the customer site the program crashes once every three days or so,
  90. because the random value at x[100] happens to be equal to the 
  91. constant MAX.
  92.  
  93. Running this example with Sentinel reports no errors of any kind.
  94.  
  95. Running this example just once though Purify, it reports:
  96.  
  97.     ----  Purify'd a.out  ----
  98.     Purify (abr): array bounds read violation:
  99.       * This is occurring while in:
  100.         main (line 5 in foo.c)
  101.         start  (0x2064 in crt0.o)
  102.       * Reading 1 byte from 0x45afc in the heap.
  103.         1 byte past end of a malloc'd block at 0x45a98 of 100 bytes.
  104.       * This block was allocated by malloc called from:
  105.         main (line 3 in foo.c)
  106.         start  (0x2064 in crt0.o)
  107.  
  108.  
  109. The example used above has
  110.  
  111.     if (x[100] == MAX) { 
  112.       abort();
  113.     }
  114.  
  115. A more realistic example, and much tougher to debug, is
  116.  
  117.     if (x[100] == MAX) { 
  118.       do_something_very_subtly_wrong()
  119.     }
  120.  
  121. Again, Purify detects this error immediately.  Moreover, Purify
  122. stops the program just *before* the error occurred, allowing
  123. you to look around with a debugger.
  124.  
  125.  
  126.  
  127. ********  Array Bounds Writes  *********
  128.  
  129. Sentinel detects some array bounds write violations by putting the 
  130. bits (11110111) in the byte immediately after the array.  At the 
  131. end of the program Sentinel searches every memory block to see 
  132. if any of the 11110111 patterns have changed.  
  133.  
  134. Here's an example:    
  135.  
  136.     char* x;
  137.  
  138.     setup()
  139.     {
  140.      x = malloc(10);
  141.     }
  142.  
  143.     do_work()
  144.     {
  145.      x[10] = 0;  /* buggy, line 14 */
  146.     }
  147.   
  148.     main()
  149.     {
  150.      setup();
  151.      do_work();
  152.     }
  153.  
  154. Running this program with Sentinel, it reports:
  155.  
  156.     SENTINEL: Warning [23]: The program has modified the boundary area 
  157.     following the 10 byte data area that starts at location 0x20F80.
  158.  
  159.     Reading symbol table...Sun format.........Done
  160.  
  161.     This problem was detected at the following location:
  162.  
  163.         SeLeakCheckpoint()+0xA8 [leak.o]
  164.         SeLeakShow()+0x4 [leak.o]
  165.         _m_LeakReport()+0x24 [leak.o]
  166.         exit()+0xB0 [exit.o]
  167.     Segmentation fault
  168.  
  169.  
  170. Even in this simple example Sentinel can't identify that the error
  171. occured in do_work.  Because Sentinel does not have object code
  172. insertion, it cannot detect errors as they occur.  In this example,
  173. Sentinel itself gets a SEGV and dumps core trying to print its
  174. diagnostic output (this is a bug in Sentinel v1.3.1 that will likely
  175. get fixed.)
  176.  
  177. Running this simple example with Purify, it reports:
  178.  
  179.     ----  Purify'd a.out  ----
  180.     Purify (abw): array bounds write violation:
  181.       * This is occurring while in:
  182.         do_work (line 14 in example.c)
  183.         main (line 20 in example.c)
  184.         start  (0x2064 in crt0.o)
  185.       * Writing 1 byte to 0x45a92 in the heap.
  186.         1 byte past end of a malloc'd block at 0x45a88 of 10 bytes.
  187.       * This block was allocated by malloc called from:
  188.         setup  (line 9 in example.c)
  189.         main(line 19 in example.c)
  190.         start  (0x2064 in crt0.o)
  191.  
  192. Note that Purify correctly identified do_work, line 14, as the 
  193. source of the error. Again, Purify detects this error immediately.  
  194. Moreover, Purify stops the program just *before* the error occurred, 
  195. allowing you to look around with a debugger.
  196.  
  197. ********  Free'd memory reads  *********
  198.  
  199. As memory ownership protocols get more complicated, it becomes harder
  200. and harder to be sure that memory is not being freed too early.
  201. Using Purify, if you access memory *after* it has been freed you
  202. get an exact immediate diagnostic.
  203.  
  204. Here is an example:
  205.  
  206.     main(){
  207.      struct flags { int present; };
  208.      struct flags* flags = malloc(sizeof(struct flags));
  209.      flags->present = TRUE;
  210.      /* ... */    
  211.      if (flags->present) {
  212.        printf("present\n");
  213.      }
  214.      free(flags);
  215.      /* ... */    
  216.      if (!flags->present) { /* line 11 */
  217.        abort(); /* or something subtle */
  218.      }
  219.     }    
  220.  
  221. The subtle part of this example is that the code will run
  222. correctly for awhile since the memory flags *probably* has not been 
  223. re-allocated and changed.
  224.  
  225. Running this example with Sentinel reports no errors of any kind.
  226.  
  227. The first time Purify is run on this code you get an exact diagnostic,
  228. telling you where the memory was freed, where it was allocated, and 
  229. where the free'd memory is being used (line 11).
  230.  
  231.     ---- Purify'd a.out ----
  232.     Purify (fmr): free memory read violation:
  233.      * This is occurring while in:
  234.         main (line 11 of fmr.c)
  235.         start(0x2064 of crt0.o)
  236.      * Reading 4 bytes from 0x39810 in the heap.
  237.        at beginning of a freed block of 4 bytes.
  238.      * This block was allocated by malloc called from:
  239.         main (line 3 of fmr.c)
  240.         start(0x2064 of crt0.o)
  241.      * This block was freed 1 calls to free ago, from:
  242.         main (line 9 of fmr.c)
  243.         start(0x2064 of crt0.o)
  244.  
  245.  
  246.  
  247. ********  Free'd memory writes  *********
  248.     
  249. Free'd memory writes are especially dangerous because if that memory
  250. gets reallocated then random memory from some other part of the
  251. program will get corrupted.  
  252.  
  253. Using Purify, if you write memory after it has been freed you
  254. get an exact immediate diagnostic just *before* it happens.
  255.  
  256. Here is an example:
  257.  
  258.     main(){
  259.      struct flags { int present; };
  260.      struct flags* flags = malloc(sizeof(struct flags));
  261.      flags->present = TRUE;
  262.      /* ... */    
  263.      if (flags->present) {
  264.       printf("present\n");
  265.      }
  266.      free(flags);
  267.      /* ... */    
  268.      flags->present = FALSE; /* I wonder whose memory we are changing */
  269.     }    
  270.  
  271. Running this example with Sentinel reports no errors of any kind.
  272.  
  273. Running this example just once though Purify, it reports:
  274.  
  275.     ----Purify'd a.out ----
  276.     Purify (fmw): free memory write violation:
  277.      * This is occurring while in:
  278.         main (line 11 of fmw.c)
  279.         start(0x2064 of crt0.o)
  280.      * Reading 4 bytes from 0x39810 in the heap.
  281.        at beginning of a freed block of 4 bytes.
  282.     * This block was allocated by malloc called from:
  283.         main (line 3 of fmw.c)
  284.         start(0x2064 of crt0.o)
  285.     * This block was freed 1 calls to free ago, from:
  286.         main (line 9 of fmw.c)
  287.         start(0x2064 of crt0.o)
  288.  
  289. ********  Uninitialized memory reads  *********
  290.  
  291. Uninitialized memory reads are another common case of mysterious
  292. and non-reproducible crashes.  Reading uninitialized memory returns 
  293. a random value, and the results are unpredictable.   
  294.  
  295. Here is an example:
  296.  
  297.  
  298.     main(){
  299.      int flag, i = 0;
  300.      /* ... */
  301.      while(i++ < 10 && flag) {
  302.          update_db();
  303.      }
  304.     }
  305.  
  306. Running this example with Sentinel reports no errors of any kind.
  307.  
  308. Running this example though Purify, it reports:
  309.  
  310.  
  311.     ----Purify'd umr.pure----
  312.     Purify (umr): uninitialized memory read violation:
  313.      * This is occurring while in:
  314.         main(pc = 0x1ab44 on line 4 of umr.c)
  315.         start(pc =0x2064 of crt0.o)
  316.      * Reading 4 bytes from 0xf7fff9dc on the stack.
  317.     This is local variable "flag" in function main.
  318.  
  319. ********  Memory Leaks   *********
  320.  
  321. Memory leaks are allocated memory that should have been freed but were
  322. not.  This is not the same as the memory allocated but not yet freed.
  323. Many programs and libraries allocate memory that is never meant to be
  324. freed.  These might be symbol tables, contents of initialization
  325. files, etc.  This memory is always in use.
  326.  
  327. Sentinel does not report memory leaks, it reports memory in use,
  328. memory that has been allocated but not freed.  Typically some small
  329. fraction of this memory is leaks, but Sentinel cannot and does not
  330. tell you which memory is still actively in use, and which memory is
  331. truly leaked.
  332.  
  333. Purify can show you the memory in use (with purify_allallocated()), or
  334. the memory leaks (with purify_newleaks()).  It can find the difference
  335. between these two groups by searching through all of memory tracing
  336. pointers.  Sentinel does not do this.
  337.  
  338. Being able to tell the difference between leaks and memory in use is
  339. critical, and only Purify is able to do it.  In Xt applications we
  340. have studied there are an average of five thousand individual memory
  341. chunks active, even after closing windows.  These hold things like the
  342. resource database.  Sentinel (or Purify with purify_allallocated())
  343. prints for you a list of all 5 thousand memory chunks.  It is up to
  344. you the developer to manually sort through this mess to find or guess
  345. what the 20 or so leaks are.  Purify's purify_allleaks() quickly and
  346. precisely identifies those 20 leaks, and does not report falsely on
  347. the 4980 chunks that are still in use and are not leaks as Sentinel
  348. does.
  349.  
  350. Here is a short example:
  351.  
  352.     int* table = 0;
  353.  
  354.         Malloc(x) {
  355.         char* val = malloc(x);
  356.         assert(val);
  357.         return val;
  358.     }
  359.  
  360.     example() {
  361.        static int first = TRUE;
  362.        char* local;
  363.        if (first) { /* first time, build tables */
  364.         int i; 
  365.         first = FALSE;
  366.         table = Malloc(400);
  367.         for(i = 1; i < 100; i++) 
  368.             table[i] = Malloc(i);
  369.        }
  370.        local = Malloc(43); /* oops, leak here */
  371.     }
  372.  
  373.  
  374. In this small example table is a long-term data structure that is
  375. built when needed.
  376.  
  377. Running this through Sentinel you get the following display, and you get
  378. to sort through this to attempt to find the one leak.
  379.     
  380.  
  381.     *************** SENTINEL: LIST OF MEMORY LEAKS**************
  382.  
  383.     POINTER                  LOCATION           ALLOC         DATA  
  384.     TO DATA               WHERE ALLOCATED       FUNCT        LENGTH 
  385.     -------- ------------------------------- -------------- --------
  386.     0x01E8E0 leak.c:6 Malloc()                  malloc(93)           90  
  387.     0x01E988 leak.c:6 Malloc()                  malloc(92)           89  
  388.     0x01EA20 leak.c:6 Malloc()                  malloc(91)           88  
  389.     0x01EAB8 leak.c:6 Malloc()                  malloc(90)           87  
  390.     0x01EB48 leak.c:6 Malloc()                  malloc(89)           86  
  391.     0x01EBD8 leak.c:6 Malloc()                  malloc(88)           85  
  392.     0x01EC68 leak.c:6 Malloc()                  malloc(87)           84  
  393.     0x01ECF8 leak.c:6 Malloc()                  malloc(86)           83  
  394.     0x01ED88 leak.c:6 Malloc()                  malloc(85)           82  
  395.     0x01EE18 leak.c:6 Malloc()                  malloc(84)           81  
  396.     0x01EEA8 leak.c:6 Malloc()                  malloc(83)           80  
  397.     0x01EF38 leak.c:6 Malloc()                  malloc(82)           79  
  398.     0x01EFC0 leak.c:6 Malloc()                  malloc(81)           78  
  399.     0x01F048 leak.c:6 Malloc()                  malloc(80)           77  
  400.     0x01F0D0 leak.c:6 Malloc()                  malloc(79)           76  
  401.     0x01F158 leak.c:6 Malloc()                  malloc(78)           75  
  402.     0x01F1E0 leak.c:6 Malloc()                  malloc(77)           74  
  403.     0x01F268 leak.c:6 Malloc()                  malloc(76)           73  
  404.     0x01F2F0 leak.c:6 Malloc()                  malloc(75)           72  
  405.     0x01F378 leak.c:6 Malloc()                  malloc(74)           71  
  406.     0x01F3F8 leak.c:6 Malloc()                  malloc(73)           70  
  407.     0x01F478 leak.c:6 Malloc()                  malloc(72)           69  
  408.     0x01F4F8 leak.c:6 Malloc()                  malloc(71)           68  
  409.     0x01F578 leak.c:6 Malloc()                  malloc(70)           67  
  410.     0x01F5F8 leak.c:6 Malloc()                  malloc(69)           66  
  411.     0x01F678 leak.c:6 Malloc()                  malloc(68)           65  
  412.     0x01F6F8 leak.c:6 Malloc()                  malloc(67)           64  
  413.     0x01F778 leak.c:6 Malloc()                  malloc(66)           63  
  414.     0x01F7F0 leak.c:6 Malloc()                  malloc(65)           62  
  415.     0x01F868 leak.c:6 Malloc()                  malloc(64)           61  
  416.     0x01F8E0 leak.c:6 Malloc()                  malloc(63)           60  
  417.     0x01F958 leak.c:6 Malloc()                  malloc(62)           59  
  418.     0x01F9D0 leak.c:6 Malloc()                  malloc(61)           58  
  419.     0x01FA48 leak.c:6 Malloc()                  malloc(60)           57  
  420.     0x01FAC0 leak.c:6 Malloc()                  malloc(59)           56  
  421.     0x01FB38 leak.c:6 Malloc()                  malloc(58)           55  
  422.     0x01FBA8 leak.c:6 Malloc()                  malloc(57)           54  
  423.     0x01FC18 leak.c:6 Malloc()                  malloc(56)           53  
  424.     0x01FC88 leak.c:6 Malloc()                  malloc(55)           52  
  425.     0x01FCF8 leak.c:6 Malloc()                  malloc(54)           51  
  426.     0x01FD68 leak.c:6 Malloc()                  malloc(53)           50  
  427.     0x01FDD8 leak.c:6 Malloc()                  malloc(52)           49  
  428.     0x01FE48 leak.c:6 Malloc()                  malloc(51)           48  
  429.     0x01FEB8 leak.c:6 Malloc()                  malloc(50)           47  
  430.     0x01FF20 leak.c:6 Malloc()                  malloc(49)           46  
  431.     0x01FF88 leak.c:6 Malloc()                  malloc(48)           45  
  432.     0x01FFF0 leak.c:6 Malloc()                  malloc(47)           44  
  433.     0x020058 leak.c:6 Malloc()                  malloc(46)           43  
  434.     0x0200C0 leak.c:6 Malloc()                  malloc(45)           42  
  435.     0x020128 leak.c:6 Malloc()                  malloc(44)           41  
  436.     0x020190 leak.c:6 Malloc()                  malloc(43)           40  
  437.     0x0201F8 leak.c:6 Malloc()                  malloc(42)           39  
  438.     0x020258 leak.c:6 Malloc()                  malloc(41)           38  
  439.     0x0202B8 leak.c:6 Malloc()                  malloc(40)           37  
  440.     0x020318 leak.c:6 Malloc()                  malloc(39)           36  
  441.     0x020378 leak.c:6 Malloc()                  malloc(38)           35  
  442.     0x0203D8 leak.c:6 Malloc()                  malloc(37)           34  
  443.     0x020438 leak.c:6 Malloc()                  malloc(36)           33  
  444.     0x020498 leak.c:6 Malloc()                  malloc(35)           32  
  445.     0x0204F8 leak.c:6 Malloc()                  malloc(34)           31  
  446.     0x020550 leak.c:6 Malloc()                  malloc(33)           30  
  447.     0x0205A8 leak.c:6 Malloc()                  malloc(32)           29  
  448.     0x020600 leak.c:6 Malloc()                  malloc(31)           28  
  449.     0x020658 leak.c:6 Malloc()                  malloc(30)           27  
  450.     0x0206B0 leak.c:6 Malloc()                  malloc(29)           26  
  451.     0x020708 leak.c:6 Malloc()                  malloc(28)           25  
  452.     0x020760 leak.c:6 Malloc()                  malloc(27)           24  
  453.     0x0207B8 leak.c:6 Malloc()                  malloc(26)           23  
  454.     0x020808 leak.c:6 Malloc()                  malloc(25)           22  
  455.     0x020858 leak.c:6 Malloc()                  malloc(24)           21  
  456.     0x0208A8 leak.c:6 Malloc()                  malloc(23)           20  
  457.     0x0208F8 leak.c:6 Malloc()                  malloc(22)           19  
  458.     0x020948 leak.c:6 Malloc()                  malloc(21)           18  
  459.     0x020998 leak.c:6 Malloc()                  malloc(20)           17  
  460.     0x0209E8 leak.c:6 Malloc()                  malloc(19)           16  
  461.     0x020A38 leak.c:6 Malloc()                  malloc(18)           15  
  462.     0x020A80 leak.c:6 Malloc()                  malloc(17)           14  
  463.     0x020AC8 leak.c:6 Malloc()                  malloc(16)           13  
  464.     0x020B10 leak.c:6 Malloc()                  malloc(15)           12  
  465.     0x020B58 leak.c:6 Malloc()                  malloc(14)           11  
  466.     0x020BA0 leak.c:6 Malloc()                  malloc(13)           10  
  467.     0x020BE8 leak.c:6 Malloc()                  malloc(12)            9  
  468.     0x020C30 leak.c:6 Malloc()                  malloc(11)            8  
  469.     0x020C78 leak.c:6 Malloc()                  malloc(10)            7  
  470.     0x020CB8 leak.c:6 Malloc()                  malloc(9)             6  
  471.     0x020CF8 leak.c:6 Malloc()                  malloc(8)             5  
  472.     0x020D38 leak.c:6 Malloc()                  malloc(7)             4  
  473.     0x020D78 leak.c:6 Malloc()                  malloc(6)             3  
  474.     0x020DB8 leak.c:6 Malloc()                  malloc(5)             2  
  475.     0x020DF8 leak.c:6 Malloc()                  malloc(4)             1  
  476.     0x020E38 leak.c:6 Malloc()                  malloc(1)           400  
  477.     0x0274A0 leak.c:6 Malloc()                  malloc(103)          43  
  478.     0x027508 leak.c:6 Malloc()                  malloc(102)          99  
  479.     0x0275A8 leak.c:6 Malloc()                  malloc(101)          98  
  480.     0x027648 leak.c:6 Malloc()                  malloc(100)          97  
  481.     0x0276E8 leak.c:6 Malloc()                  malloc(99)           96  
  482.     0x027788 leak.c:6 Malloc()                  malloc(98)           95  
  483.     0x027820 leak.c:6 Malloc()                  malloc(97)           94  
  484.     0x0278B8 leak.c:6 Malloc()                  malloc(96)           93  
  485.     0x027950 leak.c:6 Malloc()                  malloc(95)           92  
  486.     0x0279E8 leak.c:6 Malloc()                  malloc(94)           91  
  487.  
  488. Running this through Purify you get a single memory leak report and
  489. can fix the problem confident that you're not introducing another
  490. problem by freeing memory still in use.
  491.  
  492.     Purify: Searching for all memory leaks...
  493.     1 memory leak found.
  494.  
  495.     Report (mlk): 43 bytes at 0x3a570 lost, malloc called from:
  496.         example      (line 13 in ./leak.c)
  497.         main         (line 17 in ./leak.c)
  498.         start        (crt0.o)
  499.  
  500.  
  501. ******* System Call Protection ********
  502.  
  503.  
  504. Purify checks the arguments to the system calls which read or write memory.
  505. Here is an example:
  506.  
  507.     example() {
  508.      struct stat* statp = malloc(sizeof(statp));
  509.      stat(".cshrc", statp);
  510.     }
  511.  
  512. Running this example with Sentinel reports no errors of any kind.
  513.  
  514. Running this example though Purify, it reports:
  515.  
  516.     Purify (abw): array bounds write violation:
  517.     * This is occurring while in:
  518.         stat(syscalls.o)
  519.         main (line 19 in example.c)
  520.         start(0x2064 in crt0.o)
  521.     * Writing 64 bytes to 0x45a88 in the heap.
  522.       at beginning of a malloc'd block of 4 bytes.
  523.     * This block was allocated by malloc called from:
  524.         main (line 18 in example.c)
  525.         start(pc =0x2064 in crt0.o)
  526.  
  527.  
  528. A careful look at the malloc call reveals that sizeof(statp) should
  529. have been sizeof(struct stat).
  530.  
  531.  
  532.  
  533. ******* Shared Library Support *********
  534.  
  535. Sentinel does support programatic use of shared libraries, such as using
  536. dlopen.  
  537.  
  538. Consider the following example code placed  in a shared library and opened with
  539. dlopen:
  540.  
  541.     printsomething()
  542.     {
  543.      doprint();
  544.     }
  545.  
  546.     doprint()
  547.     {
  548.      char* y = malloc(5);
  549.      strcpy(y, "Too long"); /* simple strcpy error */
  550.     }
  551.  
  552. Running this example with a simple main calling printsomething, Sentinel reports:
  553.  
  554.     SENTINEL: Warning [14]: An attempt was made to access data beyond the 
  555.     end of the allocated data section.The program attempted to write 9 
  556.     bytes to location 0x1ED78.That address is at offset 0 in the 5
  557.     byte data area that starts at location 0x1ED78 (there is only
  558.     room to write 5 bytes).
  559.  
  560.     This problem was detected at the following location:
  561.  
  562.         strcpy()+0x14C [string.o]
  563.         etext()+0xF76B8FE8 [iob.o]
  564.         etext()+0xF76B8FB0 [iob.o]
  565.         main() [hello.c:31]
  566.  
  567.     This problem is *probably* associated with a 5 byte data area
  568.     allocated on the 9th call to malloc() which returned 0x1ED78.
  569.     The context of the call to malloc() was as follows:
  570.  
  571.         malloc()+0x20 [malloc.o]
  572.         etext()+0xF76B8FD0 [iob.o]
  573.         etext()+0xF76B8FB0 [iob.o]
  574.         main() [hello.c:31]
  575.  
  576. Note that Sentinel prints shared library function names as "etext()+0xF76B8FE8".
  577.  
  578. Running the same example with Purify, it reports:
  579.  
  580.     ----Purify'd prog.pure ----
  581.     Purify (abw): array bounds write violation:
  582.     * This is occurring while in:
  583.          strcpy (strings.o)
  584.          doprint (line 12 of dlopen.c)
  585.          printsomething (line 6 of dlopen.c)
  586.          main (line 31 of hello.c)
  587.          start(crt0.o)
  588.     * Writing 9 bytes to 0x3bea0 in the heap.
  589.       at beginning of a malloc'd block of 5 bytes.
  590.     * This block was allocated by malloc called from:
  591.         doprint (line 10 of dlopen.c)
  592.         printsomething (line 6 of dlopen.c)
  593.         main (line 31 of hello.c)
  594.         start(crt0.o)
  595.  
  596.  
  597. ******* Stack Corruption *******
  598.  
  599. Sentinel can be configured to walk up the stack every time it enters
  600. one of its 29 checking functions.  It can detect cases of stack
  601. corruption, if the program doesn't crash between the time of the
  602. corruption and time of the call to the check function.
  603.  
  604. Purify cannot directly help with stack corruption problems.
  605.  
  606. ******* User Memory Manager support ********
  607.  
  608.  
  609. Sentinel does not support user-defined memory managers.
  610.  
  611. Purify supports user memory managers layered on top of malloc with a
  612. simple extension language.
  613.  
  614. ******* Watchpoints ********
  615.  
  616. Sentinel's "watchpoints" check whether watched memory has changed
  617. whenever one of its libc function variants are entered.  Sentinel
  618. tells you "it changed sometime in the past".
  619.  
  620. Purify signals a message just before the exact instruction executes
  621. that is about to change the watched memory.  Purify tells you the
  622. current value and the value it is about to change to.  Purify allows
  623. the program to be stopped there, permitting you to look around with a
  624. debugger.
  625.  
  626. ********   Pricing   *********
  627.  
  628. Sentinel is CPU-licensed, and costs $400 per cpu, which translates
  629. to $400 per user.  VTI is willing to compromise signficantly on
  630. these prices.
  631.  
  632. Purify is floating network licensed.  Our customers buy and use
  633. approximately one license per 3 to 4 developers.  Each license costs
  634. between $1950 and $2750 depending on volume.  This results in per user
  635. costs of $500 to $700.
  636.  
  637.  
  638.  
  639. ********   Summary   *********
  640.  
  641. Judy Grass from Bell Labs gets to the heart of the issue in 
  642. IEEE Software, Aug 92, P125:
  643.  
  644.        "An entire month of working with a debugging 
  645.         malloc did not tell me as much about the 
  646.     program's problems as a single day spent 
  647.     with Purify"
  648.  
  649. Sentinel is a good implementation of an relatively ineffective approach,
  650. It can be useful in situations in which there's no other choice, such 
  651. as on platforms on which products like Purify or Centerline are not
  652. yet available.
  653.  
  654. Unfortunately, VTI marketing is misleading, and its implications of
  655. matching Purify's functionality are unsubstantiated.  VTI claimes that
  656. Sentinel offers most of the functionality of Purify for 20% of the
  657. price.  In fact it offers a small fraction of the functionality for
  658. half of the price on a typical per-user basis.
  659.  
  660. Purify's creators have previously written many debugging mallocs, as
  661. have many other developers.  We grew tired of debugging mallocs'
  662. limited abilities and this is what drove us to do the hard work of
  663. object code insertion.  It's the only way to get comprehensive
  664. checking.  Purify will help you get from prototype to product faster
  665. than any other run-time error detection technology.
  666.  
  667. Purify continues to be improved.  We have always done our best to be
  668. completely honest about what it did and didn't do.  We took pains in
  669. our manual to describe specifically what kind of errors Purify can not
  670. find.  We don't abuse the net by advertising our products there,
  671. instead preferring to let our customers do the talking.  We thank the
  672. thousands of Purify customers out there for helping us with 
  673. the above examples.
  674.  
  675. -Reed Hastings, President, Pure Software.
  676.  hastings@pure.com
  677.  
  678.  
  679.