Reduce amount of leaked memory by libmagic

libmagic always leaks 48 bytes. Now we leak those bytes only once instead of
every content type detection.

Signed-off-by: Sebastian Ramacher <sebastian+dev@ramacher.at>
This commit is contained in:
Sebastian Ramacher 2016-01-20 13:45:46 +01:00
parent d1c38a703c
commit e550ab66ee
8 changed files with 123 additions and 41 deletions

View file

@ -17,14 +17,23 @@
#include <glib.h> #include <glib.h>
#include <gio/gio.h> #include <gio/gio.h>
/** Read a most GT_MAX_READ bytes before falling back to file. */ struct zathura_content_type_context_s
static const size_t GT_MAX_READ = 1 << 16; {
#ifdef WITH_MAGIC
magic_t magic;
#endif
};
zathura_content_type_context_t*
zathura_content_type_new(void)
{
zathura_content_type_context_t* context =
g_try_malloc0(sizeof(zathura_content_type_context_t));
if (context == NULL) {
return NULL;
}
#ifdef WITH_MAGIC #ifdef WITH_MAGIC
static const char*
guess_type_magic(const char* path) {
const char* mime_type = NULL;
/* creat magic cookie */ /* creat magic cookie */
const int flags = const int flags =
MAGIC_MIME_TYPE | MAGIC_MIME_TYPE |
@ -36,31 +45,63 @@ guess_type_magic(const char* path) {
magic_t magic = magic_open(flags); magic_t magic = magic_open(flags);
if (magic == NULL) { if (magic == NULL) {
girara_debug("failed creating the magic cookie"); girara_debug("failed creating the magic cookie");
goto cleanup; return context;
} }
/* ... and load mime database */ /* ... and load mime database */
if (magic_load(magic, NULL) < 0) { if (magic_load(magic, NULL) < 0) {
girara_debug("failed loading the magic database: %s", magic_error(magic)); girara_debug("failed loading the magic database: %s", magic_error(magic));
goto cleanup; magic_close(magic);
return context;
} }
context->magic = magic;
#endif
return context;
}
void
zathura_content_type_free(zathura_content_type_context_t* context)
{
if (context == NULL) {
return;
}
#ifdef WITH_MAGIC
if (context->magic != NULL) {
magic_close(context->magic);
}
#endif
g_free(context);
}
/** Read a most GT_MAX_READ bytes before falling back to file. */
static const size_t GT_MAX_READ = 1 << 16;
#ifdef WITH_MAGIC
static const char*
guess_type_magic(zathura_content_type_context_t* context, const char* path)
{
if (context == NULL || context->magic == NULL) {
return NULL;
}
const char* mime_type = NULL;
/* get the mime type */ /* get the mime type */
mime_type = magic_file(magic, path); mime_type = magic_file(context->magic, path);
if (mime_type == NULL) { if (mime_type == NULL) {
girara_debug("failed guessing filetype: %s", magic_error(magic)); girara_debug("failed guessing filetype: %s", magic_error(context->magic));
goto cleanup; return NULL;
} }
/* dup so we own the memory */ /* dup so we own the memory */
mime_type = g_strdup(mime_type); mime_type = g_strdup(mime_type);
girara_debug("magic detected filetype: %s", mime_type); girara_debug("magic detected filetype: %s", mime_type);
cleanup:
if (magic != NULL) {
magic_close(magic);
}
return mime_type; return mime_type;
} }
@ -71,7 +112,9 @@ guess_type_file(const char* UNUSED(path))
} }
#else #else
static const char* static const char*
guess_type_magic(const char* UNUSED(path)) { guess_type_magic(zathura_content_type_context_t* UNUSED(context),
const char* UNUSED(path))
{
return NULL; return NULL;
} }
@ -161,10 +204,11 @@ guess_type_glib(const char* path)
} }
const char* const char*
guess_content_type(const char* path) zathura_content_type_guess(zathura_content_type_context_t* context,
const char* path)
{ {
/* try libmagic first */ /* try libmagic first */
const char* content_type = guess_type_magic(path); const char* content_type = guess_type_magic(context, path);
if (content_type != NULL) { if (content_type != NULL) {
return content_type; return content_type;
} }

View file

@ -3,6 +3,22 @@
#ifndef ZATHURA_CONTENT_TYPE_H #ifndef ZATHURA_CONTENT_TYPE_H
#define ZATHURA_CONTENT_TYPE_H #define ZATHURA_CONTENT_TYPE_H
#include "types.h"
/**
* Create new context for MIME type detection.
*
* @return new context
*/
zathura_content_type_context_t* zathura_content_type_new(void);
/**
* Free MIME type detection context.
*
* @param context The context.
*/
void zathura_content_type_free(zathura_content_type_context_t* context);
/** /**
* "Guess" the content type of a file. Various methods are tried depending on * "Guess" the content type of a file. Various methods are tried depending on
* the available libraries. * the available libraries.
@ -10,6 +26,7 @@
* @param path file name * @param path file name
* @return content type of path * @return content type of path
*/ */
const char* guess_content_type(const char* path); const char* zathura_content_type_guess(zathura_content_type_context_t* context,
const char* path);
#endif #endif

View file

@ -61,10 +61,10 @@ check_set_error(zathura_error_t* error, zathura_error_t code) {
} }
zathura_document_t* zathura_document_t*
zathura_document_open(zathura_plugin_manager_t* plugin_manager, const char* zathura_document_open(zathura_t* zathura, const char* path, const char* uri,
path, const char *uri, const char* password, zathura_error_t* error) const char* password, zathura_error_t* error)
{ {
if (path == NULL) { if (zathura == NULL || path == NULL) {
return NULL; return NULL;
} }
@ -87,14 +87,14 @@ zathura_document_open(zathura_plugin_manager_t* plugin_manager, const char*
goto error_free; goto error_free;
} }
content_type = guess_content_type(real_path); content_type = zathura_content_type_guess(zathura->content_type_context, real_path);
if (content_type == NULL) { if (content_type == NULL) {
girara_error("Could not determine file type."); girara_error("Could not determine file type.");
check_set_error(error, ZATHURA_ERROR_UNKNOWN); check_set_error(error, ZATHURA_ERROR_UNKNOWN);
goto error_free; goto error_free;
} }
plugin = zathura_plugin_manager_get_plugin(plugin_manager, content_type); plugin = zathura_plugin_manager_get_plugin(zathura->plugins.manager, content_type);
if (plugin == NULL) { if (plugin == NULL) {
girara_error("Unknown file type: '%s'", content_type); girara_error("Unknown file type: '%s'", content_type);

View file

@ -11,14 +11,14 @@
/** /**
* Open the document * Open the document
* *
* @param plugin_manager The plugin manager * @param plugin_manager The zathura instance
* @param path Path to the document * @param path Path to the document
* @param password Password of the document or NULL * @param password Password of the document or NULL
* @param error Optional error parameter * @param error Optional error parameter
* @return The document object and NULL if an error occurs * @return The document object and NULL if an error occurs
*/ */
zathura_document_t* zathura_document_open(zathura_plugin_manager_t* zathura_document_t* zathura_document_open(zathura_t* zathura,
plugin_manager, const char* path, const char *uri, const char* password, zathura_error_t* const char* path, const char *uri, const char* password, zathura_error_t*
error); error);
/** /**

View file

@ -148,7 +148,7 @@ typedef struct zathura_image_s
typedef enum zathura_link_type_e typedef enum zathura_link_type_e
{ {
ZATHURA_LINK_INVALID, /**< Invalid type */ ZATHURA_LINK_INVALID, /**< Invalid type */
ZATHURA_LINK_NONE, /**< No action */ ZATHURA_LINK_NONE, /**< No action */
ZATHURA_LINK_GOTO_DEST, /**< Links to a page */ ZATHURA_LINK_GOTO_DEST, /**< Links to a page */
ZATHURA_LINK_GOTO_REMOTE, /**< Links to a page */ ZATHURA_LINK_GOTO_REMOTE, /**< Links to a page */
ZATHURA_LINK_URI, /**< Links to an external source */ ZATHURA_LINK_URI, /**< Links to an external source */
@ -158,15 +158,15 @@ typedef enum zathura_link_type_e
typedef enum zathura_link_destination_type_e typedef enum zathura_link_destination_type_e
{ {
ZATHURA_LINK_DESTINATION_UNKNOWN, ZATHURA_LINK_DESTINATION_UNKNOWN,
ZATHURA_LINK_DESTINATION_XYZ, ZATHURA_LINK_DESTINATION_XYZ,
ZATHURA_LINK_DESTINATION_FIT, ZATHURA_LINK_DESTINATION_FIT,
ZATHURA_LINK_DESTINATION_FITH, ZATHURA_LINK_DESTINATION_FITH,
ZATHURA_LINK_DESTINATION_FITV, ZATHURA_LINK_DESTINATION_FITV,
ZATHURA_LINK_DESTINATION_FITR, ZATHURA_LINK_DESTINATION_FITR,
ZATHURA_LINK_DESTINATION_FITB, ZATHURA_LINK_DESTINATION_FITB,
ZATHURA_LINK_DESTINATION_FITBH, ZATHURA_LINK_DESTINATION_FITBH,
ZATHURA_LINK_DESTINATION_FITBV ZATHURA_LINK_DESTINATION_FITBV
} zathura_link_destination_type_t; } zathura_link_destination_type_t;
typedef struct zathura_link_target_s typedef struct zathura_link_target_s
@ -255,4 +255,9 @@ zathura_document_information_entry_new(zathura_document_information_type_t
*/ */
void zathura_document_information_entry_free(zathura_document_information_entry_t* entry); void zathura_document_information_entry_free(zathura_document_information_entry_t* entry);
/**
* Context for MIME type detection
*/
typedef struct zathura_content_type_context_s zathura_content_type_context_t;
#endif // TYPES_H #endif // TYPES_H

View file

@ -52,12 +52,14 @@ file_valid_extension(zathura_t* zathura, const char* path)
return false; return false;
} }
const gchar* content_type = guess_content_type(path); const gchar* content_type =
zathura_content_type_guess(zathura->content_type_context, path);
if (content_type == NULL) { if (content_type == NULL) {
return false; return false;
} }
zathura_plugin_t* plugin = zathura_plugin_manager_get_plugin(zathura->plugins.manager, content_type); zathura_plugin_t* plugin =
zathura_plugin_manager_get_plugin(zathura->plugins.manager, content_type);
g_free((void*)content_type); g_free((void*)content_type);
return (plugin == NULL) ? false : true; return (plugin == NULL) ? false : true;

View file

@ -43,6 +43,7 @@
#include "dbus-interface.h" #include "dbus-interface.h"
#include "css-definitions.h" #include "css-definitions.h"
#include "synctex.h" #include "synctex.h"
#include "content-type.h"
typedef struct zathura_document_info_s { typedef struct zathura_document_info_s {
zathura_t* zathura; zathura_t* zathura;
@ -103,6 +104,9 @@ zathura_create(void)
zathura->signals.sigterm = g_unix_signal_add(SIGTERM, zathura_signal_sigterm, zathura); zathura->signals.sigterm = g_unix_signal_add(SIGTERM, zathura_signal_sigterm, zathura);
#endif #endif
/* MIME type detection */
zathura->content_type_context = zathura_content_type_new();
zathura->ui.session->global.data = zathura; zathura->ui.session->global.data = zathura;
return zathura; return zathura;
@ -376,6 +380,9 @@ zathura_free(zathura_t* zathura)
document_close(zathura, false); document_close(zathura, false);
/* MIME type detection */
zathura_content_type_free(zathura->content_type_context);
#ifdef G_OS_UNIX #ifdef G_OS_UNIX
if (zathura->signals.sigterm > 0) { if (zathura->signals.sigterm > 0) {
g_source_remove(zathura->signals.sigterm); g_source_remove(zathura->signals.sigterm);
@ -760,7 +767,7 @@ document_open(zathura_t* zathura, const char* path, const char* uri, const char*
gchar* file_uri = NULL; gchar* file_uri = NULL;
zathura_error_t error = ZATHURA_ERROR_OK; zathura_error_t error = ZATHURA_ERROR_OK;
zathura_document_t* document = zathura_document_open(zathura->plugins.manager, path, uri, password, &error); zathura_document_t* document = zathura_document_open(zathura, path, uri, password, &error);
if (document == NULL) { if (document == NULL) {
if (error == ZATHURA_ERROR_INVALID_PASSWORD) { if (error == ZATHURA_ERROR_INVALID_PASSWORD) {

View file

@ -6,7 +6,9 @@
#include <stdbool.h> #include <stdbool.h>
#include <girara/types.h> #include <girara/types.h>
#include <gtk/gtk.h> #include <gtk/gtk.h>
#ifdef GDK_WINDOWING_X11
#include <gtk/gtkx.h> #include <gtk/gtkx.h>
#endif
#include "macros.h" #include "macros.h"
#include "types.h" #include "types.h"
@ -222,6 +224,11 @@ struct zathura_s
double zoom; double zoom;
} toggle_presentation_mode; } toggle_presentation_mode;
} shortcut; } shortcut;
/**
* Context for MIME type detection
*/
zathura_content_type_context_t* content_type_context;
}; };
/** /**