Skip to content

Commit c0aad2f

Browse files
cborparser_dup_string: don't modify *buffer until success
We were returning from the function with the memory we had allocated and freed, if the second iteration over the string produced a failure that didn't happen on the first one. This can't happen with pure memory buffers, but can happen with an external data source that fails to produce the same contents twice. I'm documenting that the values in all error conditions except for OOM are undefined, so one mustn't attempt to use them, even to free. This does not change behaviour of the library, just documents. But this commit does make it clear the OOM condition will return a valid `*buflen` and `next`, the latter of which is new behaviour with this commit. Fixes #258. Signed-off-by: Thiago Macieira <[email protected]>
1 parent 2fc4c35 commit c0aad2f

File tree

1 file changed

+29
-19
lines changed

1 file changed

+29
-19
lines changed

src/cborparser_dup_string.c

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -49,16 +49,19 @@
4949
* undefined, so checking with \ref cbor_value_get_type or \ref
5050
* cbor_value_is_text_string is recommended.
5151
*
52-
* If \c malloc returns a NULL pointer, this function will return error
53-
* condition \ref CborErrorOutOfMemory.
54-
*
5552
* On success, \c *buffer will contain a valid pointer that must be freed by
56-
* calling \c free(). This is the case even for zero-length strings.
57-
*
58-
* The \a next pointer, if not null, will be updated to point to the next item
59-
* after this string. If \a value points to the last item, then \a next will be
53+
* calling \c free(). This is the case even for zero-length strings. The \a
54+
* next pointer, if not null, will be updated to point to the next item after
55+
* this string. If \a value points to the last item, then \a next will be
6056
* invalid.
6157
*
58+
* If \c malloc returns a NULL pointer, this function will return error
59+
* condition \ref CborErrorOutOfMemory. In this case, \c *buflen should contain
60+
* the number of bytes necessary to copy this string and \a value will be
61+
* updated to point to the next element. On all other failure cases, the values
62+
* contained in \c *buffer, \c *buflen and \a next are undefined and mustn't be
63+
* used (for example, calling \c{free()}).
64+
*
6265
* This function may not run in constant time (it will run in O(n) time on the
6366
* number of chunks). It requires constant memory (O(1)) in addition to the
6467
* malloc'ed block.
@@ -80,16 +83,19 @@
8083
* undefined, so checking with \ref cbor_value_get_type or \ref
8184
* cbor_value_is_byte_string is recommended.
8285
*
83-
* If \c malloc returns a NULL pointer, this function will return error
84-
* condition \ref CborErrorOutOfMemory.
85-
*
8686
* On success, \c *buffer will contain a valid pointer that must be freed by
87-
* calling \c free(). This is the case even for zero-length strings.
88-
*
89-
* The \a next pointer, if not null, will be updated to point to the next item
90-
* after this string. If \a value points to the last item, then \a next will be
87+
* calling \c free(). This is the case even for zero-length strings. The \a
88+
* next pointer, if not null, will be updated to point to the next item after
89+
* this string. If \a value points to the last item, then \a next will be
9190
* invalid.
9291
*
92+
* If \c malloc returns a NULL pointer, this function will return error
93+
* condition \ref CborErrorOutOfMemory. In this case, \c *buflen should contain
94+
* the number of bytes necessary to copy this string and \a value will be
95+
* updated to point to the next element. On all other failure cases, the values
96+
* contained in \c *buffer, \c *buflen and \a next are undefined and mustn't be
97+
* used (for example, calling \c{free()}).
98+
*
9399
* This function may not run in constant time (it will run in O(n) time on the
94100
* number of chunks). It requires constant memory (O(1)) in addition to the
95101
* malloc'ed block.
@@ -98,24 +104,28 @@
98104
*/
99105
CborError _cbor_value_dup_string(const CborValue *value, void **buffer, size_t *buflen, CborValue *next)
100106
{
107+
const CborValue it = *value; // often value == next
101108
CborError err;
109+
void *tmpbuf;
102110
cbor_assert(buffer);
103111
cbor_assert(buflen);
104112
*buflen = SIZE_MAX;
105-
err = _cbor_value_copy_string(value, NULL, buflen, NULL);
113+
err = _cbor_value_copy_string(&it, NULL, buflen, next);
106114
if (err)
107115
return err;
108116

109117
++*buflen;
110-
*buffer = cbor_malloc(*buflen);
111-
if (!*buffer) {
118+
tmpbuf = cbor_malloc(*buflen);
119+
if (!tmpbuf) {
112120
/* out of memory */
113121
return CborErrorOutOfMemory;
114122
}
115-
err = _cbor_value_copy_string(value, *buffer, buflen, next);
123+
err = _cbor_value_copy_string(&it, tmpbuf, buflen, next);
116124
if (err) {
117-
cbor_free(*buffer);
125+
/* This shouldn't have happened! We've iterated once. */
126+
cbor_free(tmpbuf);
118127
return err;
119128
}
129+
*buffer = tmpbuf;
120130
return CborNoError;
121131
}

0 commit comments

Comments
 (0)