Skip to content

Commit 5732e46

Browse files
committed
Fixed ccode array index bug
1 parent a4ad49a commit 5732e46

File tree

3 files changed

+117
-103
lines changed

3 files changed

+117
-103
lines changed

CMakeLists.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ project(mapcode_cpp)
1818
# The debug configuration adds the "address sanitizer" to check for out of bounds behavior and such.
1919
# You may wish to set the following environment variables during runtime as well:
2020
#
21-
# export ASAN_OPTIONS=verbosity=2:coverage=true:strict_string_checks=1:replace_str=true:
22-
# replace_intrin=true:detect_stack_use_after_return=true:detect_invalid_pointer_pairs=99999:
23-
# detect_container_overflow=true:detect_odr_violation=2
21+
# export ASAN_OPTIONS=verbosity=2:debug=true:strict_string_checks=1:detect_stack_use_after_return=true:
22+
# detect_invalid_pointer_pairs=99999:
23+
# detect_container_overflow=true:detect_odr_violation=2:check_initialization_order=true
2424

25-
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wall -Werror -fsanitize=address -O1 -fno-common -fno-optimize-sibling-calls -fno-omit-frame-pointer")
25+
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wall -Werror -fsanitize=address -fno-common -fno-optimize-sibling-calls -fno-omit-frame-pointer")
2626
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -std=c++11")
2727
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -fsanitize=address")
2828

mapcodelib/mapcoder.c

Lines changed: 112 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -53,19 +53,21 @@
5353

5454
#define USIZE 256
5555

56+
#define MATH_PI 3.14159265358979323846
57+
5658
// Radius of Earth.
5759
#define EARTH_RADIUS_X_METERS 6378137
5860
#define EARTH_RADIUS_Y_METERS 6356752
5961

6062
// Circumference of Earth.
61-
#define EARTH_CIRCUMFERENCE_X (EARTH_RADIUS_X_METERS * 2 * _PI)
62-
#define EARTH_CIRCUMFERENCE_Y (EARTH_RADIUS_Y_METERS * 2 * _PI)
63+
#define EARTH_CIRCUMFERENCE_X (EARTH_RADIUS_X_METERS * 2 * MATH_PI)
64+
#define EARTH_CIRCUMFERENCE_Y (EARTH_RADIUS_Y_METERS * 2 * MATH_PI)
6365

6466
// Meters per degree latitude is fixed. For longitude: use factor * cos(midpoint of two degree latitudes).
6567
#define METERS_PER_DEGREE_LAT (EARTH_CIRCUMFERENCE_Y / 360.0)
6668
#define METERS_PER_DEGREE_LON (EARTH_CIRCUMFERENCE_X / 360.0)
6769

68-
#define _PI 3.14159265358979323846
70+
#define PARENT_LETTER(ccode) ((int) parentletter[ccode])
6971

7072
// Legacy buffers: NOT threadsafe!
7173
static char legacy_asciiBuffer[MAX_MAPCODE_RESULT_LEN];
@@ -95,7 +97,7 @@ double distanceInMeters(double latDeg1, double lonDeg1, double latDeg2, double l
9597
}
9698
{
9799
const double dy = (latDeg2 - latDeg1) * METERS_PER_DEGREE_LAT;
98-
const double dx = (lonDeg2 - lonDeg1) * METERS_PER_DEGREE_LON * cos((latDeg1 + latDeg2) * _PI / 360.0);
100+
const double dx = (lonDeg2 - lonDeg1) * METERS_PER_DEGREE_LON * cos((latDeg1 + latDeg2) * MATH_PI / 360.0);
99101
return sqrt(dx * dx + dy * dy);
100102
}
101103
}
@@ -338,14 +340,12 @@ static int lastrec(const int ccode) {
338340
return data_start[ccode + 1] - 1;
339341
}
340342

341-
#define ParentLetter(ccode) ((int)parentletter[ccode])
342-
343343
// returns parent of ccode, or -1
344344
static int parentTerritoryOf(const int ccode) {
345345
if (ccode < 0 || ccode > ccode_earth) {
346346
return -1;
347347
}
348-
return parentnr[ParentLetter(ccode)];
348+
return parentnr[PARENT_LETTER(ccode)];
349349
}
350350

351351
static int coDex(const int m) {
@@ -1090,7 +1090,7 @@ static int encodeLatLonToMapcodes_internal(char **v, Mapcodes *mapcodes,
10901090

10911091
typedef struct {
10921092
// input
1093-
MapcodeElements mapcodeFormat;
1093+
MapcodeElements mapcodeElements;
10941094
const char *orginput; // original full input string
10951095
const char *mapcode; // input mapcode (first character of proper mapcode excluding territory code)
10961096
const char *extension; // input extension (or empty)
@@ -1543,19 +1543,22 @@ static int decoderEngine(decodeRec *dec) {
15431543
int ccode;
15441544
int err;
15451545
int codex;
1546+
int from;
1547+
int upto;
1548+
int i;
15461549
char *s;
15471550

1548-
err = parseMapcodeString(&dec->mapcodeFormat, dec->orginput, 1, dec->context);
1551+
err = parseMapcodeString(&dec->mapcodeElements, dec->orginput, 1, dec->context);
15491552
if (err) {
15501553
return err;
15511554
}
15521555

1553-
ccode = dec->mapcodeFormat.territoryCode - 1;
1556+
ccode = dec->mapcodeElements.territoryCode - 1;
15541557
dec->context = ccode;
1555-
dec->mapcode = dec->mapcodeFormat.properMapcode;
1556-
dec->extension = dec->mapcodeFormat.precisionExtension;
1557-
codex = dec->mapcodeFormat.indexOfDot * 9 + (int) strlen(dec->mapcodeFormat.properMapcode) - 1;
1558-
s = dec->mapcodeFormat.properMapcode;
1558+
dec->mapcode = dec->mapcodeElements.properMapcode;
1559+
dec->extension = dec->mapcodeElements.precisionExtension;
1560+
codex = dec->mapcodeElements.indexOfDot * 9 + (int) strlen(dec->mapcodeElements.properMapcode) - 1;
1561+
s = dec->mapcodeElements.properMapcode;
15591562

15601563
if (strchr(s, 'A') || strchr(s, 'E') || strchr(s, 'U')) {
15611564
if (unpack_if_alldigits(s) <= 0) {
@@ -1574,95 +1577,94 @@ static int decoderEngine(decodeRec *dec) {
15741577
}
15751578
}
15761579

1580+
if (ccode < 0) {
1581+
return -1;
1582+
}
1583+
from = firstrec(ccode);
1584+
upto = lastrec(ccode);
15771585

1578-
{
1579-
const int from = firstrec(ccode);
1580-
const int upto = lastrec(ccode);
1581-
int i;
1582-
1583-
// try all ccode rectangles to decode s (pointing to first character of proper mapcode)
1584-
for (i = from; i <= upto; i++) {
1585-
const int codexi = coDex(i);
1586-
const int r = recType(i);
1587-
if (r == 0) {
1588-
if (isNameless(i)) {
1589-
if (((codexi == 21) && (codex == 22)) ||
1590-
((codexi == 22) && (codex == 32)) ||
1591-
((codexi == 13) && (codex == 23))) {
1592-
err = decodeNameless(dec, i);
1593-
break;
1594-
}
1595-
} else {
1596-
if ((codexi == codex) || ((codex == 22) && (codexi == 21))) {
1597-
err = decodeGrid(dec, i, 0);
1598-
1599-
// first of all, make sure the zone fits the country
1600-
restrictZoneTo(&dec->zone, &dec->zone, boundaries(upto));
1601-
1602-
if ((err == 0) && isRestricted(i)) {
1603-
int nrZoneOverlaps = 0;
1604-
int j;
1605-
1606-
// *** make sure decode fits somewhere ***
1607-
dec->result = getMidPointFractions(&dec->zone);
1608-
dec->coord32 = convertFractionsToCoord32(&dec->result);
1609-
for (j = i - 1; j >= from; j--) { // look in previous rects
1610-
if (!isRestricted(j)) {
1611-
if (fitsInsideBoundaries(&dec->coord32, boundaries(j))) {
1612-
nrZoneOverlaps = 1;
1613-
break;
1614-
}
1586+
// try all ccode rectangles to decode s (pointing to first character of proper mapcode)
1587+
for (i = from; i <= upto; i++) {
1588+
const int codexi = coDex(i);
1589+
const int r = recType(i);
1590+
if (r == 0) {
1591+
if (isNameless(i)) {
1592+
if (((codexi == 21) && (codex == 22)) ||
1593+
((codexi == 22) && (codex == 32)) ||
1594+
((codexi == 13) && (codex == 23))) {
1595+
err = decodeNameless(dec, i);
1596+
break;
1597+
}
1598+
} else {
1599+
if ((codexi == codex) || ((codex == 22) && (codexi == 21))) {
1600+
err = decodeGrid(dec, i, 0);
1601+
1602+
// first of all, make sure the zone fits the country
1603+
restrictZoneTo(&dec->zone, &dec->zone, boundaries(upto));
1604+
1605+
if ((err == 0) && isRestricted(i)) {
1606+
int nrZoneOverlaps = 0;
1607+
int j;
1608+
1609+
// *** make sure decode fits somewhere ***
1610+
dec->result = getMidPointFractions(&dec->zone);
1611+
dec->coord32 = convertFractionsToCoord32(&dec->result);
1612+
for (j = i - 1; j >= from; j--) { // look in previous rects
1613+
if (!isRestricted(j)) {
1614+
if (fitsInsideBoundaries(&dec->coord32, boundaries(j))) {
1615+
nrZoneOverlaps = 1;
1616+
break;
16151617
}
16161618
}
1619+
}
16171620

1618-
if (!nrZoneOverlaps) {
1619-
MapcodeZone zfound;
1620-
Boundaries prevu;
1621-
for (j = from; j < i; j++) { // try all smaller rectangles j
1622-
if (!isRestricted(j)) {
1623-
MapcodeZone z;
1624-
if (restrictZoneTo(&z, &dec->zone, boundaries(j))) {
1625-
nrZoneOverlaps++;
1626-
if (nrZoneOverlaps == 1) {
1627-
// first fit! remember...
1628-
zoneCopyFrom(&zfound, &z);
1629-
memcpy(&prevu, boundaries(j), sizeof(Boundaries));
1630-
} else { // nrZoneOverlaps >= 2
1631-
// more than one hit
1632-
break; // give up
1633-
}
1621+
if (!nrZoneOverlaps) {
1622+
MapcodeZone zfound;
1623+
Boundaries prevu;
1624+
for (j = from; j < i; j++) { // try all smaller rectangles j
1625+
if (!isRestricted(j)) {
1626+
MapcodeZone z;
1627+
if (restrictZoneTo(&z, &dec->zone, boundaries(j))) {
1628+
nrZoneOverlaps++;
1629+
if (nrZoneOverlaps == 1) {
1630+
// first fit! remember...
1631+
zoneCopyFrom(&zfound, &z);
1632+
memcpy(&prevu, boundaries(j), sizeof(Boundaries));
1633+
} else { // nrZoneOverlaps >= 2
1634+
// more than one hit
1635+
break; // give up
16341636
}
1635-
} // isRestricted
1636-
} // for j
1637+
}
1638+
} // isRestricted
1639+
} // for j
16371640

1638-
// if several sub-areas intersect, just return the whole zone
1639-
// (the center of which may NOT re-encode to the same mapcode!)
1640-
if (nrZoneOverlaps == 1) { // found exactly ONE intersection?
1641-
zoneCopyFrom(&dec->zone, &zfound);
1642-
}
1641+
// if several sub-areas intersect, just return the whole zone
1642+
// (the center of which may NOT re-encode to the same mapcode!)
1643+
if (nrZoneOverlaps == 1) { // found exactly ONE intersection?
1644+
zoneCopyFrom(&dec->zone, &zfound);
16431645
}
1646+
}
16441647

1645-
if (!nrZoneOverlaps) {
1646-
err = -1234;
1647-
}
1648-
} // *** make sure decode fits somewhere ***
1649-
break;
1650-
}
1651-
}
1652-
} else if (r == 1) {
1653-
if (codex == codexi + 10 && headerLetter(i) == *s) {
1654-
err = decodeGrid(dec, i, 1);
1655-
break;
1656-
}
1657-
} else { //r>1
1658-
if (((codex == 23) && (codexi == 22)) ||
1659-
((codex == 33) && (codexi == 23))) {
1660-
err = decodeAutoHeader(dec, i);
1648+
if (!nrZoneOverlaps) {
1649+
err = -1234;
1650+
}
1651+
} // *** make sure decode fits somewhere ***
16611652
break;
16621653
}
16631654
}
1664-
} // for
1665-
}
1655+
} else if (r == 1) {
1656+
if (codex == codexi + 10 && headerLetter(i) == *s) {
1657+
err = decodeGrid(dec, i, 1);
1658+
break;
1659+
}
1660+
} else { //r>1
1661+
if (((codex == 23) && (codexi == 22)) ||
1662+
((codex == 33) && (codexi == 23))) {
1663+
err = decodeAutoHeader(dec, i);
1664+
break;
1665+
}
1666+
}
1667+
} // for
16661668

16671669
restrictZoneTo(&dec->zone, &dec->zone, boundaries(lastrec(ccode)));
16681670

@@ -2249,14 +2251,26 @@ int getTerritoryCode(const char *territoryISO, int optionalTerritoryContext) {
22492251
} else if (territoryISO[2] && territoryISO[3] == '-') {
22502252
return binfindmatch(getParentNumber(territoryISO, 3), territoryISO + 4);
22512253
} else {
2252-
const int parentNumber =
2253-
ccode < 0 ? 0 : ((parentnumber[ccode] > 0) ? parentnumber[ccode] : parentnumber[parentTerritoryOf(
2254-
ccode)]);
2255-
const int b = binfindmatch(parentNumber, territoryISO);
2254+
int b;
2255+
int parentNumber = 0;
2256+
if (ccode >= 0) {
2257+
if (parentnumber[ccode] > 0) {
2258+
parentNumber = parentnumber[ccode];
2259+
} else {
2260+
int parentTerritory = parentTerritoryOf(ccode);
2261+
if (parentTerritory >= 0) {
2262+
parentNumber = parentnumber[parentTerritory];
2263+
} else {
2264+
parentNumber = -1;
2265+
}
2266+
2267+
}
2268+
}
2269+
b = binfindmatch(parentNumber, territoryISO);
22562270
if (b > 0) {
22572271
return b;
2258-
} //
2259-
} //
2272+
}
2273+
}
22602274
return binfindmatch(0, territoryISO);
22612275
} // else, fail:
22622276
return -1;

unittest/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ To build the unit tests, execute:
55
cd unittest
66
gcc -O unittest.c -lm -lpthread -o unittest
77

8-
(Or if you need to make sure there are no warnings:)
8+
(Or to compile and run with additional checks, when using `clang`:)
99

1010
gcc -Wall -O unittest.c -lm -lpthread -fsanitize=address -o unittest
1111

0 commit comments

Comments
 (0)