diff --git a/include/openvswitch/ofpbuf.h b/include/openvswitch/ofpbuf.h index 1fc4a3a7f..0dfa51ecb 100644 --- a/include/openvswitch/ofpbuf.h +++ b/include/openvswitch/ofpbuf.h @@ -292,6 +292,13 @@ static inline bool ofpbuf_oversized(const struct ofpbuf *ofpacts) return (char *)ofpbuf_tail(ofpacts) - (char *)ofpacts->header > UINT16_MAX; } +/* Truncates the buffer to 'new_size' bytes from the tail end of 'b'. */ +static inline void ofpbuf_truncate(struct ofpbuf *b, size_t new_size) +{ + ovs_assert(b->size >= new_size); + b->size = new_size; +} + #ifdef __cplusplus } #endif diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c index 8a05f7c9c..102abbc23 100644 --- a/lib/ofp-actions.c +++ b/lib/ofp-actions.c @@ -9674,7 +9674,7 @@ ofpacts_parse(char *str, const struct ofpact_parse_params *pp, uint32_t orig_size = pp->ofpacts->size; char *error = ofpacts_parse__(str, pp, allow_instructions, outer_action); if (error) { - pp->ofpacts->size = orig_size; + ofpbuf_truncate(pp->ofpacts, orig_size); } CONST_CAST(struct ofpact_parse_params *, pp)->depth--; return error; diff --git a/tests/test-ofpbuf.c b/tests/test-ofpbuf.c index 3d7fab90f..296d308a7 100644 --- a/tests/test-ofpbuf.c +++ b/tests/test-ofpbuf.c @@ -24,6 +24,7 @@ #define BUF_SIZE 100 #define HDR_OFS 10 #define MSG_OFS 50 +#define DATA_SIZE 16 static void test_ofpbuf_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) @@ -59,6 +60,15 @@ test_ofpbuf_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) ovs_assert(buf->header == (char *) buf->base + BUF_SIZE + HDR_OFS); ovs_assert(buf->msg == (char *) buf->base + BUF_SIZE + MSG_OFS); + size_t prev_size = buf->size; + ofpbuf_put_uninit(buf, DATA_SIZE); + ofpbuf_truncate(buf, prev_size); + /* Check that everything else is unchanged after truncate. */ + ovs_assert(!buf->size); + ovs_assert((char *) buf->base + BUF_SIZE == buf->data); + ovs_assert(buf->header == (char *) buf->base + BUF_SIZE + HDR_OFS); + ovs_assert(buf->msg == (char *) buf->base + BUF_SIZE + MSG_OFS); + ofpbuf_delete(buf); exit(exit_code); }