Add support (if CONFIG_DEBUG_TCG is defined) for debugging leakage
of temporary variables. Generally any temporaries created by
a target while it is translating an instruction should be freed
by the end of that instruction; otherwise carefully crafted
guest code could cause TCG to run out of temporaries and assert.
By calling tcg_check_temp_count() after each instruction we can
check that we are not leaking temporaries in this way.

Signed-off-by: Peter Maydell <peter.mayd...@linaro.org>
---
 tcg/tcg.c |   32 ++++++++++++++++++++++++++++++++
 tcg/tcg.h |   17 +++++++++++++++++
 2 files changed, 49 insertions(+), 0 deletions(-)

diff --git a/tcg/tcg.c b/tcg/tcg.c
index 5dd6a2c..8748c05 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -450,6 +450,10 @@ static inline int tcg_temp_new_internal(TCGType type, int 
temp_local)
             s->nb_temps++;
         }
     }
+
+#if defined(CONFIG_DEBUG_TCG)
+    s->temps_in_use++;
+#endif
     return idx;
 }
 
@@ -475,6 +479,13 @@ static inline void tcg_temp_free_internal(int idx)
     TCGTemp *ts;
     int k;
 
+#if defined(CONFIG_DEBUG_TCG)
+    s->temps_in_use--;
+    if (s->temps_in_use < 0) {
+        fprintf(stderr, "More temporaries freed than allocated!\n");
+    }
+#endif
+
     assert(idx >= s->nb_globals && idx < s->nb_temps);
     ts = &s->temps[idx];
     assert(ts->temp_allocated != 0);
@@ -528,6 +539,27 @@ TCGv_i64 tcg_const_local_i64(int64_t val)
     return t0;
 }
 
+#if defined(CONFIG_DEBUG_TCG)
+void tcg_clear_temp_count(void)
+{
+    TCGContext *s = &tcg_ctx;
+    s->temps_in_use = 0;
+}
+
+int tcg_check_temp_count(void)
+{
+    TCGContext *s = &tcg_ctx;
+    if (s->temps_in_use) {
+        /* Clear the count so that we don't give another
+         * warning immediately next time around.
+         */
+        s->temps_in_use = 0;
+        return 1;
+    }
+    return 0;
+}
+#endif
+
 void tcg_register_helper(void *func, const char *name)
 {
     TCGContext *s = &tcg_ctx;
diff --git a/tcg/tcg.h b/tcg/tcg.h
index e1afde2..5538db9 100644
--- a/tcg/tcg.h
+++ b/tcg/tcg.h
@@ -323,6 +323,10 @@ struct TCGContext {
     int64_t restore_count;
     int64_t restore_time;
 #endif
+
+#ifdef CONFIG_DEBUG_TCG
+    int temps_in_use;
+#endif
 };
 
 extern TCGContext tcg_ctx;
@@ -392,6 +396,19 @@ static inline TCGv_i64 tcg_temp_local_new_i64(void)
 void tcg_temp_free_i64(TCGv_i64 arg);
 char *tcg_get_arg_str_i64(TCGContext *s, char *buf, int buf_size, TCGv_i64 
arg);
 
+#if defined(CONFIG_DEBUG_TCG)
+/* If you call tcg_clear_temp_count() at the start of a section of
+ * code which is not supposed to leak any TCG temporaries, then
+ * calling tcg_check_temp_count() at the end of the section will
+ * return 1 if the section did in fact leak a temporary.
+ */
+void tcg_clear_temp_count(void);
+int tcg_check_temp_count(void);
+#else
+#define tcg_clear_temp_count()
+#define tcg_check_temp_count() 0
+#endif
+
 void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf);
 
 #define TCG_CT_ALIAS  0x80
-- 
1.7.1


Reply via email to