[Fontconfig] [PATCH 2/3] Fix an off-by-one error in FcLangSetIndex()

Florent Rougon f.rougon at free.fr
Tue Jun 6 21:32:28 UTC 2017

This commit fixes a bug that can be reproduced like this:
  - remove all languages starting with 'a' in fc-lang/Makefile.am (in
    ORTH's definition);
  - rebuild fontconfig with this change (-> new fc-lang/fclang.h);
  - create an FcLangSet 'ls1' that contains at least the first language
    from fcLangData (i.e., the first *remaining* in lexicographic
    order); let's assume it is "ba" for the sake of this description;
  - create an FcLangSet 'ls2' that only contains the language "aa" (any
    language starting with 'a' should work as well);
  - check the return value of FcLangSetContains(ls1, ls2);

The expected return value is FcFalse, however it is FcTrue if you use
the code before this commit.

What happens is that FcLangSetIndex() returns 0, because this is the
index of the first slot after the not-found language "aa" in fcLangData
(since we removed all languages starting with 'a'). However, this index
happens to be non-negative, therefore FcLangSetContainsLang() mistakenly
infers that the language "aa" was found in fcLangData, and thus calls
FcLangSetBitGet(ls1, 0), which returns FcTrue since we've put the first
remaining language "ba" in the 'ls1' language set.

The "return -low;" statement previously in FcLangSetIndex() was
inconsistent with the final return statement. "return -(low+1);" fixes
this inconsistency as well as the incorrect behavior described above.
 src/fclang.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/src/fclang.c b/src/fclang.c
index b1fd1bc..50ea793 100644
--- a/src/fclang.c
+++ b/src/fclang.c
@@ -505,6 +505,15 @@ bail0:
     return 0;
+/* When the language isn't found, the return value r is such that:
+ *  1) r < 0
+ *  2) -r -1 is the index of the first language in fcLangData that comes after
+ *     the 'lang' argument in lexicographic order.
+ *
+ *  The -1 is necessary to avoid problems with language id 0 (otherwise, we
+ *  wouldn't be able to distinguish between “language found, id is 0” and
+ *  “language not found, sorts right before language id 0”).
+ */
 static int
 FcLangSetIndex (const FcChar8 *lang)
@@ -529,7 +538,7 @@ FcLangSetIndex (const FcChar8 *lang)
 	high = fcLangCharSetRanges[firstChar - 'a'].end;
 	/* no matches */
 	if (low > high)
-	    return -low; /* next entry after where it would be */
+	    return -(low+1); /* one past next entry after where it would be */
     while (low <= high)

More information about the Fontconfig mailing list