darknet rnn valid: trailing -seed without a value causes NULL seed dereference (strlen) in valid_char_rnn
Summary
With darknet rnn valid cfg/rnn.cfg -file <value> -seed (a trailing -seed with no value), find_char_arg() (src/utils.c:163-175) returns NULL instead of the default "\n\n": the preceding -file <value> has already been consumed by two del_arg() calls, pushing -seed into argv[4], and its value slot argv[5] is the NULL sentinel left by del_arg; moreover argc is passed by value and never decremented (utils.c:113-118), so the i < argc-1 check is ineffective. The NULL is passed straight through run_char_rnn() (examples/rnn.c:526, 537) into valid_char_rnn(), which executes strlen(seed) at rnn.c:446 → SIGSEGV. A standalone trailing -seed (without a preceding -file) does not trigger the bug — in that case -seed sits at argv[4], i == argc-1 does not satisfy i < argc-1, and the default value is returned.
Reproduction
# Build (in the darknet-master/ directory; CPU-only build, zero external dependencies):
# make -j$(nproc) DEBUG=1 # DEBUG=1 adds -O0 -g; the default DEBUG=0 build crashes the same way
#
# Run:
./darknet rnn valid cfg/rnn.cfg -file data/shakespeare.txt -seed < /dev/nullNote: the -file value does not need to exist (the valid subcommand never opens the file, it only consumes two argument slots); weights are not loaded (weights=(argc>4)?argv[4]:0 = NULL is a valid usage), so no weights need to be downloaded.
Source
/* src/utils.c:113-118 — shift left + set the trailing slot to a NULL sentinel;
* argc is passed by value and never decremented */
void del_arg(int argc, char **argv, int index)
{
int i;
for(i = index; i < argc-1; ++i) argv[i] = argv[i+1];
argv[i] = 0;
}
/* src/utils.c:163-175 — no NULL guard on the value slot */
char *find_char_arg(int argc, char **argv, char *arg, char *def)
{
int i;
for(i = 0; i < argc-1; ++i){
if(!argv[i]) continue;
if(0==strcmp(argv[i], arg)){
def = argv[i+1]; /* the value slot may be the NULL sentinel left by del_arg */
del_arg(argc, argv, i);
del_arg(argc, argv, i);
break;
}
}
return def; /* returns NULL */
}/* examples/rnn.c:526 — reads -seed; 537 — passes it straight through */
char *seed = find_char_arg(argc, argv, "-seed", "\n\n"); /* line 526 */
...
else if(0==strcmp(argv[2], "valid")) valid_char_rnn(cfg, weights, seed); /* line 537 */
/* examples/rnn.c:446 — sink */
int len = strlen(seed); /* crashes when seed==NULL */Result
Source: pjreddie/darknet