Skip to content

Commit

Permalink
Fix segfault while serializing a geometrycollection
Browse files Browse the repository at this point in the history
This commit addresses an issue where serializing a
geometrycollection may segfault.

For tg_geom_geojson(), tg_geom_wkt(), and tg_geom_wkb()

Fixes #7
  • Loading branch information
tidwall committed Aug 27, 2024
1 parent 190f4a6 commit fc9d1fc
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 54 deletions.
20 changes: 20 additions & 0 deletions tests/test_geojson.c
Original file line number Diff line number Diff line change
Expand Up @@ -1028,12 +1028,32 @@ void test_geojson_big_shapes() {
tg_geom_free(geom2);
}

void test_geojson_geometrycollection() {
struct tg_geom *g1 = tg_parse_wkt("POLYGON ((30 10, 40 40, 20 40, 10 20, 30 10))");
assert(!tg_geom_error(g1));
struct tg_geom *g2 = tg_parse_wkt("POLYGON ((300 100, 400 400, 200 400, 100 200, 300 100))");
assert(!tg_geom_error(g2));
struct tg_geom *collection = tg_geom_new_geometrycollection((const struct tg_geom*const[]) {g1, g2}, 2);
assert(!tg_geom_error(collection));
char dst1[1024];
char dst2[1024];
tg_geom_geojson(tg_geom_geometry_at(collection, 1), dst1, sizeof(dst1));
struct tg_geom *g3 = tg_parse_geojson(dst1);
tg_geom_geojson(g3, dst2, sizeof(dst2));
assert(strcmp(dst1, dst2) == 0);
tg_geom_free(g1);
tg_geom_free(g2);
tg_geom_free(collection);
tg_geom_free(g3);
}

int main(int argc, char **argv) {
seedrand();
do_test(test_geojson_basic_syntax);
do_test(test_geojson_feature);
do_test(test_geojson_various);
do_test(test_geojson_big_shapes);
do_chaos_test(test_geojson_chaos);
do_test(test_geojson_geometrycollection);
return 0;
}
21 changes: 21 additions & 0 deletions tests/test_wkb.c
Original file line number Diff line number Diff line change
Expand Up @@ -801,6 +801,26 @@ void test_wkb_big_shapes() {
tg_geom_free(geom2);
}

void test_wkb_geometrycollection() {
struct tg_geom *g1 = tg_parse_wkt("POLYGON ((30 10, 40 40, 20 40, 10 20, 30 10))");
assert(!tg_geom_error(g1));
struct tg_geom *g2 = tg_parse_wkt("POLYGON ((300 100, 400 400, 200 400, 100 200, 300 100))");
assert(!tg_geom_error(g2));
struct tg_geom *collection = tg_geom_new_geometrycollection((const struct tg_geom*const[]) {g1, g2}, 2);
assert(!tg_geom_error(collection));
uint8_t dst1[1024];
uint8_t dst2[1024];
size_t sz1 = tg_geom_wkb(tg_geom_geometry_at(collection, 1), dst1, sizeof(dst1));
struct tg_geom *g3 = tg_parse_wkb(dst1, sz1);
size_t sz2 = tg_geom_wkb(g3, dst2, sizeof(dst2));
assert(sz1 == sz2 && memcmp(dst1, dst2, sz1) == 0);
tg_geom_free(g1);
tg_geom_free(g2);
tg_geom_free(collection);
tg_geom_free(g3);
}


int main(int argc, char **argv) {
do_test(test_wkb_basic_syntax);
do_test(test_wkb_max_depth);
Expand All @@ -810,5 +830,6 @@ int main(int argc, char **argv) {
do_test(test_wkb_with_srid);
do_test(test_wkb_various);
do_test(test_wkb_big_shapes);
do_test(test_wkb_geometrycollection);
return 0;
}
19 changes: 19 additions & 0 deletions tests/test_wkt.c
Original file line number Diff line number Diff line change
Expand Up @@ -715,12 +715,31 @@ void test_wkt_various() {
tg_geom_free(geom);
}

void test_wkt_geometrycollection() {
struct tg_geom *g1 = tg_parse_wkt("POLYGON ((30 10, 40 40, 20 40, 10 20, 30 10))");
assert(!tg_geom_error(g1));
struct tg_geom *g2 = tg_parse_wkt("POLYGON ((300 100, 400 400, 200 400, 100 200, 300 100))");
assert(!tg_geom_error(g2));
struct tg_geom *collection = tg_geom_new_geometrycollection((const struct tg_geom*const[]) {g1, g2}, 2);
assert(!tg_geom_error(collection));
char dst1[1024];
char dst2[1024];
tg_geom_wkt(tg_geom_geometry_at(collection, 1), dst1, sizeof(dst1));
struct tg_geom *g3 = tg_parse_wkt(dst1);
tg_geom_wkt(g3, dst2, sizeof(dst2));
assert(strcmp(dst1, dst2) == 0);
tg_geom_free(g1);
tg_geom_free(g2);
tg_geom_free(collection);
tg_geom_free(g3);
}

int main(int argc, char **argv) {
seedrand();
do_test(test_wkt_basic_syntax);
do_test(test_wkt_max_depth);
do_chaos_test(test_wkt_chaos);
do_test(test_wkt_various);
do_test(test_wkt_geometrycollection);
return 0;
}
122 changes: 68 additions & 54 deletions tg.c
Original file line number Diff line number Diff line change
Expand Up @@ -10600,7 +10600,9 @@ static void write_geom_geometrycollection_geojson(const struct tg_geom *geom,
write_char(wr, '}');
}

static void write_geom_geojson(const struct tg_geom *geom, struct writer *wr) {
static void write_base_geom_geojson(const struct tg_geom *geom,
struct writer *wr)
{
if ((geom->head.flags&IS_ERROR) == IS_ERROR) {
// sigh, just write us an empty point ...
write_string(wr, "{\"type\":\"Point\",\"coordinates\":[]}");
Expand Down Expand Up @@ -10775,6 +10777,26 @@ static void write_poly_geojson(const struct tg_poly *poly, struct writer *wr) {
}
}

static void write_geom_geojson(const struct tg_geom *geom, struct writer *wr) {
switch (geom->head.base) {
case BASE_GEOM:
write_base_geom_geojson(geom, wr);
break;
case BASE_POINT:
write_point_geojson((struct boxed_point*)geom, wr);
break;
case BASE_LINE:
write_line_geojson((struct tg_line*)geom, wr);
break;
case BASE_RING:
write_ring_geojson((struct tg_ring*)geom, wr);
break;
case BASE_POLY:
write_poly_geojson((struct tg_poly*)geom, wr);
break;
}
}

/// Writes a GeoJSON representation of a geometry.
///
/// The content is stored as a C string in the buffer pointed to by dst.
Expand Down Expand Up @@ -10804,23 +10826,7 @@ static void write_poly_geojson(const struct tg_poly *poly, struct writer *wr) {
size_t tg_geom_geojson(const struct tg_geom *geom, char *dst, size_t n) {
if (!geom) return 0;
struct writer wr = { .dst = (uint8_t*)dst, .n = n };
switch (geom->head.base) {
case BASE_GEOM:
write_geom_geojson(geom, &wr);
break;
case BASE_POINT:
write_point_geojson((struct boxed_point*)geom, &wr);
break;
case BASE_LINE:
write_line_geojson((struct tg_line*)geom, &wr);
break;
case BASE_RING:
write_ring_geojson((struct tg_ring*)geom, &wr);
break;
case BASE_POLY:
write_poly_geojson((struct tg_poly*)geom, &wr);
break;
}
write_geom_geojson(geom, &wr);
write_nullterm(&wr);
return wr.count;
}
Expand Down Expand Up @@ -12129,7 +12135,7 @@ static void write_geom_geometrycollection_wkt(const struct tg_geom *geom,
write_char(wr, ')');
}

static void write_geom_wkt(const struct tg_geom *geom, struct writer *wr) {
static void write_base_geom_wkt(const struct tg_geom *geom, struct writer *wr) {
switch (geom->head.type) {
case TG_POINT:
write_geom_point_wkt(geom, wr);
Expand All @@ -12155,6 +12161,26 @@ static void write_geom_wkt(const struct tg_geom *geom, struct writer *wr) {
}
}

static void write_geom_wkt(const struct tg_geom *geom, struct writer *wr) {
switch (geom->head.base) {
case BASE_GEOM:
write_base_geom_wkt(geom, wr);
break;
case BASE_POINT:
write_point_wkt((struct boxed_point*)geom, wr);
break;
case BASE_LINE:
write_line_wkt((struct tg_line*)geom, wr);
break;
case BASE_RING:
write_ring_wkt((struct tg_ring*)geom, wr);
break;
case BASE_POLY:
write_poly_wkt((struct tg_poly*)geom, wr);
break;
}
}

/// Writes a Well-known text (WKT) representation of a geometry.
///
/// The content is stored as a C string in the buffer pointed to by dst.
Expand Down Expand Up @@ -12184,23 +12210,7 @@ static void write_geom_wkt(const struct tg_geom *geom, struct writer *wr) {
size_t tg_geom_wkt(const struct tg_geom *geom, char *dst, size_t n) {
if (!geom) return 0;
struct writer wr = { .dst = (uint8_t*)dst, .n = n };
switch (geom->head.base) {
case BASE_GEOM:
write_geom_wkt(geom, &wr);
break;
case BASE_POINT:
write_point_wkt((struct boxed_point*)geom, &wr);
break;
case BASE_LINE:
write_line_wkt((struct tg_line*)geom, &wr);
break;
case BASE_RING:
write_ring_wkt((struct tg_ring*)geom, &wr);
break;
case BASE_POLY:
write_poly_wkt((struct tg_poly*)geom, &wr);
break;
}
write_geom_wkt(geom, &wr);
write_nullterm(&wr);
return wr.count;
}
Expand Down Expand Up @@ -13284,7 +13294,7 @@ static void write_geom_geometrycollection_wkb(const struct tg_geom *geom,
}
}

static void write_geom_wkb(const struct tg_geom *geom, struct writer *wr) {
static void write_base_geom_wkb(const struct tg_geom *geom, struct writer *wr) {
switch (geom->head.type) {
case TG_POINT:
write_geom_point_wkb(geom, wr);
Expand All @@ -13310,6 +13320,26 @@ static void write_geom_wkb(const struct tg_geom *geom, struct writer *wr) {
}
}

static void write_geom_wkb(const struct tg_geom *geom, struct writer *wr) {
switch (geom->head.base) {
case BASE_GEOM:
write_base_geom_wkb(geom, wr);
break;
case BASE_POINT:
write_point_wkb((struct boxed_point*)geom, wr);
break;
case BASE_LINE:
write_line_wkb((struct tg_line*)geom, wr);
break;
case BASE_RING:
write_ring_wkb((struct tg_ring*)geom, wr);
break;
case BASE_POLY:
write_poly_wkb((struct tg_poly*)geom, wr);
break;
}
}

/// Writes a Well-known binary (WKB) representation of a geometry.
///
/// The content is stored in the buffer pointed by dst.
Expand Down Expand Up @@ -13337,23 +13367,7 @@ static void write_geom_wkb(const struct tg_geom *geom, struct writer *wr) {
size_t tg_geom_wkb(const struct tg_geom *geom, uint8_t *dst, size_t n) {
if (!geom) return 0;
struct writer wr = { .dst = dst, .n = n };
switch (geom->head.base) {
case BASE_GEOM:
write_geom_wkb(geom, &wr);
break;
case BASE_POINT:
write_point_wkb((struct boxed_point*)geom, &wr);
break;
case BASE_LINE:
write_line_wkb((struct tg_line*)geom, &wr);
break;
case BASE_RING:
write_ring_wkb((struct tg_ring*)geom, &wr);
break;
case BASE_POLY:
write_poly_wkb((struct tg_poly*)geom, &wr);
break;
}
write_geom_wkb(geom, &wr);
return wr.count;
}

Expand Down

0 comments on commit fc9d1fc

Please sign in to comment.