Dunk: > Hi, > Please see latest version of the patch, I tried testing with valgrind under > Alpine Linux in a Docker container and it didn?t report any errors. But a > ?postfix stop? exits postfix/valgrind without a summary. > > Duncan
Valgrind always produces output. If you don't get any then your test is invalid. Can you test this with: $ cd src/global $ make mail_dict cd ../.. $ sh postfix-env.sh valgrind --tool=memcheck src/global/mail_dict redis:/path/to/file read <<'EOF' get something-that-exists get something-that-does-not-exist EOF I will wait for real valgrind output before I look at the code. Wietse > > > On 27 Feb 2021, at 23:20, Wietse Venema <wie...@porcupine.org> wrote: > > > > ?Duncan Bellamy: > >> Hi, > >> > >> This patch is based on the original code by Titus Jose on GitHub, I > >> updated it to work with the development branch and have added some > >> documentation. > > > > Thanks. I have a few suggestions regarding memory leaks, data > > owbership, and testing. > > > > 115 static const char *dict_redis_lookup(DICT *dict, const char *name) > > 116 { > > ... > > 124 result = vstring_alloc(10); > > 125 VSTRING_RESET(result); /* Not needed -- WZV */ > > 126 VSTRING_TERMINATE(result); /* Not needed -- WZV */ > > > > I think that you're leaking one VSTRING per dict_redis_lookup() > > call. With the Postfix DICT variants, a dictionary owns the lookup > > result (no multi-threading), it is therefore OK to make the result > > a member of the DICT_REDIS instance. > > > > 141 if(dict_redis->c) { > > 142 reply = redisCommand(dict_redis->c,"GET > > %s%s",dict_redis->prefix 142 ,name); > > 143 } > > 144 else { /* Can't happen - WZV */ > > 145 dict->error = DICT_ERR_CONFIG; > > 146 } > > > > The code in dict_redis_open guarantees that a DICT_REDIS instance > > never has null DICT_REDIS.c member. You can delete the test and the > > unreachable branch. > > > > 172 DICT *dict_redis_open(const char *name, int open_flags, int dict_flags > > 172 ) > > 173 { > > ... > > 193 c = redisConnect(dict_redis->host,dict_redis->port); > > 194 if(c->err) { /* Redirect to surrogate -- WZV */ > > 195 msg_fatal("%s:%s: Cannot connect to Redis server %s: %s\n", > > 196 DICT_TYPE_REDIS, name, dict_redis->host, c->errstr); > > > > For consistency with other code, this should > > > > 1) Free the 'c' > > 2) Set dict_redis->c to null and invoke dict_close(&dict_redis) > > 3) Return dict_surrogate(DICT_TYPE_REDIS, name, ...) > > > > 206 static void dict_redis_close(DICT *dict) > > 207 { > > 208 DICT_REDIS *dict_redis = (DICT_REDIS *) dict; > > > > This function leaks the dict_redis->c pointer. > > Here, call free dict_redis->c if it is not null. > > > > Be sure to test this under VALGRIND. See Makefile > > for how to build and run mail_dict.c. > > > > Wietse