Index: src/diff.c
==================================================================
--- src/diff.c
+++ src/diff.c
@@ -619,10 +619,24 @@
 /**************************************************************************
 ** The basic difference engine is above.  What follows is the annotation
 ** engine.  Both are in the same file since they share many components.
 */
 
+/*
+** Linked list of strings, labels used in the annotator code.
+** The elements of the list and the pointed string (str)
+** will be freed once they become totally unreferenced
+** (nref == 0).
+*/
+struct Label
+{
+    struct Label *prev;   /* previous element */
+    struct Label *next;   /* next element */
+    char *str;            /* The label string */
+    int nref;             /* Number of references to the string */
+};
+
 /*
 ** The status of an annotation operation is recorded by an instance
 ** of the following structure.
 */
 typedef struct Annotator Annotator;
@@ -630,18 +644,19 @@
   DContext c;       /* The diff-engine context */
   struct AnnLine {  /* Lines of the original files... */
     const char *z;       /* The text of the line */
     short int n;         /* Number of bytes (omitting trailing space and \n) */
     short int iLevel;    /* Level at which tag was set */
-    const char *zSrc;    /* Tag showing origin of this line */
+    struct Label *zSrc;    /* Tag showing origin of this line */
   } *aOrig;
   int nOrig;        /* Number of elements in aOrig[] */
   int nNoSrc;       /* Number of entries where aOrig[].zSrc==NULL */
   int iLevel;       /* Current level */
   int nVers;        /* Number of versions analyzed */
-  char **azVers;    /* Names of versions analyzed */
+  struct Label **azVers;    /* Names of versions analyzed */
   Blob toAnnotate;
+  struct Label *firstLabel;
 };
 
 /*
 ** Initialize the annotation process by specifying the file that is
 ** to be annotated.  The annotator takes control of the input Blob and
@@ -670,11 +685,11 @@
 ** being annotated.  Do another step of the annotation.  Return true
 ** if additional annotation is required.  zPName is the tag to insert
 ** on each line of the file being annotated that was contributed by
 ** pParent.  Memory to hold zPName is leaked.
 */
-static int annotation_step(Annotator *p, Blob *pParent, char *zPName){
+static int annotation_step(Annotator *p, Blob *pParent, struct Label *zPName){
   int i, j;
   int lnTo;
   int iPrevLevel;
   int iThisLevel;
 
@@ -698,13 +713,22 @@
   iThisLevel = p->iLevel;
   for(i=lnTo=0; i<p->c.nEdit; i+=3){
     struct AnnLine *x = &p->aOrig[lnTo];
     for(j=0; j<p->c.aEdit[i]; j++, lnTo++, x++){
       if( x->zSrc==0 || x->iLevel==iPrevLevel ){
-         /* TODO: handle zPName so we can free labels
-          * if they get totally unreferenced in the Annotator */
+         if (x->zSrc!=0)
+         {
+           if(--x->zSrc->nref == 0)
+           {
+               free(x->zSrc->str);
+               x->zSrc->prev->next = x->zSrc->next;
+               x->zSrc->next->prev = x->zSrc->prev;
+               free(x->zSrc);
+           }
+         }
          x->zSrc = zPName;
+         ++zPName->nref;
          x->iLevel = iThisLevel;
       }
     }
     lnTo += p->c.aEdit[i+2];
   }
@@ -739,20 +763,36 @@
   content_get(name_to_rid(g.argv[2]), &x.toAnnotate);
   if( annotation_start(&x) ){
     fossil_fatal("binary file");
   }
   for(i=3; i<g.argc; i++){
+    struct Label *l;
     blob_zero(&b);
     content_get(name_to_rid(g.argv[i]), &b);
-    if( annotation_step(&x, &b, g.argv[i-1]) ){
+    l = fossil_malloc(sizeof(*l));
+    l->str = g.argv[i-1];
+    l->nref = 0;
+    l->next = x.firstLabel;
+    if (x.firstLabel)
+      x.firstLabel->prev = l;
+    x.firstLabel = l;
+    if( annotation_step(&x, &b, l) ){
       fossil_fatal("binary file");
     }
   }
   for(i=0; i<x.nOrig; i++){
-    const char *zSrc = x.aOrig[i].zSrc;
+    const char *zSrc = x.aOrig[i].zSrc->str;
     if( zSrc==0 ) zSrc = g.argv[g.argc-1];
     fossil_print("%10s: %.*s\n", zSrc, x.aOrig[i].n, x.aOrig[i].z);
+  }
+  while(x.firstLabel) {
+    struct Label *l;
+    l = x.firstLabel->next;
+    assert(x.firstLabel->nref > 0);
+    free(x.firstLabel->str);
+    free(x.firstLabel);
+    x.firstLabel = l;
   }
 }
 
 /* Annotation flags */
 #define ANN_FILE_VERS  0x001  /* Show file version rather than commit version */
@@ -770,11 +810,10 @@
   int iLimit,          /* Limit the number of levels if greater than zero */
   int annFlags         /* Flags to alter the annotation */
 ){
   Blob step = empty_blob;           /* Text of previous revision */
   int rid;             /* Artifact ID of the file being annotated */
-  char *zLabel;        /* Label to apply to a line */
   Stmt q;              /* Query returning all ancestor versions */
 
   /* Initialize the annotation */
   rid = db_int(0, "SELECT fid FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid);
   if( rid==0 ){
@@ -808,23 +847,31 @@
   while( db_step(&q)==SQLITE_ROW ){
     int pid = db_column_int(&q, 0);
     const char *zUuid = db_column_text(&q, 1);
     const char *zDate = db_column_text(&q, 2);
     const char *zUser = db_column_text(&q, 3);
+    struct Label *l = fossil_malloc(sizeof(*l));
+    l->nref = 0;
+    l->next = p->firstLabel;
+    if (p->firstLabel)
+      p->firstLabel->prev = l;
     if( webLabel ){
-      zLabel = mprintf(
+      l->str = mprintf(
           "<a href='%s/info/%s' target='infowindow'>%.10s</a> %s %9.9s", 
           g.zTop, zUuid, zUuid, zDate, zUser
       );
     }else{
-      zLabel = mprintf("%.10s %s %9.9s", zUuid, zDate, zUser);
+      l->str = mprintf("%.10s %s %9.9s", zUuid, zDate, zUser);
     }
+    p->firstLabel = l;
     p->nVers++;
     p->azVers = fossil_realloc(p->azVers, p->nVers*sizeof(p->azVers[0]) );
-    p->azVers[p->nVers-1] = zLabel;
+    p->azVers[p->nVers-1] = l;
     content_get(pid, &step);
-    annotation_step(p, &step, zLabel);
+    annotation_step(p, &step, l);
+    if (l->nref == 0)
+      free(l->str);
     blob_reset(&step);
   }
   db_finalize(&q);
   free(p->c.aTo);
 }
@@ -860,20 +907,20 @@
   if( P("log") ){
     int i;
     @ <h2>Versions analyzed:</h2>
     @ <ol>
     for(i=0; i<ann.nVers; i++){
-      @ <li><tt>%s(ann.azVers[i])</tt></li>
+      @ <li><tt>%s(ann.azVers[i]->str)</tt></li>
     }
     @ </ol>
     @ <hr>
     @ <h2>Annotation:</h2>
   }
   @ <pre>
   for(i=0; i<ann.nOrig; i++){
     ((char*)ann.aOrig[i].z)[ann.aOrig[i].n] = 0;
-    @ %s(ann.aOrig[i].zSrc): %h(ann.aOrig[i].z)
+    @ %s(ann.aOrig[i].zSrc->str): %h(ann.aOrig[i].z)
   }
   @ </pre>
   style_footer();
 }
 
@@ -930,17 +977,25 @@
   }
   if( fileVers ) annFlags |= ANN_FILE_VERS;
   annotate_file(&ann, fnid, mid, 0, iLimit, annFlags);
   if( showLog ){
     for(i=0; i<ann.nVers; i++){
-      printf("version %3d: %s\n", i+1, ann.azVers[i]);
+      printf("version %3d: %s\n", i+1, ann.azVers[i]->str);
     }
     printf("---------------------------------------------------\n");
   }
   for(i=0; i<ann.nOrig; i++){
     fossil_print("%s: %.*s\n", 
-                 ann.aOrig[i].zSrc, ann.aOrig[i].n, ann.aOrig[i].z);
+                 ann.aOrig[i].zSrc->str, ann.aOrig[i].n, ann.aOrig[i].z);
   }
   free(ann.azVers);
   free(ann.aOrig);
   blob_reset(&ann.toAnnotate);
+  while(ann.firstLabel) {
+    struct Label *l;
+    l = ann.firstLabel->next;
+    assert(ann.firstLabel->nref > 0);
+    free(ann.firstLabel->str);
+    free(ann.firstLabel);
+    ann.firstLabel = l;
+  }
 }