[gnumeric] Names: fix memory corruption.
- From: Morten Welinder <mortenw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnumeric] Names: fix memory corruption.
- Date: Mon, 3 Mar 2014 02:36:23 +0000 (UTC)
commit f8ad082d199d245096144b7e5308c1fe8fc0f785
Author: Morten Welinder <terra gnome org>
Date: Sun Mar 2 21:31:41 2014 -0500
Names: fix memory corruption.
ChangeLog | 15 +++
NEWS | 1 +
plugins/excel/ms-excel-write.c | 3 +-
plugins/openoffice/openoffice-read.c | 17 ++--
src/application.c | 18 ++++
src/application.h | 2 +
src/dependent.c | 2 +-
src/expr-name.c | 158 ++++++++++++++++++++++++++++------
src/expr-name.h | 16 +---
src/ssconvert.c | 4 +-
src/ssindex.c | 7 +-
src/wbc-gtk.c | 13 +++-
12 files changed, 207 insertions(+), 49 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index c0178af..8558a64 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,20 @@
2014-03-02 Morten Welinder <terra gnome org>
+ * src/wbc-gtk.c (cb_workbook_debug_info): New debug flag
+ name-collections.
+
+ * src/expr-name.c (gnm_named_expr_collection_dump)
+ (gnm_named_expr_collection_sanity_check): New function.
+
+ * src/application.c (gnm_app_sanity_check): New function.
+
+ * src/expr-name.c (gnm_named_expr_collection_new): Don't use the
+ string inside the GOString as a hash key. It can change.
+ (gnm_named_expr_collection_foreach): As a consequence of the
+ above, the first argument to the handler for
+ gnm_named_expr_collection_foreach changes to something
+ unspecified. All callers changed.
+
* src/sheet.c (sheet_dup): Don't flip display-outlines for the new
sheet.
diff --git a/NEWS b/NEWS
index 0f0999f..94bd3b5 100644
--- a/NEWS
+++ b/NEWS
@@ -51,6 +51,7 @@ Morten:
* Don't generate value format during xls read. [#725453]
* Fix name criticals.
* Fix sheet duplication issue. [#725504]
+ * Fix named expressions crasher. [Part of #725459]
--------------------------------------------------------------------------
Gnumeric 1.12.11
diff --git a/plugins/excel/ms-excel-write.c b/plugins/excel/ms-excel-write.c
index 2e07ad0..1b8ac12 100644
--- a/plugins/excel/ms-excel-write.c
+++ b/plugins/excel/ms-excel-write.c
@@ -6413,7 +6413,8 @@ excel_write_v8 (ExcelWriteState *ewb, GsfOutfile *outfile)
/****************************************************************************/
static void
-cb_check_names (gpointer key, GnmNamedExpr *nexpr, ExcelWriteState *ewb)
+cb_check_names (G_GNUC_UNUSED gconstpointer key,
+ GnmNamedExpr *nexpr, ExcelWriteState *ewb)
{
if (expr_name_is_active (nexpr))
excel_write_prep_expr (ewb, nexpr->texpr);
diff --git a/plugins/openoffice/openoffice-read.c b/plugins/openoffice/openoffice-read.c
index 3fa881a..732bf91 100644
--- a/plugins/openoffice/openoffice-read.c
+++ b/plugins/openoffice/openoffice-read.c
@@ -1824,16 +1824,18 @@ odf_fix_en_validate (char const *name, odf_fix_expr_names_t *fen)
}
static void
-odf_fix_en_collect (gchar const *key, G_GNUC_UNUSED GnmNamedExpr *nexpr, odf_fix_expr_names_t *fen)
+odf_fix_en_collect (G_GNUC_UNUSED gconstpointer key_,
+ GnmNamedExpr *nexpr, odf_fix_expr_names_t *fen)
{
GString *str;
gchar *here;
+ const char *name = expr_name_name (nexpr);
- if (expr_name_validate (key))
+ if (expr_name_validate (name))
return;
- if (NULL != g_hash_table_lookup (fen->orig2fixed, key))
+ if (NULL != g_hash_table_lookup (fen->orig2fixed, name))
return;
- str = g_string_new (key);
+ str = g_string_new (name);
for (here = str->str; *here; here = g_utf8_next_char (here)) {
if (!g_unichar_isalnum (g_utf8_get_char (here)) &&
@@ -1845,13 +1847,14 @@ odf_fix_en_collect (gchar const *key, G_GNUC_UNUSED GnmNamedExpr *nexpr, odf_fix
}
while (!odf_fix_en_validate (str->str, fen))
g_string_append_c (str, '_');
- odf_fix_expr_names_t_add (fen, key, g_string_free (str, FALSE));
+ odf_fix_expr_names_t_add (fen, name, g_string_free (str, FALSE));
}
static void
-odf_fix_en_find (gchar const *key, GnmNamedExpr *nexpr, odf_fix_expr_names_t *fen)
+odf_fix_en_find (G_GNUC_UNUSED gconstpointer key,
+ GnmNamedExpr *nexpr, odf_fix_expr_names_t *fen)
{
- if (strcmp (key, fen->nexpr_name) == 0)
+ if (strcmp (expr_name_name (nexpr), fen->nexpr_name) == 0)
fen->nexpr = nexpr;
}
diff --git a/src/application.c b/src/application.c
index 33ed7eb..db6ba67 100644
--- a/src/application.c
+++ b/src/application.c
@@ -25,6 +25,8 @@
#include "sheet-object.h"
#include "commands.h"
#include "gui-clipboard.h"
+#include "expr-name.h"
+#include "workbook-priv.h"
#include <gnumeric-conf.h>
#include <goffice/goffice.h>
@@ -154,6 +156,22 @@ gnm_app_workbook_list (void)
return app->workbook_list;
}
+void
+gnm_app_sanity_check (void)
+{
+ GList *l;
+ gboolean err = FALSE;
+ for (l = gnm_app_workbook_list (); l; l = l->next) {
+ Workbook *wb = l->data;
+ if (gnm_named_expr_collection_sanity_check (wb->names, "workbook"))
+ err = TRUE;
+ }
+ if (err)
+ g_error ("Sanity check failed\n");
+}
+
+
+
/**
* gnm_app_clipboard_clear:
*
diff --git a/src/application.h b/src/application.h
index f88b4e8..af1d16b 100644
--- a/src/application.h
+++ b/src/application.h
@@ -24,6 +24,8 @@ Workbook *gnm_app_workbook_get_by_index (int i);
GSList *gnm_app_history_get_list (int max_elements);
void gnm_app_history_add (char const *filename, const char *mimetype);
+void gnm_app_sanity_check (void);
+
void gnm_app_recalc (void);
void gnm_app_recalc_start (void);
void gnm_app_recalc_finish (void);
diff --git a/src/dependent.c b/src/dependent.c
index 174aaeb..ab9b974 100644
--- a/src/dependent.c
+++ b/src/dependent.c
@@ -2114,7 +2114,7 @@ struct cb_remote_names {
};
static void
-cb_remote_names1 (G_GNUC_UNUSED const char *name,
+cb_remote_names1 (G_GNUC_UNUSED gconstpointer key,
GnmNamedExpr *nexpr,
struct cb_remote_names *data)
{
diff --git a/src/expr-name.c b/src/expr-name.c
index 1056367..c4e0185 100644
--- a/src/expr-name.c
+++ b/src/expr-name.c
@@ -174,6 +174,33 @@ expr_name_relink_deps (GnmNamedExpr *nexpr)
g_slist_free (deps);
}
+static guint
+fake_go_string_hash (gconstpointer s_)
+{
+ const GOString *s = s_;
+ return g_str_hash (s->str);
+}
+
+static gboolean
+fake_go_string_equal (gconstpointer a_, gconstpointer b_)
+{
+ const GOString *a = a_;
+ const GOString *b = b_;
+ return g_str_equal (a->str, b->str);
+}
+
+
+struct _GnmNamedExprCollection {
+ /* all the defined names */
+ GHashTable *names;
+
+ /* placeholders for references to undefined names */
+ GHashTable *placeholders;
+
+ /* <private> */
+ unsigned ref_count; /* boxed type */
+};
+
/**
* gnm_named_expr_collection_new:
*
@@ -184,9 +211,11 @@ gnm_named_expr_collection_new (void)
{
GnmNamedExprCollection *res = g_new (GnmNamedExprCollection, 1);
- res->names = g_hash_table_new_full (g_str_hash, g_str_equal,
- NULL, (GDestroyNotify) cb_nexpr_remove);
- res->placeholders = g_hash_table_new_full (g_str_hash, g_str_equal,
+ res->names = g_hash_table_new_full
+ (fake_go_string_hash, fake_go_string_equal,
+ NULL, (GDestroyNotify) cb_nexpr_remove);
+ res->placeholders = g_hash_table_new_full
+ (fake_go_string_hash, fake_go_string_equal,
NULL, (GDestroyNotify) cb_nexpr_remove);
res->ref_count = 1;
@@ -221,6 +250,76 @@ gnm_named_expr_collection_ref (GnmNamedExprCollection *names)
return names;
}
+void
+gnm_named_expr_collection_dump (GnmNamedExprCollection *names, const char *id)
+{
+ g_printerr ("Named collection %s\n", id);
+ if (!names) {
+ g_printerr (" Empty\n");
+ return;
+ }
+
+ if (names->names && g_hash_table_size (names->names)) {
+ GHashTableIter hiter;
+ gpointer key, value;
+
+ g_printerr (" Defined names:\n");
+ g_hash_table_iter_init (&hiter, names->names);
+ while (g_hash_table_iter_next (&hiter, &key, &value)) {
+ const GOString *name = key;
+ GnmNamedExpr const *nexpr = value;
+ g_printerr (" [%s] =>\n", name->str);
+ if (name != nexpr->name)
+ g_printerr (" Weird keys: %p vs %p\n",
+ name, nexpr->name);
+ }
+ }
+
+ if (names->placeholders && g_hash_table_size (names->placeholders)) {
+ GHashTableIter hiter;
+ gpointer key, value;
+
+ g_printerr (" Defined placeholders:\n");
+ g_hash_table_iter_init (&hiter, names->placeholders);
+ while (g_hash_table_iter_next (&hiter, &key, &value)) {
+ const GOString *name = key;
+ GnmNamedExpr const *nexpr = value;
+ g_printerr (" [%s] =>\n", name->str);
+ if (name != nexpr->name)
+ g_printerr (" Weird keys: %p vs %p\n",
+ name, nexpr->name);
+ }
+ }
+}
+
+gboolean
+gnm_named_expr_collection_sanity_check (GnmNamedExprCollection *names,
+ const char *id)
+{
+ gboolean err = FALSE;
+ g_printerr ("Checking sanity for container %s\n", id);
+ if (names->names) {
+ GHashTableIter hiter;
+ gpointer key, value;
+
+ g_hash_table_iter_init (&hiter, names->names);
+ while (g_hash_table_iter_next (&hiter, &key, &value)) {
+ const GOString *name = key;
+ GnmNamedExpr const *nexpr = value;
+ if (name != nexpr->name) {
+ err = TRUE;
+ g_printerr ("Container %s has strange defined name\n",
+ id);
+ g_printerr (" key is %p [%s]\n",
+ name, name->str);
+ g_printerr (" target's name is %p [%s]\n",
+ nexpr->name, nexpr->name->str);
+ }
+ }
+ }
+ return err;
+}
+
GType
gnm_named_expr_collection_get_type (void)
{
@@ -280,9 +379,14 @@ gnm_named_expr_collection_lookup (GnmNamedExprCollection const *scope,
char const *name)
{
if (scope != NULL) {
- GnmNamedExpr *nexpr = g_hash_table_lookup (scope->names, name);
+ GOString fake_name;
+ GnmNamedExpr *nexpr;
+
+ fake_name.str = name;
+ nexpr = g_hash_table_lookup (scope->names, &fake_name);
if (nexpr == NULL)
- nexpr = g_hash_table_lookup (scope->placeholders, name);
+ nexpr = g_hash_table_lookup (scope->placeholders,
+ &fake_name);
return nexpr;
} else
return NULL;
@@ -333,8 +437,9 @@ gnm_named_expr_collection_insert (GnmNamedExprCollection *scope,
/* name can be active at this point, eg we are converting a
* placeholder, or changing a scope */
nexpr->scope = scope;
- g_hash_table_replace (nexpr->is_placeholder
- ? scope->placeholders : scope->names, (gpointer)nexpr->name->str, nexpr);
+ g_hash_table_replace
+ (nexpr->is_placeholder ? scope->placeholders : scope->names,
+ (gpointer)nexpr->name, nexpr);
}
typedef struct {
@@ -620,12 +725,15 @@ expr_name_add (GnmParsePos const *pp, char const *name,
{
GnmNamedExpr *nexpr = NULL;
GnmNamedExprCollection *scope = NULL;
+ GOString fake_name;
g_return_val_if_fail (pp != NULL, NULL);
g_return_val_if_fail (pp->sheet != NULL || pp->wb != NULL, NULL);
g_return_val_if_fail (name != NULL, NULL);
g_return_val_if_fail (stub == NULL || stub->is_placeholder, NULL);
+ fake_name.str = name;
+
if (texpr != NULL && expr_name_check_for_loop (name, texpr)) {
gnm_expr_top_unref (texpr);
if (error_msg)
@@ -635,7 +743,7 @@ expr_name_add (GnmParsePos const *pp, char const *name,
scope = (pp->sheet != NULL) ? pp->sheet->names : pp->wb->names;
/* see if there was a place holder */
- nexpr = g_hash_table_lookup (scope->placeholders, name);
+ nexpr = g_hash_table_lookup (scope->placeholders, &fake_name);
if (nexpr != NULL) {
if (texpr == NULL) {
/* there was already a placeholder for this */
@@ -644,10 +752,10 @@ expr_name_add (GnmParsePos const *pp, char const *name,
}
/* convert the placeholder into a real name */
- g_hash_table_steal (scope->placeholders, name);
+ g_hash_table_steal (scope->placeholders, &fake_name);
nexpr->is_placeholder = FALSE;
} else {
- nexpr = g_hash_table_lookup (scope->names, name);
+ nexpr = g_hash_table_lookup (scope->names, &fake_name);
/* If this is a permanent name, we may be adding it */
/* on opening of a file, although */
/* the name is already in place. */
@@ -767,7 +875,7 @@ expr_name_remove (GnmNamedExpr *nexpr)
g_hash_table_remove (
nexpr->is_placeholder ? nexpr->scope->placeholders : nexpr->scope->names,
- nexpr->name->str);
+ nexpr->name);
}
const char *
@@ -790,6 +898,7 @@ expr_name_set_name (GnmNamedExpr *nexpr,
{
const char *old_name;
GHashTable *h;
+ GOString fake_new_name;
g_return_val_if_fail (nexpr != NULL, TRUE);
g_return_val_if_fail (nexpr->scope == NULL || new_name, TRUE);
@@ -798,6 +907,7 @@ expr_name_set_name (GnmNamedExpr *nexpr,
if (go_str_compare (new_name, old_name) == 0)
return FALSE;
+ fake_new_name.str = new_name;
#if 0
g_printerr ("Renaming %s to %s\n", old_name, new_name);
#endif
@@ -808,21 +918,23 @@ expr_name_set_name (GnmNamedExpr *nexpr,
: NULL;
if (h) {
if (new_name &&
- (g_hash_table_lookup (nexpr->scope->placeholders, new_name) ||
- g_hash_table_lookup (nexpr->scope->names, new_name))) {
+ (g_hash_table_lookup (nexpr->scope->placeholders,
+ &fake_new_name) ||
+ g_hash_table_lookup (nexpr->scope->names,
+ &fake_new_name))) {
/* The only error not to be blamed on the programmer is
already-in-use. */
return TRUE;
}
- g_hash_table_steal (h, old_name);
+ g_hash_table_steal (h, nexpr->name);
}
go_string_unref (nexpr->name);
nexpr->name = go_string_new (new_name);
if (h)
- g_hash_table_insert (h, (gpointer)nexpr->name->str, nexpr);
+ g_hash_table_insert (h, (gpointer)nexpr->name, nexpr);
return FALSE;
}
@@ -889,7 +1001,6 @@ char *
expr_name_set_pos (GnmNamedExpr *nexpr, GnmParsePos const *pp)
{
GnmNamedExprCollection *old_scope, *new_scope;
- const char *name;
g_return_val_if_fail (nexpr != NULL, NULL);
g_return_val_if_fail (pp != NULL, NULL);
@@ -897,20 +1008,19 @@ expr_name_set_pos (GnmNamedExpr *nexpr, GnmParsePos const *pp)
old_scope = nexpr->scope;
new_scope = pp->sheet ? pp->sheet->names : pp->wb->names;
- name = nexpr->name->str;
if (old_scope != new_scope &&
- (g_hash_table_lookup (new_scope->placeholders, name) ||
- g_hash_table_lookup (new_scope->names, name))) {
+ (g_hash_table_lookup (new_scope->placeholders, nexpr->name) ||
+ g_hash_table_lookup (new_scope->names, nexpr->name))) {
const char *fmt = pp->sheet
? _("'%s' is already defined in sheet")
: _("'%s' is already defined in workbook");
- return g_strdup_printf (fmt, name);
+ return g_strdup_printf (fmt, nexpr->name);
}
if (old_scope)
g_hash_table_steal
(nexpr->is_placeholder ? old_scope->placeholders : old_scope->names,
- name);
+ nexpr->name);
nexpr->pos = *pp;
gnm_named_expr_collection_insert (new_scope, nexpr);
@@ -1013,12 +1123,10 @@ expr_name_set_is_placeholder (GnmNamedExpr *nexpr, gboolean is_placeholder)
nexpr->is_placeholder = is_placeholder;
if (nexpr->scope) {
- const char *name = expr_name_name (nexpr);
-
g_hash_table_steal (is_placeholder
? nexpr->scope->names
: nexpr->scope->placeholders,
- name);
+ nexpr->name);
gnm_named_expr_collection_insert (nexpr->scope, nexpr);
}
}
@@ -1036,7 +1144,7 @@ struct cb_expr_name_in_use {
};
static void
-cb_expr_name_in_use (G_GNUC_UNUSED const char *name,
+cb_expr_name_in_use (G_GNUC_UNUSED gconstpointer key,
GnmNamedExpr *nexpr,
struct cb_expr_name_in_use *pdata)
{
diff --git a/src/expr-name.h b/src/expr-name.h
index 6e5a0be..7bd2eab 100644
--- a/src/expr-name.h
+++ b/src/expr-name.h
@@ -65,17 +65,6 @@ GOUndo *expr_name_set_expr_undo_new (GnmNamedExpr *nexpr);
/******************************************************************************/
-struct _GnmNamedExprCollection {
- /* all the defined names */
- GHashTable *names;
-
- /* placeholders for references to undefined names */
- GHashTable *placeholders;
-
- /* <private> */
- unsigned ref_count; /* boxed type */
-};
-
GType gnm_named_expr_collection_get_type (void);
GnmNamedExprCollection *gnm_named_expr_collection_new (void);
void gnm_named_expr_collection_free (GnmNamedExprCollection *names);
@@ -88,6 +77,11 @@ GSList *gnm_named_expr_collection_list (GnmNamedExprCollection const *scope);
GnmNamedExpr *gnm_named_expr_collection_lookup (GnmNamedExprCollection const *scope,
char const *name);
+void gnm_named_expr_collection_dump (GnmNamedExprCollection *names,
+ const char *id);
+gboolean gnm_named_expr_collection_sanity_check (GnmNamedExprCollection *names,
+ const char *id);
+
G_END_DECLS
#endif /* _GNM_EXPR_NAME_H_ */
diff --git a/src/ssconvert.c b/src/ssconvert.c
index 0a0435a..75f4006 100644
--- a/src/ssconvert.c
+++ b/src/ssconvert.c
@@ -335,7 +335,9 @@ suggest_size (GSList *wbs, int *csuggest, int *rsuggest)
}
static void
-cb_fixup_name_wb (const char *name, GnmNamedExpr *nexpr, Workbook *wb)
+cb_fixup_name_wb (G_GNUC_UNUSED gconstpointer key,
+ GnmNamedExpr *nexpr,
+ Workbook *wb)
{
GnmParsePos newpos = nexpr->pos;
diff --git a/src/ssindex.c b/src/ssindex.c
index d255734..b23c778 100644
--- a/src/ssindex.c
+++ b/src/ssindex.c
@@ -20,6 +20,7 @@
#include "workbook.h"
#include "sheet.h"
#include "cell.h"
+#include "expr-name.h"
#include "value.h"
#include "mstyle.h"
#include "sheet-style.h"
@@ -150,9 +151,11 @@ ssindex_chart (IndexerState *state, GogObject *obj)
}
static void
-cb_index_name (const char *name, GnmExprName const *nexpr, IndexerState *state)
+cb_index_name (G_GNUC_UNUSED gconstpointer key,
+ GnmNamedExpr const *nexpr, IndexerState *state)
{
- gsf_xml_out_simple_element (state->output, "data", name);
+ gsf_xml_out_simple_element (state->output,
+ "data", expr_name_name (nexpr));
}
diff --git a/src/wbc-gtk.c b/src/wbc-gtk.c
index 84c4846..8d8d318 100644
--- a/src/wbc-gtk.c
+++ b/src/wbc-gtk.c
@@ -60,6 +60,7 @@
#include "tools/analysis-auto-expression.h"
#include "sheet-object-cell-comment.h"
#include "print-info.h"
+#include "expr-name.h"
#include <goffice/goffice.h>
#include <gsf/gsf-impl-utils.h>
@@ -2202,6 +2203,7 @@ cb_statusbox_focus (GtkEntry *entry, GdkEventFocus *event,
}
/******************************************************************************/
+
static void
cb_workbook_debug_info (WBCGtk *wbcg)
{
@@ -2223,6 +2225,14 @@ cb_workbook_debug_info (WBCGtk *wbcg)
if (gnm_debug_flag ("style-optimize")) {
workbook_optimize_style (wb);
}
+
+ if (gnm_debug_flag ("name-collections")) {
+ gnm_named_expr_collection_dump (wb->names, "workbook");
+ WORKBOOK_FOREACH_SHEET(wb, sheet, {
+ gnm_named_expr_collection_dump (sheet->names,
+ sheet->name_unquoted);
+ });
+ }
}
static void
@@ -2821,7 +2831,8 @@ wbc_gtk_create_edit_area (WBCGtk *wbcg)
debug_button = GET_GUI_ITEM ("debug_button");
if (gnm_debug_flag ("deps") ||
gnm_debug_flag ("expr-sharer") ||
- gnm_debug_flag ("style-optimize")) {
+ gnm_debug_flag ("style-optimize") ||
+ gnm_debug_flag ("name-collections")) {
g_signal_connect_swapped (debug_button,
"clicked", G_CALLBACK (cb_workbook_debug_info),
wbcg);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]