Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
hiredis
Commits
dd5fc264
Commit
dd5fc264
authored
Apr 21, 2011
by
Pieter Noordhuis
Browse files
Make command formatters gracefully abort when out of memory
parent
d4ebb60d
Changes
1
Hide whitespace changes
Inline
Side-by-side
hiredis.c
View file @
dd5fc264
...
...
@@ -652,59 +652,74 @@ static int intlen(int i) {
return
len
;
}
/* Helper function for redisvFormatCommand(). */
static
void
addArgument
(
sds
a
,
char
***
argv
,
int
*
argc
,
int
*
totlen
)
{
(
*
argc
)
++
;
if
((
*
argv
=
realloc
(
*
argv
,
sizeof
(
char
*
)
*
(
*
argc
)))
==
NULL
)
redisOOM
();
if
(
totlen
)
*
totlen
=
*
totlen
+
1
+
intlen
(
sdslen
(
a
))
+
2
+
sdslen
(
a
)
+
2
;
(
*
argv
)[(
*
argc
)
-
1
]
=
a
;
/* Helper that calculates the bulk length given a certain string length. */
static
size_t
bulklen
(
size_t
len
)
{
return
1
+
intlen
(
len
)
+
2
+
len
+
2
;
}
int
redisvFormatCommand
(
char
**
target
,
const
char
*
format
,
va_list
ap
)
{
size_t
size
;
const
char
*
arg
,
*
c
=
format
;
const
char
*
c
=
format
;
char
*
cmd
=
NULL
;
/* final command */
int
pos
;
/* position in final command */
sds
cur
rent
;
/* current argument */
sds
cur
arg
,
newarg
;
/* current argument */
int
touched
=
0
;
/* was the current argument touched? */
char
**
argv
=
NULL
;
int
argc
=
0
,
j
;
char
**
curargv
=
NULL
,
**
new
argv
=
NULL
;
int
argc
=
0
;
int
totlen
=
0
;
int
j
;
/* Abort if there is not target to set */
if
(
target
==
NULL
)
return
-
1
;
/* Build the command string accordingly to protocol */
current
=
sdsempty
();
curarg
=
sdsempty
();
if
(
curarg
==
NULL
)
return
-
1
;
while
(
*
c
!=
'\0'
)
{
if
(
*
c
!=
'%'
||
c
[
1
]
==
'\0'
)
{
if
(
*
c
==
' '
)
{
if
(
touched
)
{
addArgument
(
current
,
&
argv
,
&
argc
,
&
totlen
);
current
=
sdsempty
();
newargv
=
realloc
(
curargv
,
sizeof
(
char
*
)
*
(
argc
+
1
));
if
(
newargv
==
NULL
)
goto
err
;
curargv
=
newargv
;
curargv
[
argc
++
]
=
curarg
;
totlen
+=
bulklen
(
sdslen
(
curarg
));
/* curarg is put in argv so it can be overwritten. */
curarg
=
sdsempty
();
if
(
curarg
==
NULL
)
goto
err
;
touched
=
0
;
}
}
else
{
current
=
sdscatlen
(
current
,
c
,
1
);
newarg
=
sdscatlen
(
curarg
,
c
,
1
);
if
(
newarg
==
NULL
)
goto
err
;
curarg
=
newarg
;
touched
=
1
;
}
}
else
{
char
*
arg
;
size_t
size
;
/* Set newarg so it can be checked even if it is not touched. */
newarg
=
curarg
;
switch
(
c
[
1
])
{
case
's'
:
arg
=
va_arg
(
ap
,
char
*
);
size
=
strlen
(
arg
);
if
(
size
>
0
)
current
=
sdscatlen
(
cur
rent
,
arg
,
size
);
newarg
=
sdscatlen
(
cur
arg
,
arg
,
size
);
break
;
case
'b'
:
arg
=
va_arg
(
ap
,
char
*
);
size
=
va_arg
(
ap
,
size_t
);
if
(
size
>
0
)
current
=
sdscatlen
(
cur
rent
,
arg
,
size
);
newarg
=
sdscatlen
(
cur
arg
,
arg
,
size
);
break
;
case
'%'
:
current
=
sdscat
(
cur
rent
,
"%"
);
newarg
=
sdscat
(
cur
arg
,
"%"
);
break
;
default:
/* Try to detect printf format */
...
...
@@ -746,7 +761,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
memcpy
(
_format
,
c
,
_l
);
_format
[
_l
]
=
'\0'
;
va_copy
(
_cpy
,
ap
);
current
=
sdscatvprintf
(
cur
rent
,
_format
,
_cpy
);
newarg
=
sdscatvprintf
(
cur
arg
,
_format
,
_cpy
);
va_end
(
_cpy
);
/* Update current position (note: outer blocks
...
...
@@ -759,6 +774,10 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
va_arg
(
ap
,
void
);
}
}
if
(
newarg
==
NULL
)
goto
err
;
curarg
=
newarg
;
touched
=
1
;
c
++
;
}
...
...
@@ -767,31 +786,55 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
/* Add the last argument if needed */
if
(
touched
)
{
addArgument
(
current
,
&
argv
,
&
argc
,
&
totlen
);
newargv
=
realloc
(
curargv
,
sizeof
(
char
*
)
*
(
argc
+
1
));
if
(
newargv
==
NULL
)
goto
err
;
curargv
=
newargv
;
curargv
[
argc
++
]
=
curarg
;
totlen
+=
bulklen
(
sdslen
(
curarg
));
}
else
{
sdsfree
(
cur
rent
);
sdsfree
(
cur
arg
);
}
/* Clear curarg because it was put in curargv or was free'd. */
curarg
=
NULL
;
/* Add bytes needed to hold multi bulk count */
totlen
+=
1
+
intlen
(
argc
)
+
2
;
/* Build the command at protocol level */
cmd
=
malloc
(
totlen
+
1
);
if
(
!
cmd
)
redisOOM
();
if
(
cmd
==
NULL
)
goto
err
;
pos
=
sprintf
(
cmd
,
"*%d
\r\n
"
,
argc
);
for
(
j
=
0
;
j
<
argc
;
j
++
)
{
pos
+=
sprintf
(
cmd
+
pos
,
"$%zu
\r\n
"
,
sdslen
(
argv
[
j
]));
memcpy
(
cmd
+
pos
,
argv
[
j
],
sdslen
(
argv
[
j
]));
pos
+=
sdslen
(
argv
[
j
]);
sdsfree
(
argv
[
j
]);
pos
+=
sprintf
(
cmd
+
pos
,
"$%zu
\r\n
"
,
sdslen
(
cur
argv
[
j
]));
memcpy
(
cmd
+
pos
,
cur
argv
[
j
],
sdslen
(
cur
argv
[
j
]));
pos
+=
sdslen
(
cur
argv
[
j
]);
sdsfree
(
cur
argv
[
j
]);
cmd
[
pos
++
]
=
'\r'
;
cmd
[
pos
++
]
=
'\n'
;
}
assert
(
pos
==
totlen
);
free
(
argv
);
cmd
[
totlen
]
=
'\0'
;
cmd
[
pos
]
=
'\0'
;
free
(
curargv
);
*
target
=
cmd
;
return
totlen
;
err:
while
(
argc
--
)
sdsfree
(
curargv
[
argc
]);
free
(
curargv
);
if
(
curarg
!=
NULL
)
sdsfree
(
curarg
);
/* No need to check cmd since it is the last statement that can fail,
* but do it anyway to be as defensive as possible. */
if
(
cmd
!=
NULL
)
free
(
cmd
);
return
-
1
;
}
/* Format a command according to the Redis protocol. This function
...
...
@@ -830,12 +873,14 @@ int redisFormatCommandArgv(char **target, int argc, const char **argv, const siz
totlen
=
1
+
intlen
(
argc
)
+
2
;
for
(
j
=
0
;
j
<
argc
;
j
++
)
{
len
=
argvlen
?
argvlen
[
j
]
:
strlen
(
argv
[
j
]);
totlen
+=
1
+
int
len
(
len
)
+
2
+
len
+
2
;
totlen
+=
bulk
len
(
len
);
}
/* Build the command at protocol level */
cmd
=
malloc
(
totlen
+
1
);
if
(
!
cmd
)
redisOOM
();
if
(
cmd
==
NULL
)
return
-
1
;
pos
=
sprintf
(
cmd
,
"*%d
\r\n
"
,
argc
);
for
(
j
=
0
;
j
<
argc
;
j
++
)
{
len
=
argvlen
?
argvlen
[
j
]
:
strlen
(
argv
[
j
]);
...
...
@@ -846,7 +891,8 @@ int redisFormatCommandArgv(char **target, int argc, const char **argv, const siz
cmd
[
pos
++
]
=
'\n'
;
}
assert
(
pos
==
totlen
);
cmd
[
totlen
]
=
'\0'
;
cmd
[
pos
]
=
'\0'
;
*
target
=
cmd
;
return
totlen
;
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment