On 14 July 2016 at 16:58, mtsio <[email protected]> wrote:
> I think I discovered what causes the crash. In apropos_in_all_indices
> (indices.c) at line 605 we are freeing up some memory (free
> (this_fb->contents;). If I delete these lines it works correctly but
> what is the root cause of that I'm not sure. The closer I got is that
> when the address of win->node->contents is 'close' to this_fb->contents
> and we free the second one we also messing up with win->node->contents.
> If the info file we search for is big these two could overlap.
>
> Is something like that possible?
Yes, I believe you are right. It's possible for win->node->contents to
point into the middle of the block pointed to by this_fb->contents. It
doesn't always happen (for example, if the character encoding has been
converted), so that could be why I didn't reproduce the crash.
The code that frees this_fb->contents is wrong. I'm fairly sure that I
put that code there in the first place: my best guess is that I wasn't
thinking about the interactive command "M-x index-apropos" and only
thinking of the "--apropos" command-line option.
I think that it is worth trying to conserve memory for an index
apropos search, because there can potentially be many manuals
installed on a system and loading them all into memory could be too
wasteful.
Measured with the "top" command (followed by "On" to sort by memory usage):
Running ginfo, followed by "M-x index-apropos RET gettext RET": the
memory in the VIRT column (virtual memory in kilobytes) is 20736.
If I comment out the lines to free the memory, recompile, and do the
same test, I get the usage up to 57952.
I've attached my work so far on a fix, which frees the file only when
the file had to be loaded. Because I haven't been able to replicate
the crash you got, I'm not sure for certain if it solves the problem.
Index: indices.c
===================================================================
--- indices.c (revision 7149)
+++ indices.c (working copy)
@@ -558,7 +558,7 @@ apropos_in_all_indices (char *search_string, int i
for (dir_index = 0; dir_menu[dir_index]; dir_index++)
{
REFERENCE **this_index, *this_item;
- FILE_BUFFER *this_fb;
+ FILE_BUFFER *this_fb, *loaded_file = 0;
this_item = dir_menu[dir_index];
if (!this_item->filename)
@@ -574,11 +574,14 @@ apropos_in_all_indices (char *search_string, int i
if (i < dir_index)
continue;
- this_fb = info_find_file (this_item->filename);
+ this_fb = check_loaded_file (this_item->filename);
if (!this_fb)
- continue;
+ this_fb = loaded_file = info_find_file (this_item->filename);
+ if (!this_fb)
+ continue; /* Couldn't load file. */
+
if (this_fb && inform)
message_in_echo_area (_("Scanning indices of '%s'..."), this_item->filename);
@@ -602,9 +605,13 @@ apropos_in_all_indices (char *search_string, int i
free (old_indices);
}
}
+
/* Try to avoid running out of memory */
- free (this_fb->contents);
- this_fb->contents = NULL;
+ if (loaded_file)
+ {
+ free (loaded_file->contents);
+ loaded_file->contents = NULL;
+ }
}
/* Build a list of the references which contain SEARCH_STRING. */
Index: nodes.c
===================================================================
--- nodes.c (revision 7149)
+++ nodes.c (working copy)
@@ -544,24 +544,17 @@ static void get_file_character_encoding (FILE_BUFF
static void forget_info_file (FILE_BUFFER *file_buffer);
static void info_reload_file_buffer_contents (FILE_BUFFER *fb);
-/* Locate the file named by FILENAME, and return the information structure
- describing this file. The file may appear in our list of loaded files
- already, or it may not. If it does not already appear, find the file,
- and add it to the list of loaded files. If the file cannot be found,
- return a NULL FILE_BUFFER *. */
+/* Try to find a file in our list of already loaded files. */
FILE_BUFFER *
-info_find_file (char *filename)
+check_loaded_file (char *filename)
{
- int i;
+ int is_fullpath, i;
FILE_BUFFER *file_buffer;
- char *fullpath;
- int is_fullpath;
/* If full path to the file has been given, we must find it exactly. */
is_fullpath = IS_ABSOLUTE (filename)
|| filename[0] == '.' && IS_SLASH(filename[1]);
- /* First try to find the file in our list of already loaded files. */
if (info_loaded_files)
{
for (i = 0; (file_buffer = info_loaded_files[i]); i++)
@@ -601,11 +594,31 @@ FILE_BUFFER *
return file_buffer;
}
}
+ return 0;
+}
+/* Locate the file named by FILENAME, and return the information structure
+ describing this file. The file may appear in our list of loaded files
+ already, or it may not. If it does not already appear, find the file,
+ and add it to the list of loaded files. If the file cannot be found,
+ return a NULL FILE_BUFFER *. */
+FILE_BUFFER *
+info_find_file (char *filename)
+{
+ FILE_BUFFER *file_buffer;
+ char *fullpath;
+ int is_fullpath;
+
+ file_buffer = check_loaded_file (filename);
+ if (file_buffer)
+ return file_buffer;
+
/* The file wasn't loaded. Try to load it now. */
/* Get the full pathname of this file, as known by the info system.
That is to say, search along INFOPATH and expand tildes, etc. */
+ is_fullpath = IS_ABSOLUTE (filename)
+ || filename[0] == '.' && IS_SLASH(filename[1]);
if (!is_fullpath)
fullpath = info_find_fullpath (filename, 0);
else
Index: nodes.h
===================================================================
--- nodes.h (revision 7149)
+++ nodes.h (working copy)
@@ -141,6 +141,8 @@ extern size_t info_loaded_files_slots;
return a NULL FILE_BUFFER *. */
FILE_BUFFER *info_find_file (char *filename);
+FILE_BUFFER *check_loaded_file (char *filename);
+
FILE_BUFFER *info_find_subfile (char *filename);
TAG *info_create_tag (void);