From ab9256adf082ce78cfb39eb246323e57b846a7a4 Mon Sep 17 00:00:00 2001
From: Lukas Fleischer <lfleischer@calcurse.org>
Date: Tue, 27 Sep 2016 18:52:13 +0200
Subject: Fix out-of-bounds memory access

Do not try to access freed day items. This also fixes unexpected
selection changes after modifying appointments or events.

Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
---
 src/calcurse.c | 11 ++++++++++-
 src/calcurse.h |  2 ++
 src/day.c      |  9 +++++++--
 src/ui-day.c   |  9 +++++++--
 4 files changed, 26 insertions(+), 5 deletions(-)

(limited to 'src')

diff --git a/src/calcurse.c b/src/calcurse.c
index c0d9624..89710af 100644
--- a/src/calcurse.c
+++ b/src/calcurse.c
@@ -49,6 +49,15 @@ int count, reg;
 static void do_storage(int day_changed)
 {
 	struct day_item *day = ui_day_selitem();
+	union aptev_ptr item;
+
+	if (day) {
+		/*
+		 * day_process_storage() rebuilds the vector of day items, so
+		 * we need to save the reference to the actual item here.
+		 */
+		item = day->item;
+	}
 
 	day_process_storage(ui_calendar_get_slctd_day(), day_changed);
 	ui_day_load_items();
@@ -56,7 +65,7 @@ static void do_storage(int day_changed)
 	if (day_changed)
 		ui_day_sel_reset();
 	else if (day)
-		ui_day_set_selitem(day);
+		ui_day_set_selitem_by_aptev_ptr(item);
 }
 
 static inline void key_generic_change_view(void)
diff --git a/src/calcurse.h b/src/calcurse.h
index 3aab885..c8f7bb9 100644
--- a/src/calcurse.h
+++ b/src/calcurse.h
@@ -772,6 +772,7 @@ int day_check_if_item(struct date);
 unsigned day_chk_busy_slices(struct date, int, int *);
 struct day_item *day_cut_item(long, int);
 int day_paste_item(struct day_item *, long);
+int day_get_position_by_aptev_ptr(union aptev_ptr);
 int day_get_position(struct day_item *);
 struct day_item *day_get_item(int);
 unsigned day_item_count(int);
@@ -1044,6 +1045,7 @@ void todo_free_list(void);
 
 /* ui-day.c */
 struct day_item *ui_day_selitem(void);
+void ui_day_set_selitem_by_aptev_ptr(union aptev_ptr);
 void ui_day_set_selitem(struct day_item *);
 void ui_day_item_add(void);
 void ui_day_item_delete(unsigned);
diff --git a/src/day.c b/src/day.c
index 2bd4a31..970e8ff 100644
--- a/src/day.c
+++ b/src/day.c
@@ -695,20 +695,25 @@ int day_paste_item(struct day_item *p, long date)
 }
 
 /* Returns the position corresponding to a given item. */
-int day_get_position(struct day_item *needle)
+int day_get_position_by_aptev_ptr(union aptev_ptr aptevp)
 {
 	int n = 0;
 
 	VECTOR_FOREACH(&day_items, n) {
 		struct day_item *p = VECTOR_NTH(&day_items, n);
 		/* Compare pointers. */
-		if (p->item.ev == needle->item.ev)
+		if (p->item.ev == aptevp.ev)
 			return n;
 	}
 
 	return -1;
 }
 
+int day_get_position(struct day_item *needle)
+{
+	return day_get_position_by_aptev_ptr(needle->item);
+}
+
 /* Returns a structure containing the selected item. */
 struct day_item *day_get_item(int item_number)
 {
diff --git a/src/ui-day.c b/src/ui-day.c
index 6eb055e..c8a4420 100644
--- a/src/ui-day.c
+++ b/src/ui-day.c
@@ -46,13 +46,18 @@ struct day_item *ui_day_selitem(void)
 	return day_get_item(listbox_get_sel(&lb_apt));
 }
 
-void ui_day_set_selitem(struct day_item *day)
+void ui_day_set_selitem_by_aptev_ptr(union aptev_ptr p)
 {
-	int n = day_get_position(day);
+	int n = day_get_position_by_aptev_ptr(p);
 	if (n >= 0)
 		listbox_set_sel(&lb_apt, n);
 }
 
+void ui_day_set_selitem(struct day_item *day)
+{
+	ui_day_set_selitem_by_aptev_ptr(day->item);
+}
+
 /* Request the user to enter a new time. */
 static int day_edit_time(int time, unsigned *new_hour,
 			 unsigned *new_minute)
-- 
cgit v1.2.3-70-g09d2