]> Kevux Git Server - rit/commitdiff
config: clarify memory ownership in `git_config_string()`
authorPatrick Steinhardt <ps@pks.im>
Mon, 27 May 2024 11:46:39 +0000 (13:46 +0200)
committerJunio C Hamano <gitster@pobox.com>
Mon, 27 May 2024 18:20:00 +0000 (11:20 -0700)
The out parameter of `git_config_string()` is a `const char **` even
though we transfer ownership of memory to the caller. This is quite
misleading and has led to many memory leaks all over the place. Adapt
the parameter to instead be `char **`.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
30 files changed:
alias.c
attr.c
attr.h
builtin/commit.c
builtin/log.c
builtin/merge.c
builtin/rebase.c
builtin/receive-pack.c
builtin/repack.c
config.c
config.h
convert.c
delta-islands.c
diff.c
environment.c
environment.h
gpg-interface.c
http.c
imap-send.c
mailmap.c
mailmap.h
merge-ll.c
pager.c
pretty.c
promisor-remote.h
remote.c
remote.h
sequencer.c
upload-pack.c
userdiff.h

diff --git a/alias.c b/alias.c
index 5a238f2..269892c 100644 (file)
--- a/alias.c
+++ b/alias.c
@@ -22,7 +22,7 @@ static int config_alias_cb(const char *key, const char *value,
 
        if (data->alias) {
                if (!strcasecmp(p, data->alias))
-                       return git_config_string((const char **)&data->v,
+                       return git_config_string(&data->v,
                                                 key, value);
        } else if (data->list) {
                string_list_append(data->list, p);
diff --git a/attr.c b/attr.c
index 33473bd..5607db2 100644 (file)
--- a/attr.c
+++ b/attr.c
@@ -25,7 +25,7 @@
 #include "tree-walk.h"
 #include "object-name.h"
 
-const char *git_attr_tree;
+char *git_attr_tree;
 
 const char git_attr__true[] = "(builtin)true";
 const char git_attr__false[] = "\0(builtin)false";
diff --git a/attr.h b/attr.h
index 127998a..e7cc318 100644 (file)
--- a/attr.h
+++ b/attr.h
@@ -236,6 +236,6 @@ const char *git_attr_global_file(void);
 /* Return whether the system gitattributes file is enabled and should be used. */
 int git_attr_system_is_enabled(void);
 
-extern const char *git_attr_tree;
+extern char *git_attr_tree;
 
 #endif /* ATTR_H */
index 1cc88e9..f53e7e8 100644 (file)
@@ -133,7 +133,7 @@ static struct strvec trailer_args = STRVEC_INIT;
  * is specified explicitly.
  */
 static enum commit_msg_cleanup_mode cleanup_mode;
-static const char *cleanup_arg;
+static char *cleanup_arg;
 
 static enum commit_whence whence;
 static int use_editor = 1, include_status = 1;
index 890bf0c..517d798 100644 (file)
@@ -582,11 +582,11 @@ static int git_log_config(const char *var, const char *value,
 
        if (!strcmp(var, "format.pretty")) {
                FREE_AND_NULL(cfg->fmt_pretty);
-               return git_config_string((const char **) &cfg->fmt_pretty, var, value);
+               return git_config_string(&cfg->fmt_pretty, var, value);
        }
        if (!strcmp(var, "format.subjectprefix")) {
                FREE_AND_NULL(cfg->fmt_patch_subject_prefix);
-               return git_config_string((const char **) &cfg->fmt_patch_subject_prefix, var, value);
+               return git_config_string(&cfg->fmt_patch_subject_prefix, var, value);
        }
        if (!strcmp(var, "format.filenamemaxlength")) {
                cfg->fmt_patch_name_max = git_config_int(var, value, ctx->kvi);
@@ -602,7 +602,7 @@ static int git_log_config(const char *var, const char *value,
        }
        if (!strcmp(var, "log.date")) {
                FREE_AND_NULL(cfg->default_date_mode);
-               return git_config_string((const char **) &cfg->default_date_mode, var, value);
+               return git_config_string(&cfg->default_date_mode, var, value);
        }
        if (!strcmp(var, "log.decorate")) {
                cfg->decoration_style = parse_decoration_style(value);
@@ -1076,7 +1076,7 @@ static int git_format_config(const char *var, const char *value,
        }
        if (!strcmp(var, "format.suffix")) {
                FREE_AND_NULL(cfg->fmt_patch_suffix);
-               return git_config_string((const char **) &cfg->fmt_patch_suffix, var, value);
+               return git_config_string(&cfg->fmt_patch_suffix, var, value);
        }
        if (!strcmp(var, "format.to")) {
                if (!value)
@@ -1133,7 +1133,7 @@ static int git_format_config(const char *var, const char *value,
        }
        if (!strcmp(var, "format.signature")) {
                FREE_AND_NULL(cfg->signature);
-               return git_config_string((const char **) &cfg->signature, var, value);
+               return git_config_string(&cfg->signature, var, value);
        }
        if (!strcmp(var, "format.signaturefile")) {
                FREE_AND_NULL(cfg->signature_file);
@@ -1149,7 +1149,7 @@ static int git_format_config(const char *var, const char *value,
        }
        if (!strcmp(var, "format.outputdirectory")) {
                FREE_AND_NULL(cfg->config_output_directory);
-               return git_config_string((const char **) &cfg->config_output_directory, var, value);
+               return git_config_string(&cfg->config_output_directory, var, value);
        }
        if (!strcmp(var, "format.useautobase")) {
                if (value && !strcasecmp(value, "whenAble")) {
index e4bd65e..daed2d4 100644 (file)
@@ -100,7 +100,7 @@ static struct strategy all_strategy[] = {
        { "subtree",    NO_FAST_FORWARD | NO_TRIVIAL },
 };
 
-static const char *pull_twohead, *pull_octopus;
+static char *pull_twohead, *pull_octopus;
 
 enum ff_type {
        FF_NO,
@@ -110,7 +110,7 @@ enum ff_type {
 
 static enum ff_type fast_forward = FF_ALLOW;
 
-static const char *cleanup_arg;
+static char *cleanup_arg;
 static enum commit_msg_cleanup_mode cleanup_mode;
 
 static int option_parse_message(const struct option *opt,
index 0466d94..14d4f0a 100644 (file)
@@ -83,7 +83,7 @@ static const char *action_names[] = {
 struct rebase_options {
        enum rebase_type type;
        enum empty_type empty;
-       const char *default_backend;
+       char *default_backend;
        const char *state_dir;
        struct commit *upstream;
        const char *upstream_name;
index 56228ad..01c1f04 100644 (file)
@@ -88,7 +88,7 @@ static struct strbuf push_cert = STRBUF_INIT;
 static struct object_id push_cert_oid;
 static struct signature_check sigcheck;
 static const char *push_cert_nonce;
-static const char *cert_nonce_seed;
+static char *cert_nonce_seed;
 static struct strvec hidden_refs = STRVEC_INIT;
 
 static const char *NONCE_UNSOLICITED = "UNSOLICITED";
index 43491a4..e40dcea 100644 (file)
@@ -48,10 +48,10 @@ static const char incremental_bitmap_conflict_error[] = N_(
 );
 
 struct pack_objects_args {
-       const char *window;
-       const char *window_memory;
-       const char *depth;
-       const char *threads;
+       char *window;
+       char *window_memory;
+       char *depth;
+       char *threads;
        unsigned long max_pack_size;
        int no_reuse_delta;
        int no_reuse_object;
index f910104..da52a7f 100644 (file)
--- a/config.c
+++ b/config.c
@@ -1338,7 +1338,7 @@ int git_config_bool(const char *name, const char *value)
        return v;
 }
 
-int git_config_string(const char **dest, const char *var, const char *value)
+int git_config_string(char **dest, const char *var, const char *value)
 {
        if (!value)
                return config_error_nonbool(var);
@@ -1566,7 +1566,7 @@ static int git_default_core_config(const char *var, const char *value,
 
        if (!strcmp(var, "core.checkroundtripencoding")) {
                FREE_AND_NULL(check_roundtrip_encoding);
-               return git_config_string((const char **) &check_roundtrip_encoding, var, value);
+               return git_config_string(&check_roundtrip_encoding, var, value);
        }
 
        if (!strcmp(var, "core.notesref")) {
@@ -2418,7 +2418,7 @@ int git_configset_get_string(struct config_set *set, const char *key, char **des
 {
        const char *value;
        if (!git_configset_get_value(set, key, &value, NULL))
-               return git_config_string((const char **)dest, key, value);
+               return git_config_string(dest, key, value);
        else
                return 1;
 }
index b3103bb..2d2e22e 100644 (file)
--- a/config.h
+++ b/config.h
@@ -280,7 +280,7 @@ int git_config_bool(const char *, const char *);
  * Allocates and copies the value string into the `dest` parameter; if no
  * string is given, prints an error message and returns -1.
  */
-int git_config_string(const char **, const char *, const char *);
+int git_config_string(char **, const char *, const char *);
 
 /**
  * Similar to `git_config_string`, but expands `~` or `~user` into the
index 03c3c52..f2b9f01 100644 (file)
--- a/convert.c
+++ b/convert.c
@@ -981,9 +981,9 @@ done:
 static struct convert_driver {
        const char *name;
        struct convert_driver *next;
-       const char *smudge;
-       const char *clean;
-       const char *process;
+       char *smudge;
+       char *clean;
+       char *process;
        int required;
 } *user_convert, **user_convert_tail;
 
index 4ac3c10..89d51b7 100644 (file)
@@ -313,7 +313,7 @@ struct island_load_data {
        size_t nr;
        size_t alloc;
 };
-static const char *core_island_name;
+static char *core_island_name;
 
 static void free_config_regexes(struct island_load_data *ild)
 {
diff --git a/diff.c b/diff.c
index 679ef47..e70301d 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -56,8 +56,8 @@ static int diff_color_moved_default;
 static int diff_color_moved_ws_default;
 static int diff_context_default = 3;
 static int diff_interhunk_context_default;
-static const char *diff_word_regex_cfg;
-static const char *external_diff_cmd_cfg;
+static char *diff_word_regex_cfg;
+static char *external_diff_cmd_cfg;
 static char *diff_order_file_cfg;
 int diff_auto_refresh_index = 1;
 static int diff_mnemonic_prefix;
@@ -412,11 +412,11 @@ int git_diff_ui_config(const char *var, const char *value,
        }
        if (!strcmp(var, "diff.srcprefix")) {
                FREE_AND_NULL(diff_src_prefix);
-               return git_config_string((const char **) &diff_src_prefix, var, value);
+               return git_config_string(&diff_src_prefix, var, value);
        }
        if (!strcmp(var, "diff.dstprefix")) {
                FREE_AND_NULL(diff_dst_prefix);
-               return git_config_string((const char **) &diff_dst_prefix, var, value);
+               return git_config_string(&diff_dst_prefix, var, value);
        }
        if (!strcmp(var, "diff.relative")) {
                diff_relative = git_config_bool(var, value);
index ab69565..701d515 100644 (file)
@@ -42,8 +42,8 @@ int is_bare_repository_cfg = -1; /* unspecified */
 int warn_ambiguous_refs = 1;
 int warn_on_object_refname_ambiguity = 1;
 int repository_format_precious_objects;
-const char *git_commit_encoding;
-const char *git_log_output_encoding;
+char *git_commit_encoding;
+char *git_log_output_encoding;
 char *apply_default_whitespace;
 char *apply_default_ignorewhitespace;
 char *git_attributes_file;
@@ -58,8 +58,8 @@ size_t packed_git_window_size = DEFAULT_PACKED_GIT_WINDOW_SIZE;
 size_t packed_git_limit = DEFAULT_PACKED_GIT_LIMIT;
 size_t delta_base_cache_limit = 96 * 1024 * 1024;
 unsigned long big_file_threshold = 512 * 1024 * 1024;
-const char *editor_program;
-const char *askpass_program;
+char *editor_program;
+char *askpass_program;
 char *excludes_file;
 enum auto_crlf auto_crlf = AUTO_CRLF_FALSE;
 enum eol core_eol = EOL_UNSET;
index be1b88a..e9f01d4 100644 (file)
@@ -224,11 +224,11 @@ int odb_pack_keep(const char *name);
 const char *get_log_output_encoding(void);
 const char *get_commit_output_encoding(void);
 
-extern const char *git_commit_encoding;
-extern const char *git_log_output_encoding;
+extern char *git_commit_encoding;
+extern char *git_log_output_encoding;
 
-extern const char *editor_program;
-extern const char *askpass_program;
+extern char *editor_program;
+extern char *askpass_program;
 extern char *excludes_file;
 
 /*
index 2b50ed0..5193223 100644 (file)
@@ -27,14 +27,14 @@ static void gpg_interface_lazy_init(void)
 }
 
 static char *configured_signing_key;
-static const char *ssh_default_key_command;
+static char *ssh_default_key_command;
 static char *ssh_allowed_signers;
 static char *ssh_revocation_file;
 static enum signature_trust_level configured_min_trust_level = TRUST_UNDEFINED;
 
 struct gpg_format {
        const char *name;
-       const char *program;
+       char *program;
        const char **verify_args;
        const char **sigs;
        int (*verify_signed_buffer)(struct signature_check *sigc,
diff --git a/http.c b/http.c
index fa3ea87..67cc47d 100644 (file)
--- a/http.c
+++ b/http.c
@@ -38,11 +38,11 @@ char curl_errorstr[CURL_ERROR_SIZE];
 
 static int curl_ssl_verify = -1;
 static int curl_ssl_try;
-static const char *curl_http_version = NULL;
+static char *curl_http_version;
 static char *ssl_cert;
 static char *ssl_cert_type;
-static const char *ssl_cipherlist;
-static const char *ssl_version;
+static char *ssl_cipherlist;
+static char *ssl_version;
 static struct {
        const char *name;
        long ssl_version;
@@ -95,7 +95,7 @@ static struct {
         */
 };
 #ifdef CURLGSSAPI_DELEGATION_FLAG
-static const char *curl_deleg;
+static char *curl_deleg;
 static struct {
        const char *name;
        long curl_deleg_param;
@@ -383,11 +383,11 @@ static int http_options(const char *var, const char *value,
        if (!strcmp("http.sslcert", var))
                return git_config_pathname(&ssl_cert, var, value);
        if (!strcmp("http.sslcerttype", var))
-               return git_config_string((const char **)&ssl_cert_type, var, value);
+               return git_config_string(&ssl_cert_type, var, value);
        if (!strcmp("http.sslkey", var))
                return git_config_pathname(&ssl_key, var, value);
        if (!strcmp("http.sslkeytype", var))
-               return git_config_string((const char **)&ssl_key_type, var, value);
+               return git_config_string(&ssl_key_type, var, value);
        if (!strcmp("http.sslcapath", var))
                return git_config_pathname(&ssl_capath, var, value);
        if (!strcmp("http.sslcainfo", var))
@@ -440,19 +440,19 @@ static int http_options(const char *var, const char *value,
                return 0;
        }
        if (!strcmp("http.proxy", var))
-               return git_config_string((const char **)&curl_http_proxy, var, value);
+               return git_config_string(&curl_http_proxy, var, value);
 
        if (!strcmp("http.proxyauthmethod", var))
-               return git_config_string((const char **)&http_proxy_authmethod, var, value);
+               return git_config_string(&http_proxy_authmethod, var, value);
 
        if (!strcmp("http.proxysslcert", var))
-               return git_config_string((const char **)&http_proxy_ssl_cert, var, value);
+               return git_config_string(&http_proxy_ssl_cert, var, value);
 
        if (!strcmp("http.proxysslkey", var))
-               return git_config_string((const char **)&http_proxy_ssl_key, var, value);
+               return git_config_string(&http_proxy_ssl_key, var, value);
 
        if (!strcmp("http.proxysslcainfo", var))
-               return git_config_string((const char **)&http_proxy_ssl_ca_info, var, value);
+               return git_config_string(&http_proxy_ssl_ca_info, var, value);
 
        if (!strcmp("http.proxysslcertpasswordprotected", var)) {
                proxy_ssl_cert_password_required = git_config_bool(var, value);
@@ -476,7 +476,7 @@ static int http_options(const char *var, const char *value,
        }
 
        if (!strcmp("http.useragent", var))
-               return git_config_string((const char **)&user_agent, var, value);
+               return git_config_string(&user_agent, var, value);
 
        if (!strcmp("http.emptyauth", var)) {
                if (value && !strcmp("auto", value))
index c0130d0..a5d1510 100644 (file)
@@ -70,16 +70,16 @@ static char *next_arg(char **);
 
 struct imap_server_conf {
        const char *name;
-       const char *tunnel;
-       const char *host;
+       char *tunnel;
+       char *host;
        int port;
-       const char *folder;
-       const char *user;
-       const char *pass;
+       char *folder;
+       char *user;
+       char *pass;
        int use_ssl;
        int ssl_verify;
        int use_html;
-       const char *auth_method;
+       char *auth_method;
 };
 
 static struct imap_server_conf server = {
index 044466b..b2efe29 100644 (file)
--- a/mailmap.c
+++ b/mailmap.c
@@ -7,7 +7,7 @@
 #include "setup.h"
 
 char *git_mailmap_file;
-const char *git_mailmap_blob;
+char *git_mailmap_blob;
 
 struct mailmap_info {
        char *name;
index 429a760..cbda9bc 100644 (file)
--- a/mailmap.h
+++ b/mailmap.h
@@ -4,7 +4,7 @@
 struct string_list;
 
 extern char *git_mailmap_file;
-extern const char *git_mailmap_blob;
+extern char *git_mailmap_blob;
 
 int read_mailmap(struct string_list *map);
 void clear_mailmap(struct string_list *map);
index bf1077a..e29b15f 100644 (file)
@@ -27,9 +27,9 @@ typedef enum ll_merge_result (*ll_merge_fn)(const struct ll_merge_driver *,
 
 struct ll_merge_driver {
        const char *name;
-       const char *description;
+       char *description;
        ll_merge_fn fn;
-       const char *recursive;
+       char *recursive;
        struct ll_merge_driver *next;
        char *cmdline;
 };
@@ -268,7 +268,7 @@ static enum ll_merge_result ll_ext_merge(const struct ll_merge_driver *fn,
  * merge.default and merge.driver configuration items
  */
 static struct ll_merge_driver *ll_user_merge, **ll_user_merge_tail;
-static const char *default_ll_merge;
+static char *default_ll_merge;
 
 static int read_merge_config(const char *var, const char *value,
                             const struct config_context *ctx UNUSED,
diff --git a/pager.c b/pager.c
index b8822a9..e9e121d 100644 (file)
--- a/pager.c
+++ b/pager.c
@@ -13,7 +13,7 @@ int pager_use_color = 1;
 #endif
 
 static struct child_process pager_process;
-static const char *pager_program;
+static char *pager_program;
 
 /* Is the value coming back from term_columns() just a guess? */
 static int term_columns_guessed;
index 7ead078..22a8150 100644 (file)
--- a/pretty.c
+++ b/pretty.c
@@ -62,7 +62,7 @@ static int git_pretty_formats_config(const char *var, const char *value,
 {
        struct cmt_fmt_map *commit_format = NULL;
        const char *name;
-       const char *fmt;
+       char *fmt;
        int i;
 
        if (!skip_prefix(var, "pretty.", &name))
@@ -93,13 +93,17 @@ static int git_pretty_formats_config(const char *var, const char *value,
        if (git_config_string(&fmt, var, value))
                return -1;
 
-       if (skip_prefix(fmt, "format:", &fmt))
+       if (skip_prefix(fmt, "format:", &commit_format->user_format)) {
                commit_format->is_tformat = 0;
-       else if (skip_prefix(fmt, "tformat:", &fmt) || strchr(fmt, '%'))
+       } else if (skip_prefix(fmt, "tformat:", &commit_format->user_format)) {
                commit_format->is_tformat = 1;
-       else
+       } else if (strchr(fmt, '%')) {
+               commit_format->is_tformat = 1;
+               commit_format->user_format = fmt;
+       } else {
                commit_format->is_alias = 1;
-       commit_format->user_format = fmt;
+               commit_format->user_format = fmt;
+       }
 
        return 0;
 }
index 2cb9eda..88cb599 100644 (file)
@@ -13,7 +13,7 @@ struct object_id;
  */
 struct promisor_remote {
        struct promisor_remote *next;
-       const char *partial_clone_filter;
+       char *partial_clone_filter;
        const char name[FLEX_ARRAY];
 };
 
index ec8c158..d319f28 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -428,29 +428,29 @@ static int handle_config(const char *key, const char *value,
        else if (!strcmp(subkey, "prunetags"))
                remote->prune_tags = git_config_bool(key, value);
        else if (!strcmp(subkey, "url")) {
-               const char *v;
+               char *v;
                if (git_config_string(&v, key, value))
                        return -1;
                add_url(remote, v);
        } else if (!strcmp(subkey, "pushurl")) {
-               const char *v;
+               char *v;
                if (git_config_string(&v, key, value))
                        return -1;
                add_pushurl(remote, v);
        } else if (!strcmp(subkey, "push")) {
-               const char *v;
+               char *v;
                if (git_config_string(&v, key, value))
                        return -1;
                refspec_append(&remote->push, v);
-               free((char *)v);
+               free(v);
        } else if (!strcmp(subkey, "fetch")) {
-               const char *v;
+               char *v;
                if (git_config_string(&v, key, value))
                        return -1;
                refspec_append(&remote->fetch, v);
-               free((char *)v);
+               free(v);
        } else if (!strcmp(subkey, "receivepack")) {
-               const char *v;
+               char *v;
                if (git_config_string(&v, key, value))
                        return -1;
                if (!remote->receivepack)
@@ -458,7 +458,7 @@ static int handle_config(const char *key, const char *value,
                else
                        error(_("more than one receivepack given, using the first"));
        } else if (!strcmp(subkey, "uploadpack")) {
-               const char *v;
+               char *v;
                if (git_config_string(&v, key, value))
                        return -1;
                if (!remote->uploadpack)
@@ -471,10 +471,10 @@ static int handle_config(const char *key, const char *value,
                else if (!strcmp(value, "--tags"))
                        remote->fetch_tags = 2;
        } else if (!strcmp(subkey, "proxy")) {
-               return git_config_string((const char **)&remote->http_proxy,
+               return git_config_string(&remote->http_proxy,
                                         key, value);
        } else if (!strcmp(subkey, "proxyauthmethod")) {
-               return git_config_string((const char **)&remote->http_proxy_authmethod,
+               return git_config_string(&remote->http_proxy_authmethod,
                                         key, value);
        } else if (!strcmp(subkey, "vcs")) {
                return git_config_string(&remote->foreign_vcs, key, value);
index dfd4837..e8c6655 100644 (file)
--- a/remote.h
+++ b/remote.h
@@ -46,7 +46,7 @@ struct remote_state {
        struct hashmap branches_hash;
 
        struct branch *current_branch;
-       const char *pushremote_name;
+       char *pushremote_name;
 
        struct rewrites rewrites;
        struct rewrites rewrites_push;
@@ -65,7 +65,7 @@ struct remote {
 
        int origin, configured_in_repo;
 
-       const char *foreign_vcs;
+       char *foreign_vcs;
 
        /* An array of all of the url_nr URLs configured for the remote */
        const char **url;
@@ -309,9 +309,9 @@ struct branch {
        const char *refname;
 
        /* The name of the remote listed in the configuration. */
-       const char *remote_name;
+       char *remote_name;
 
-       const char *pushremote_name;
+       char *pushremote_name;
 
        /* An array of the "merge" lines in the configuration. */
        const char **merge_name;
index dbd60d7..3c81ef9 100644 (file)
@@ -306,7 +306,7 @@ static int git_sequencer_config(const char *k, const char *v,
        }
 
        if (!opts->default_strategy && !strcmp(k, "pull.twohead")) {
-               int ret = git_config_string((const char**)&opts->default_strategy, k, v);
+               int ret = git_config_string(&opts->default_strategy, k, v);
                if (ret == 0) {
                        /*
                         * pull.twohead is allowed to be multi-valued; we only
index 8fbd138..5801eb2 100644 (file)
@@ -94,7 +94,7 @@ struct upload_pack_data {
 
        struct packet_writer writer;
 
-       const char *pack_objects_hook;
+       char *pack_objects_hook;
 
        unsigned stateless_rpc : 1;                             /* v0 only */
        unsigned no_done : 1;                                   /* v0 only */
index d726804..cc8e5ab 100644 (file)
@@ -7,19 +7,19 @@ struct index_state;
 struct repository;
 
 struct userdiff_funcname {
-       const char *pattern;
+       char *pattern;
        int cflags;
 };
 
 struct userdiff_driver {
        const char *name;
-       const char *external;
-       const char *algorithm;
+       char *external;
+       char *algorithm;
        int binary;
        struct userdiff_funcname funcname;
-       const char *word_regex;
-       const char *word_regex_multi_byte;
-       const char *textconv;
+       char *word_regex;
+       char *word_regex_multi_byte;
+       char *textconv;
        struct notes_cache *textconv_cache;
        int textconv_want_cache;
 };