Fixed race condition
authorRobert Pengelly <robertapengelly@hotmail.com>
Mon, 1 Jun 2026 06:46:12 +0000 (07:46 +0100)
committerRobert Pengelly <robertapengelly@hotmail.com>
Mon, 1 Jun 2026 06:46:12 +0000 (07:46 +0100)
hashtab.c
hashtab.h
lib.c

index 3f26b37a80f29156170df137a906960b91d3a99c..78b3d6cc49b64ff0b9c30b86f5b5f0b27ae0641a 100755 (executable)
--- a/hashtab.c
+++ b/hashtab.c
@@ -204,14 +204,19 @@ int hashtab_put (struct hashtab *table, struct hashtab_name *key, void *value) {
 void hashtab_remove (struct hashtab *table, struct hashtab_name *key) {
 
     struct hashtab_entry *entry;
-    
-    if ((entry = find_entry (table->entries, table->capacity, key)) != NULL) {
-    
-        entry->key = 0;
-        entry->value = 0;
-        
-        --table->count;
-    
+
+    if (!table || table->count == 0) {
+        return;
     }
 
+    entry = find_entry (table->entries, table->capacity, key);
+
+    if (!entry->key) {
+        return;
+    }
+
+    entry->value = HASHTAB_TOMBSTONE;
+    entry->key = 0;
+
+    --table->count;
 }
index 5ab0492350cebd139fa42ca716d11fcce36d6ee2..1959593f709278faf8bcdc79ad412ca22f5fac45 100755 (executable)
--- a/hashtab.h
+++ b/hashtab.h
@@ -25,9 +25,10 @@ struct hashtab {
 
 };
 
+#define     HASHTAB_TOMBSTONE           ((void *) -1)
 struct hashtab_name *hashtab_alloc_name (const char *str);
-struct hashtab_name *hashtab_get_key (struct hashtab *table, const char *name);
 
+struct hashtab_name *hashtab_get_key (struct hashtab *table, const char *name);
 void *hashtab_get (struct hashtab *table, struct hashtab_name *key);
 
 int hashtab_put (struct hashtab *table, struct hashtab_name *key, void *value);
diff --git a/lib.c b/lib.c
index 46441213a0e1f410e51652fb41c82ea2657e2278..6e12da5965fcbdd2aaace12eb3b2c5f0851f8744 100755 (executable)
--- a/lib.c
+++ b/lib.c
@@ -647,8 +647,8 @@ int is_pragma_igored (const char *filename) {
 
 struct temp_file {
 
+    char *name, *path;
     FILE *fp;
-    char name[1];
 
 };
 
@@ -656,7 +656,7 @@ static struct hashtab hashtab_tmpfiles = { 0 };
 
 FILE *scc_tmpfile (void) {
 
-    char *temp_path, *template;
+    char *temp_path, *template, *name, *p;
     
     struct hashtab_name *key;
     struct temp_file *tmp;
@@ -669,37 +669,62 @@ FILE *scc_tmpfile (void) {
     }
     
     template = xmalloc (strlen (temp_path) + 1 + 10 + 1);
+    
+again:
+    
     sprintf (template, "%s/sccXXXXXX", temp_path);
     
     if ((fd = mkstemp (template)) < 0) {
         return 0;
     }
     
-    if ((fp = fdopen (fd, "w+b"))) {
+    if ((p = strrchr (template, '/'))) {
+        name = xstrdup (p + 1);
+    } else {
+        name = xstrdup (template);
+    }
     
-        if (!(key = hashtab_get_key (&hashtab_tmpfiles, template))) {
-        
-            if (!((key = hashtab_alloc_name (xstrdup (template))))) {
-            
-                remove (template);
-                fclose (fp);
-                
-                return 0;
-            
-            }
-        
-        }
+    if ((key = hashtab_get_key (&hashtab_tmpfiles, name))) {
+    
+        close (fd);
         
-        tmp = xmalloc (sizeof (*tmp) + strlen (template )+ 1);
+        remove (template);
+        free (name);
         
-        sprintf (tmp->name, "%s", template);
+        goto again;
+    
+    }
+    
+    if (!((key = hashtab_alloc_name (name)))) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "failed to allocate memory for key");
+        exit (EXIT_FAILURE);
+    
+    }
+    
+    if ((fp = fdopen (fd, "w+b"))) {
+    
+        tmp = xmalloc (sizeof (*tmp));
         tmp->fp = fp;
         
+        tmp->path = xstrdup (template);
+        tmp->name = name;
+        
         hashtab_put (&hashtab_tmpfiles, key, tmp);
+        
+        free (template);
         return fp;
     
     }
     
+    free (name);
+    free (key);
+    
+    close (fd);
+    
+    remove (template);
+    free (template);
+    
     return 0;
 
 }
@@ -717,7 +742,7 @@ int scc_close (FILE *fp) {
             continue;
         }
         
-        if (!entry->key || !entry->value) {
+        if (!entry->key || !entry->value || entry->value == HASHTAB_TOMBSTONE) {
             continue;
         }
         
@@ -729,9 +754,13 @@ int scc_close (FILE *fp) {
                 return ret;
             }
             
-            remove (tmp->name);
+            hashtab_remove (&hashtab_tmpfiles, entry->key);
+            remove (tmp->path);
             
-            hashtab_remove (&hashtab_tmpfiles, hashtab_get_key (&hashtab_tmpfiles, tmp->name));
+            free (tmp->path);
+            free (tmp->name);
+            
+            free (tmp);
             return 0;
         
         }
@@ -755,7 +784,7 @@ void cleanup_tempfiles (void) {
             continue;
         }
         
-        if (!entry->key || !entry->value) {
+        if (!entry->key || !entry->value || entry->value == HASHTAB_TOMBSTONE) {
             continue;
         }
         
@@ -765,8 +794,7 @@ void cleanup_tempfiles (void) {
             continue;
         }
         
-        remove (tmp->name);
-        hashtab_remove (&hashtab_tmpfiles, hashtab_get_key (&hashtab_tmpfiles, tmp->name));
+        remove (tmp->path);
     
     }
 
@@ -876,49 +904,55 @@ FILE *scc_tmpfile (void) {
     struct hashtab_name *key;
     struct temp_file *tmp;
     
-    char *name;
+    char *name, *p;
     FILE *fp;
     
     if (!GetTempPath (MAX_PATH + 1, temp_path)) {
         return 0;
     }
     
+again:
+    
     if (!GetTempFileName (temp_path, "scc", 0, full_path)) {
         return 0;
     }
     
-    if ((name = strrchr (full_path, '\\'))) {
-        name++;
+    if ((p = strrchr (full_path, '\\'))) {
+        name = xstrdup (p + 1);
     } else {
-        name = full_path;
+        name = xstrdup (full_path);
+    }
+    
+    if ((key = hashtab_get_key (&hashtab_tmpfiles, name))) {
+    
+        free (name);
+        goto again;
+    
+    }
+    
+    if (!((key = hashtab_alloc_name (name)))) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "failed to allocate memory for key");
+        exit (EXIT_FAILURE);
+    
     }
     
     if ((fp = fopen (full_path, "w+b"))) {
-        
-        if (!(key = hashtab_get_key (&hashtab_tmpfiles, name))) {
-        
-            if (!((key = hashtab_alloc_name (xstrdup (name))))) {
-            
-                remove (full_path);
-                fclose (fp);
-                
-                return 0;
-            
-            }
-        
-        }
-        
+    
         tmp = xmalloc (sizeof (*tmp));
         tmp->fp = fp;
         
         tmp->path = xstrdup (full_path);
-        tmp->name = xstrdup (name);
+        tmp->name = name;
         
         hashtab_put (&hashtab_tmpfiles, key, tmp);
         return fp;
     
     }
     
+    free (name);
+    free (key);
+    
     return 0;
 
 }
@@ -926,8 +960,9 @@ FILE *scc_tmpfile (void) {
 int scc_close (FILE *fp) {
 
     struct hashtab_entry *entry;
-    struct temp_file *tmp;
+    struct hashtab_name *key;
     
+    struct temp_file *tmp;
     int ret, i;
     
     for (i = 0; i < hashtab_tmpfiles.capacity; i++) {
@@ -936,7 +971,7 @@ int scc_close (FILE *fp) {
             continue;
         }
         
-        if (!entry->key || !entry->value) {
+        if (!entry->key || !entry->value || entry->value == HASHTAB_TOMBSTONE) {
             continue;
         }
         
@@ -948,9 +983,12 @@ int scc_close (FILE *fp) {
                 return ret;
             }
             
+            hashtab_remove (&hashtab_tmpfiles, entry->key);
             remove (tmp->path);
             
-            hashtab_remove (&hashtab_tmpfiles, hashtab_get_key (&hashtab_tmpfiles, tmp->name));
+            free (tmp->path);
+            free (tmp->name);
+            
             return 0;
         
         }
@@ -974,7 +1012,7 @@ void cleanup_tempfiles (void) {
             continue;
         }
         
-        if (!entry->key || !entry->value) {
+        if (!entry->key || !entry->value || entry->value == HASHTAB_TOMBSTONE) {
             continue;
         }
         
@@ -985,7 +1023,6 @@ void cleanup_tempfiles (void) {
         }
         
         remove (tmp->path);
-        hashtab_remove (&hashtab_tmpfiles, hashtab_get_key (&hashtab_tmpfiles, tmp->name));
     
     }
 
@@ -995,8 +1032,8 @@ void cleanup_tempfiles (void) {
 
 struct temp_file {
 
+    char *name;
     FILE *fp;
-    char name[1];
 
 };
 
@@ -1030,7 +1067,7 @@ FILE *scc_tmpfile (void) {
 
     static unsigned long temp_id = 1;
     
-    char name[64];
+    char name[64], *temp;
     unsigned long i;
     
     struct hashtab_name *key;
@@ -1049,30 +1086,36 @@ FILE *scc_tmpfile (void) {
         
         }
         
+        temp = xstrdup (name);
+        
+        if ((key = hashtab_get_key (&hashtab_tmpfiles, temp))) {
+        
+            free (temp);
+            continue;
+        
+        }
+        
+        if (!((key = hashtab_alloc_name (temp)))) {
+        
+            report_at (program_name, 0, REPORT_ERROR, "failed to allocate memory for key");
+            exit (EXIT_FAILURE);
+        
+        }
+        
         if ((fp = fopen (name, "w+b"))) {
             
-            if (!(key = hashtab_get_key (&hashtab_tmpfiles, name))) {
-            
-                if (!((key = hashtab_alloc_name (xstrdup (name))))) {
-                
-                    remove (name);
-                    fclose (fp);
-                    
-                    continue;
-                
-                }
-            
-            }
-            
-            tmp = xmalloc (sizeof (*tmp) + strlen (name) + 1);
-            sprintf (tmp->name, "%s", name);
+            tmp = xmalloc (sizeof (*tmp));
             
+            tmp->name = temp;
             tmp->fp = fp;
         
             hashtab_put (&hashtab_tmpfiles, key, tmp);
             return fp;
         
         }
+        
+        free (temp);
+        free (key);
     
     }
     
@@ -1083,8 +1126,9 @@ FILE *scc_tmpfile (void) {
 int scc_close (FILE *fp) {
 
     struct hashtab_entry *entry;
-    struct temp_file *tmp;
+    struct hashtab_name *key;
     
+    struct temp_file *tmp;
     int ret, i;
     
     for (i = 0; i < hashtab_tmpfiles.capacity; i++) {
@@ -1093,7 +1137,7 @@ int scc_close (FILE *fp) {
             continue;
         }
         
-        if (!entry->key || !entry->value) {
+        if (!entry->key || !entry->value || entry->value == HASHTAB_TOMBSTONE) {
             continue;
         }
         
@@ -1105,9 +1149,10 @@ int scc_close (FILE *fp) {
                 return ret;
             }
             
+            hashtab_remove (&hashtab_tmpfiles, entry->key);
             remove (tmp->name);
             
-            hashtab_remove (&hashtab_tmpfiles, hashtab_get_key (&hashtab_tmpfiles, tmp->name));
+            free (tmp->name);
             return 0;
         
         }
@@ -1131,7 +1176,7 @@ void cleanup_tempfiles (void) {
             continue;
         }
         
-        if (!entry->key || !entry->value) {
+        if (!entry->key || !entry->value || entry->value == HASHTAB_TOMBSTONE) {
             continue;
         }
         
@@ -1142,7 +1187,6 @@ void cleanup_tempfiles (void) {
         }
         
         remove (tmp->name);
-        hashtab_remove (&hashtab_tmpfiles, hashtab_get_key (&hashtab_tmpfiles, tmp->name));
     
     }