Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion lang/c/src/schema.c
Original file line number Diff line number Diff line change
Expand Up @@ -538,7 +538,14 @@ const char *avro_schema_enum_get(const avro_schema_t enump,
st_data_t data;
char *sym;
} val;
st_lookup(avro_schema_to_enum(enump)->symbols, index, &val.data);
/*
* Return NULL for an unknown index rather than an uninitialized
* pointer: st_lookup() leaves val.data untouched when the key is
* not found.
*/
if (!st_lookup(avro_schema_to_enum(enump)->symbols, index, &val.data)) {
return NULL;
}
return val.sym;
}

Expand Down
13 changes: 13 additions & 0 deletions lang/c/src/value-read.c
Original file line number Diff line number Diff line change
Expand Up @@ -329,10 +329,23 @@ read_value(avro_reader_t reader, avro_value_t *dest)

case AVRO_ENUM:
{
avro_schema_t schema = avro_value_get_schema(dest);
int64_t val;
check_prefix(rval, avro_binary_encoding.
read_long(reader, &val),
"Cannot read enum value: ");
/*
* Reject an out-of-range ordinal read from the input
* before it is used to look up a symbol; otherwise the
* lookup fails and an uninitialized pointer would be
* returned to the caller (see avro_schema_enum_get).
*/
if (val < 0 ||
val >= avro_schema_enum_number_of_symbols(schema)) {
avro_set_error("Enum value %ld is out of range",
(long) val);
return EINVAL;
}
return avro_value_set_enum(dest, val);
}

Expand Down
1 change: 1 addition & 0 deletions lang/c/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,4 @@ add_avro_test_checkmem(test_avro_1691)
add_avro_test_checkmem(test_avro_1906)
add_avro_test_checkmem(test_avro_1904)
add_avro_test_checkmem(test_avro_4246)
add_avro_test_checkmem(test_avro_4344)
95 changes: 95 additions & 0 deletions lang/c/tests/test_avro_4344.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to you under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

/*
* AVRO-4344: reading an out-of-range enum ordinal must return an error
* rather than continuing with an out-of-range index (which previously led
* avro_schema_enum_get() to return an uninitialized pointer).
*/

#include <avro.h>
#include <stdio.h>
#include <stdlib.h>

static avro_schema_t
make_enum_schema(void)
{
/* Two symbols -> valid ordinals are 0 and 1. */
avro_schema_t schema = avro_schema_enum("suit");
avro_schema_enum_symbol_append(schema, "SPADES");
avro_schema_enum_symbol_append(schema, "HEARTS");
return schema;
}

static int
read_enum(avro_value_iface_t *iface, const char *buf, size_t len)
{
avro_reader_t reader = avro_reader_memory(buf, len);
avro_value_t value;
int rval;

avro_generic_value_new(iface, &value);
rval = avro_value_read(reader, &value);
avro_value_decref(&value);
avro_reader_free(reader);
return rval;
}

int main(void)
{
avro_schema_t schema = make_enum_schema();
avro_value_iface_t *iface = avro_generic_class_from_schema(schema);

/* A valid ordinal (1, zig-zag 0x02) must read successfully. */
{
const char buf[] = { 0x02 };
if (read_enum(iface, buf, sizeof(buf)) != 0) {
fprintf(stderr, "Valid enum ordinal failed to read: %s\n",
avro_strerror());
exit(EXIT_FAILURE);
}
}

/* An out-of-range positive ordinal (5, zig-zag 0x0A) must error. */
{
const char buf[] = { 0x0a };
if (read_enum(iface, buf, sizeof(buf)) == 0) {
fprintf(stderr, "Out-of-range enum ordinal was accepted\n");
exit(EXIT_FAILURE);
}
}

/* A negative ordinal (-1, zig-zag 0x01) must error. */
{
const char buf[] = { 0x01 };
if (read_enum(iface, buf, sizeof(buf)) == 0) {
fprintf(stderr, "Negative enum ordinal was accepted\n");
exit(EXIT_FAILURE);
}
}

/* avro_schema_enum_get() returns NULL (not garbage) for a bad index. */
if (avro_schema_enum_get(schema, 99) != NULL) {
fprintf(stderr, "avro_schema_enum_get did not return NULL for "
"an out-of-range index\n");
exit(EXIT_FAILURE);
}

avro_value_iface_decref(iface);
avro_schema_decref(schema);
exit(EXIT_SUCCESS);
}
Loading