luke-jr/bfgminer

Memory leak in _load_default_configs()

lcatro opened this issue · 6 comments

ASAN Detect :

The reason is load_config() return json_error by malloc() ,but _load_default_configs() never free this return .

Fix :

static
bool _load_default_configs(const char * const filepath, void * __maybe_unused userp)
{
        bool * const found_defcfg_p = userp;
        *found_defcfg_p = true;

        char* buffer = load_config(filepath, NULL);

        if (NULL != buffer)
                free(buffer);

        // Regardless of status of loading the config file, we should continue loading other defaults
        return false;
}

Pretty minor since it is just a small leak during startup in an error condition.

Unfortunately, fixing it isn't that simple: you can't free the other return values, and ccan opt needs to handle the return value properly as well.

@luke-jr Oh ,I'm forget something .parse_config() will return a buffer ,and this is a static buffer .I change this buffer alloc by malloc() .

@luke-jr

this is my fix code at parse_config()

static char *parse_config(json_t *config, bool fileconf, int * const fileconf_load_p)
{
        //static char err_buf[200];
        struct opt_table *opt;
        json_t *val;

        if (fileconf && !*fileconf_load_p)
                *fileconf_load_p = 1;

        for (opt = opt_config_table; opt->type != OPT_END; opt++) {
                char *p, *name, *sp;

                /* We don't handle subtables. */
                assert(!(opt->type & OPT_SUBTABLE));

                if (!opt->names)
                        continue;

                /* Pull apart the option name(s). */
                name = strdup(opt->names);
                for (p = strtok_r(name, "|", &sp); p; p = strtok_r(NULL, "|", &sp)) {
                        char *err = "Invalid value";

                        /* Ignore short options. */
                        if (p[1] != '-')
                                continue;

                        val = json_object_get(config, p+2);
                        if (!val)
                                continue;

                        if (opt->type & OPT_HASARG) {
                          if (json_is_string(val)) {
                                err = opt->cb_arg(json_string_value(val),
                                                  opt->u.arg);
                          } else if (json_is_number(val)) {
                                        char buf[256], *p, *q;
                                        snprintf(buf, 256, "%f", json_number_value(val));
                                        if ( (p = strchr(buf, '.')) ) {
                                                // Trim /\.0*$/ to work properly with integer-only arguments
                                                q = p;
                                                while (*(++q) == '0') {}
                                                if (*q == '\0')
                                                        *p = '\0';
                                        }
                                        err = opt->cb_arg(buf, opt->u.arg);
                          } else if (json_is_array(val)) {
                                int n, size = json_array_size(val);

                                err = NULL;
                                for (n = 0; n < size && !err; n++) {
                                        if (json_is_string(json_array_get(val, n)))
                                                err = opt->cb_arg(json_string_value(json_array_get(val, n)), opt->u.arg);
                                        else if (json_is_object(json_array_get(val, n)))
                                                err = parse_config(json_array_get(val, n), false, fileconf_load_p);
                                }
                          }
                        } else if (opt->type & OPT_NOARG) {
                                if (json_is_true(val))
                                        err = opt->cb(opt->u.arg);
                                else if (json_is_boolean(val)) {
                                        if (opt->cb == (void*)opt_set_bool)
                                                err = opt_set_invbool(opt->u.arg);
                                        else if (opt->cb == (void*)opt_set_invbool)
                                                err = opt_set_bool(opt->u.arg);
                                }
                        }

                        if (err) {
                                /* Allow invalid values to be in configuration
                                 * file, just skipping over them provided the
                                 * JSON is still valid after that. */
                                if (fileconf) {
                                        applog(LOG_ERR, "Invalid config option %s: %s", p, err);
                                        *fileconf_load_p = -1;
                                } else {
                                        char* err_buf = malloc(200);
                                        snprintf(err_buf, sizeof(err_buf), "Parsing JSON option %s: %s",
                                                p, err);
                                        free(name);
                                        return err_buf;
                                }
                        }
                }
                free(name);
        }

        val = json_object_get(config, JSON_INCLUDE_CONF);
        if (val && json_is_string(val))
                return load_config(json_string_value(val), NULL);

        return NULL;
}

This would be easier to review as a pull request...

@luke-jr I'm try to fuzzing bfgminer and fix more code at last mouth .now forget these codes where i rewrite .So sorry . :)

other little problem :

@coderxani My email is m4i1f0rt3st@sina.cn .Thanks for your share : )

Sending you an email now ..thanks