shithub: freetype+ttf2subf

Download patch

ref: 46b5c4ac313b074bedd683a0f1fb25ad2b5e9664
parent: b5a0a34be7f8512a1b94859de99f94e4fa8dc6d9
author: Werner Lemberg <[email protected]>
date: Tue Aug 17 19:02:06 EDT 2004

* src/otlayout/otlgpos.c (otl_gpos_lookup1_validate,
otl_gpos_lookup2_validate, otl_gpos_lookup3_validate,
otl_gpos_lookup4_validate, otl_gpos_lookup5_validate,
otl_gpos_lookup6_validate, otl_gpos_lookup9_validate,
otl_gpos_validate): Update
function arguments.
(otl_gpos_lookup7_validate, otl_gpos_lookup8_validate): Update
function arguments.
Handle NULL offsets correctly.
Check sequence and lookup indices for format 3.
(otl_pos_rule_validate, otl_chain_pos_rule_validate): Add argument
to pass lookup count.
Check sequence and glyph indices.
(otl_gpos_subtable_validate): Update function arguments.
Update callers.

* src/otlayout/otlgpos.h: Updated.

* src/otlayout/otlgsub.c (otl_gsub_lookup1_validate,
otl_gsub_lookup3_validate, otl_gsub_lookup8_validate): Update
function arguments.
Add glyph index checks.
(otl_sequence_validate, otl_alternate_set_validate,
otl_ligature_validate): Add argument to pass glyph count.
Update callers.
Add glyph index check.
(otl_gsub_lookup2_validate, otl_gsub_lookup4_validate): Update
function arguments.
(otl_ligature_set_validate): Add argument to pass glyph count.
Update caller.
(otl_sub_class_rule_validate,
otl_sub_class_rule_set_validate): Removed.
(otl_sub_rule_validate, otl_chain_sub_rule_validate): Add argument
to pass lookup count.
Update callers.
Add lookup index check.
(otl_sub_rule_set_validate, otl_chain_sub_rule_set_validate): Add
argument to pass lookup count.
Update callers.
(otl_gsub_lookup5_validate): Update function arguments.
Handle NULL offsets correctly.
Don't call otl_sub_class_rule_set_validate but
otl_sub_rule_set_validate.
Check sequence and lookup indices for format 3.
(otl_gsub_lookup6_validate): Update function arguments.
Handle NULL offsets correctly.
Check sequence and lookup indices for format 3.
(otl_gsub_lookup7_validate, otl_gsub_validate): Update function
arguments.

* src/otlayout/otlgsub.h: Updated.

* src/otlayout/otlbase.c (otl_base_validate): Handle NULL offsets
correctly.

* src/otlayout/otlcommn.c (otl_class_definition_validate): Fix
compiler warning.
(otl_coverage_get_first, otl_coverage_get_last): New functions.
(otl_lookup_validate): Add arguments to pass lookup and glyph
counts.
Update callers.
(otl_lookup_list_validate): Add argument to pass glyph count.
Update callers.

* src/otlayout/otlcommn.h: Updated.

* src/otlayout/otljstf.c (otl_jstf_extender_validate,
otl_jstf_max_validate, otl_jstf_script_validate,
otl_jstf_priority_validate, otl_jstf_lang_validate): Add parameter
to validate glyph indices.
Update callers.
(otl_jstf_validate): Add parameter which specifies number of glyphs
in font.

* src/otlayout/otljstf.h: Updated.

git/fs: mount .git/fs: mount/attach disallowed
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,81 @@
+2004-08-16  Werner Lemberg  <[email protected]>
+
+	* src/otlayout/otlgpos.c (otl_gpos_lookup1_validate,
+	otl_gpos_lookup2_validate, otl_gpos_lookup3_validate,
+	otl_gpos_lookup4_validate, otl_gpos_lookup5_validate,
+	otl_gpos_lookup6_validate, otl_gpos_lookup9_validate,
+	otl_gpos_validate): Update
+	function arguments.
+	(otl_gpos_lookup7_validate, otl_gpos_lookup8_validate): Update
+	function arguments.
+	Handle NULL offsets correctly.
+	Check sequence and lookup indices for format 3.
+	(otl_pos_rule_validate, otl_chain_pos_rule_validate): Add argument
+	to pass lookup count.
+	Check sequence and glyph indices.
+	(otl_gpos_subtable_validate): Update function arguments.
+	Update callers. 
+
+	* src/otlayout/otlgpos.h: Updated.
+
+	* src/otlayout/otlgsub.c (otl_gsub_lookup1_validate,
+	otl_gsub_lookup3_validate, otl_gsub_lookup8_validate): Update
+	function arguments.
+	Add glyph index checks.
+	(otl_sequence_validate, otl_alternate_set_validate,
+	otl_ligature_validate): Add argument to pass glyph count.
+	Update callers.
+	Add glyph index check.
+	(otl_gsub_lookup2_validate, otl_gsub_lookup4_validate): Update
+	function arguments.
+	(otl_ligature_set_validate): Add argument to pass glyph count.
+	Update caller.
+	(otl_sub_class_rule_validate,
+	otl_sub_class_rule_set_validate): Removed.
+	(otl_sub_rule_validate, otl_chain_sub_rule_validate): Add argument
+	to pass lookup count.
+	Update callers.
+	Add lookup index check.
+	(otl_sub_rule_set_validate, otl_chain_sub_rule_set_validate): Add
+	argument to pass lookup count.
+	Update callers.
+	(otl_gsub_lookup5_validate): Update function arguments.
+	Handle NULL offsets correctly.
+	Don't call otl_sub_class_rule_set_validate but
+	otl_sub_rule_set_validate.
+	Check sequence and lookup indices for format 3.
+	(otl_gsub_lookup6_validate): Update function arguments.
+	Handle NULL offsets correctly.
+	Check sequence and lookup indices for format 3.
+	(otl_gsub_lookup7_validate, otl_gsub_validate): Update function
+	arguments.
+
+	* src/otlayout/otlgsub.h: Updated.
+
+	* src/otlayout/otlbase.c (otl_base_validate): Handle NULL offsets
+	correctly.
+
+	* src/otlayout/otlcommn.c (otl_class_definition_validate): Fix
+	compiler warning.
+	(otl_coverage_get_first, otl_coverage_get_last): New functions.
+	(otl_lookup_validate): Add arguments to pass lookup and glyph
+	counts.
+	Update callers.
+	(otl_lookup_list_validate): Add argument to pass glyph count.
+	Update callers.
+
+	* src/otlayout/otlcommn.h: Updated.
+
+	* src/otlayout/otljstf.c (otl_jstf_extender_validate,
+	otl_jstf_max_validate, otl_jstf_script_validate,
+	otl_jstf_priority_validate, otl_jstf_lang_validate): Add parameter
+	to validate glyph indices.
+	Update callers.
+	(otl_jstf_validate): Add parameter which specifies number of glyphs
+	in font.
+
+	* src/otlayout/otljstf.h: Updated.
+
 2004-08-15  Werner Lemberg  <[email protected]>
 
 	* src/otlayout/otlgpos.c (otl_liga_mark2_validate): Add parameter
--- a/src/otlayout/otlayout.h
+++ b/src/otlayout/otlayout.h
@@ -189,6 +189,8 @@
   } OTL_ValidatorRec;
 
   typedef void  (*OTL_ValidateFunc)( OTL_Bytes      table,
+                                     OTL_UInt       lookup_count,
+                                     OTL_UInt       glyph_count,
                                      OTL_Validator  valid );
 
   OTL_API( void )
--- a/src/otlayout/otlbase.c
+++ b/src/otlayout/otlbase.c
@@ -208,6 +208,7 @@
                      OTL_Validator  valid )
   {
     OTL_Bytes p = table;
+    OTL_UInt  val;
 
 
     OTL_CHECK( 6 );
@@ -215,8 +216,15 @@
     if ( OTL_NEXT_ULONG( p ) != 0x10000UL )
       OTL_INVALID_DATA;
 
-    otl_axis_table_validate( table + OTL_NEXT_USHORT( p ), valid );
-    otl_axis_table_validate( table + OTL_NEXT_USHORT( p ), valid );
+    /* validate horizontal axis table */
+    val = OTL_NEXT_USHORT( p );
+    if ( val )
+      otl_axis_table_validate( table + val, valid );
+
+    /* validate vertical axis table */
+    val = OTL_NEXT_USHORT( p );
+    if ( val )
+      otl_axis_table_validate( table + val, valid );
   }
 
 
--- a/src/otlayout/otlcommn.c
+++ b/src/otlayout/otlcommn.c
@@ -87,6 +87,47 @@
 
 
   OTL_LOCALDEF( OTL_UInt )
+  otl_coverage_get_first( OTL_Bytes  table )
+  {
+    OTL_Bytes  p = table;
+
+
+    p += 4;     /* skip format and count */
+
+    return OTL_NEXT_USHORT( p );
+  }
+
+
+  OTL_LOCALDEF( OTL_UInt )
+  otl_coverage_get_last( OTL_Bytes  table )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   format = OTL_NEXT_USHORT( p );
+    OTL_UInt   count  = OTL_NEXT_USHORT( p );
+    OTL_UInt   result;
+
+
+    switch ( format )
+    {
+    case 1:
+      p += ( count - 1 ) * 2;
+      result = OTL_NEXT_USHORT( p );
+      break;
+
+    case 2:
+      p += ( count - 1 ) * 6 + 2;
+      result = OTL_NEXT_USHORT( p );
+      break;
+
+    default:
+      ;
+    }
+
+    return result;
+  }
+
+
+  OTL_LOCALDEF( OTL_UInt )
   otl_coverage_get_count( OTL_Bytes  table )
   {
     OTL_Bytes  p      = table;
@@ -215,14 +256,15 @@
     {
     case 1:
       {
-        OTL_UInt  num_glyphs, start = OTL_NEXT_USHORT( p );
+        OTL_UInt  num_glyphs;
 
 
+        p += 2;         /* skip start_glyph */
+
         OTL_CHECK( 2 );
         num_glyphs = OTL_NEXT_USHORT( p );
 
         OTL_CHECK( num_glyphs * 2 );
-
       }
       break;
 
@@ -442,6 +484,8 @@
   otl_lookup_validate( OTL_Bytes          table,
                        OTL_UInt           type_count,
                        OTL_ValidateFunc*  type_funcs,
+                       OTL_UInt           lookup_count,
+                       OTL_UInt           glyph_count,
                        OTL_Validator      valid )
   {
     OTL_Bytes         p = table;
@@ -463,7 +507,8 @@
 
     /* scan subtables */
     for ( ; num_subtables > 0; num_subtables-- )
-      validate( table + OTL_NEXT_USHORT( p ), valid );
+      validate( table + OTL_NEXT_USHORT( p ), lookup_count, glyph_count,
+                valid );
   }
 
 
@@ -511,10 +556,11 @@
   otl_lookup_list_validate( OTL_Bytes          table,
                             OTL_UInt           type_count,
                             OTL_ValidateFunc*  type_funcs,
+                            OTL_UInt           glyph_count,
                             OTL_Validator      valid )
   {
     OTL_Bytes  p = table;
-    OTL_UInt   num_lookups;
+    OTL_UInt   num_lookups, count;
 
 
     OTL_CHECK( 2 );
@@ -522,9 +568,10 @@
     OTL_CHECK( 2 * num_lookups );
 
     /* scan lookup records */
-    for ( ; num_lookups > 0; num_lookups-- )
+    for ( count = num_lookups; count > 0; count-- )
       otl_lookup_validate( table + OTL_NEXT_USHORT( p ),
-                           type_count, type_funcs, valid );
+                           type_count, type_funcs,
+                           num_lookups, glyph_count, valid );
   }
 
 
--- a/src/otlayout/otlcommn.h
+++ b/src/otlayout/otlcommn.h
@@ -37,6 +37,14 @@
   otl_coverage_validate( OTL_Bytes      table,
                          OTL_Validator  valid );
 
+  /* return first covered glyph */
+  OTL_LOCAL( OTL_UInt )
+  otl_coverage_get_first( OTL_Bytes  table );
+
+  /* return last covered glyph */
+  OTL_LOCAL( OTL_UInt )
+  otl_coverage_get_last( OTL_Bytes  table );
+
   /* return number of covered glyphs */
   OTL_LOCAL( OTL_UInt )
   otl_coverage_get_count( OTL_Bytes  table );
@@ -116,6 +124,8 @@
   otl_lookup_validate( OTL_Bytes          table,
                        OTL_UInt           type_count,
                        OTL_ValidateFunc*  type_funcs,
+                       OTL_UInt           lookup_count,
+                       OTL_UInt           glyph_count,
                        OTL_Validator      valid );
 
   /* return number of sub-tables in a lookup */
@@ -143,6 +153,7 @@
   otl_lookup_list_validate( OTL_Bytes          table,
                             OTL_UInt           type_count,
                             OTL_ValidateFunc*  type_funcs,
+                            OTL_UInt           glyph_count,
                             OTL_Validator      valid );
 
 #if 0
--- a/src/otlayout/otlgpos.c
+++ b/src/otlayout/otlgpos.c
@@ -173,12 +173,17 @@
 
   static void
   otl_gpos_lookup1_validate( OTL_Bytes      table,
+                             OTL_UInt       lookup_count,
+                             OTL_UInt       glyph_count,
                              OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
     OTL_UInt   format;
 
+    OTL_UNUSED( lookup_count );
+    OTL_UNUSED( glyph_count );
 
+
     OTL_CHECK( 2 );
     format = OTL_NEXT_USHORT( p );
     switch ( format )
@@ -270,12 +275,17 @@
 
   static void
   otl_gpos_lookup2_validate( OTL_Bytes      table,
+                             OTL_UInt       lookup_count,
+                             OTL_UInt       glyph_count,
                              OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
     OTL_UInt   format;
 
+    OTL_UNUSED( lookup_count );
+    OTL_UNUSED( glyph_count );
 
+
     OTL_CHECK( 2 );
     format = OTL_NEXT_USHORT( p );
     switch ( format )
@@ -354,12 +364,17 @@
 
   static void
   otl_gpos_lookup3_validate( OTL_Bytes      table,
+                             OTL_UInt       lookup_count,
+                             OTL_UInt       glyph_count,
                              OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
     OTL_UInt   format;
 
+    OTL_UNUSED( lookup_count );
+    OTL_UNUSED( glyph_count );
 
+
     OTL_CHECK( 2 );
     format = OTL_NEXT_USHORT( p );
     switch ( format )
@@ -430,12 +445,17 @@
 
   static void
   otl_gpos_lookup4_validate( OTL_Bytes      table,
+                             OTL_UInt       lookup_count,
+                             OTL_UInt       glyph_count,
                              OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
     OTL_UInt   format;
 
+    OTL_UNUSED( lookup_count );
+    OTL_UNUSED( glyph_count );
 
+
     OTL_CHECK( 2 );
     format = OTL_NEXT_USHORT( p );
     switch ( format )
@@ -466,6 +486,7 @@
     }
   }
 
+
   /*************************************************************************/
   /*************************************************************************/
   /*****                                                               *****/
@@ -529,12 +550,17 @@
 
   static void
   otl_gpos_lookup5_validate( OTL_Bytes      table,
+                             OTL_UInt       lookup_count,
+                             OTL_UInt       glyph_count,
                              OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
     OTL_UInt   format;
 
+    OTL_UNUSED( lookup_count );
+    OTL_UNUSED( glyph_count );
 
+
     OTL_CHECK( 2 );
     format = OTL_NEXT_USHORT( p );
     switch ( format )
@@ -576,12 +602,17 @@
 
   static void
   otl_gpos_lookup6_validate( OTL_Bytes      table,
+                             OTL_UInt       lookup_count,
+                             OTL_UInt       glyph_count,
                              OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
     OTL_UInt   format;
 
+    OTL_UNUSED( lookup_count );
+    OTL_UNUSED( glyph_count );
 
+
     OTL_CHECK( 2 );
     format = OTL_NEXT_USHORT( p );
     switch ( format )
@@ -623,6 +654,7 @@
   /* used for both format 1 and 2 */
   static void
   otl_pos_rule_validate( OTL_Bytes      table,
+                         OTL_UInt       lookup_count,
                          OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
@@ -638,8 +670,15 @@
 
     OTL_CHECK( ( num_glyphs - 1 ) * 2 + num_pos * 4 );
 
-    /* XXX: check pos lookups */
+    for ( ; num_pos > 0; num_pos-- )
+    {
+      if ( OTL_NEXT_USHORT( p ) >= num_glyphs )
+        OTL_INVALID_DATA;
 
+      if ( OTL_NEXT_USHORT( p ) >= lookup_count )
+        OTL_INVALID_DATA;
+    }
+
     /* no need to check glyph indices/classes used as input for this  */
     /* context rule since even invalid glyph indices/classes return a */
     /* meaningful result                                              */
@@ -649,6 +688,7 @@
   /* used for both format 1 and 2 */
   static void
   otl_pos_rule_set_validate( OTL_Bytes      table,
+                             OTL_UInt       lookup_count,
                              OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
@@ -662,18 +702,23 @@
 
     /* scan posrule records */
     for ( ; num_posrules > 0; num_posrules-- )
-      otl_pos_rule_validate( table + OTL_NEXT_USHORT( p ), valid );
+      otl_pos_rule_validate( table + OTL_NEXT_USHORT( p ), lookup_count,
+                             valid );
   }
 
 
   static void
   otl_gpos_lookup7_validate( OTL_Bytes      table,
+                             OTL_UInt       lookup_count,
+                             OTL_UInt       glyph_count,
                              OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
     OTL_UInt   format;
 
+    OTL_UNUSED( glyph_count );
 
+
     OTL_CHECK( 2 );
     format = OTL_NEXT_USHORT( p );
     switch ( format )
@@ -693,7 +738,8 @@
 
         /* scan posrule set records */
         for ( ; num_posrule_sets > 0; num_posrule_sets-- )
-          otl_pos_rule_set_validate( table + OTL_NEXT_USHORT( p ), valid );
+          otl_pos_rule_set_validate( table + OTL_NEXT_USHORT( p ),
+                                     lookup_count, valid );
       }
       break;
 
@@ -714,13 +760,19 @@
 
         /* scan pos class set rules */
         for ( ; num_posclass_sets > 0; num_posclass_sets-- )
-          otl_pos_rule_set_validate( table + OTL_NEXT_USHORT( p ), valid );
+        {
+          OTL_UInt  offset = OTL_NEXT_USHORT( p );
+
+
+          if ( offset )
+            otl_pos_rule_set_validate( table + offset, lookup_count, valid );
+        }
       }
       break;
 
     case 3:
       {
-        OTL_UInt  num_glyphs, num_pos;
+        OTL_UInt  num_glyphs, num_pos, count;
 
 
         OTL_CHECK( 4 );
@@ -729,10 +781,17 @@
 
         OTL_CHECK( num_glyphs * 2 + num_pos * 4 );
 
-        for ( ; num_glyphs > 0; num_glyphs-- )
+        for ( count = num_glyphs; count > 0; count-- )
           otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
 
-        /* XXX: check pos lookups */
+        for ( ; num_pos > 0; num_pos-- )
+        {
+          if ( OTL_NEXT_USHORT( p ) >= num_glyphs )
+            OTL_INVALID_DATA;
+
+          if ( OTL_NEXT_USHORT( p ) >= lookup_count )
+            OTL_INVALID_DATA;
+        }
       }
       break;
 
@@ -753,6 +812,7 @@
   /* used for both format 1 and 2 */
   static void
   otl_chain_pos_rule_validate( OTL_Bytes      table,
+                               OTL_UInt       lookup_count,
                                OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
@@ -780,7 +840,18 @@
     num_pos = OTL_NEXT_USHORT( p );
     OTL_CHECK( num_pos * 4 );
 
-    /* XXX: check pos lookups */
+    for ( ; num_pos > 0; num_pos-- )
+    {
+      if ( OTL_NEXT_USHORT( p ) >= num_input_glyphs )
+        OTL_INVALID_DATA;
+
+      if ( OTL_NEXT_USHORT( p ) >= lookup_count )
+        OTL_INVALID_DATA;
+    }
+
+    /* no need to check glyph indices/classes used as input for this  */
+    /* context rule since even invalid glyph indices/classes return a */
+    /* meaningful result                                              */
   }
 
 
@@ -787,31 +858,37 @@
   /* used for both format 1 and 2 */
   static void
   otl_chain_pos_rule_set_validate( OTL_Bytes      table,
+                                   OTL_UInt       lookup_count,
                                    OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
-    OTL_UInt   count;
+    OTL_UInt   num_chain_subrules;
 
 
     OTL_CHECK( 2 );
-    count = OTL_NEXT_USHORT( p );
+    num_chain_subrules = OTL_NEXT_USHORT( p );
 
-    OTL_CHECK( 2 * count );
+    OTL_CHECK( num_chain_subrules * 2 );
 
     /* scan chain pos rule records */
-    for ( ; count > 0; count-- )
-      otl_chain_pos_rule_validate( table + OTL_NEXT_USHORT( p ), valid );
+    for ( ; num_chain_subrules > 0; num_chain_subrules-- )
+      otl_chain_pos_rule_validate( table + OTL_NEXT_USHORT( p ),
+                                   lookup_count, valid );
   }
 
 
   static void
   otl_gpos_lookup8_validate( OTL_Bytes      table,
+                             OTL_UInt       lookup_count,
+                             OTL_UInt       glyph_count,
                              OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
     OTL_UInt   format;
 
+    OTL_UNUSED( glyph_count );
 
+
     OTL_CHECK( 2 );
     format = OTL_NEXT_USHORT( p );
     switch ( format )
@@ -832,7 +909,7 @@
         /* scan chain pos ruleset records */
         for ( ; num_chain_pos_rulesets > 0; num_chain_pos_rulesets-- )
           otl_chain_pos_rule_set_validate( table + OTL_NEXT_USHORT( p ),
-                                           valid );
+                                           lookup_count, valid );
       }
       break;
 
@@ -859,8 +936,14 @@
 
         /* scan chainpos class set records */
         for ( ; num_chainpos_class_sets > 0; num_chainpos_class_sets-- )
-          otl_chain_pos_rule_set_validate( table + OTL_NEXT_USHORT( p ),
-                                           valid );
+        {
+          OTL_UInt  offset = OTL_NEXT_USHORT( p );
+
+
+          if ( offset )
+            otl_chain_pos_rule_set_validate( table + offset, lookup_count,
+                                             valid );
+        }
       }
       break;
 
@@ -867,25 +950,25 @@
     case 3:
       {
         OTL_UInt  num_backtrack_glyphs, num_input_glyphs;
-        OTL_UInt  num_lookahead_glyphs, num_pos;
+        OTL_UInt  num_lookahead_glyphs, num_pos, count;
 
 
         OTL_CHECK( 2 );
+
         num_backtrack_glyphs = OTL_NEXT_USHORT( p );
+        OTL_CHECK( num_backtrack_glyphs * 2 + 2 );
 
-        OTL_CHECK( 2 * num_backtrack_glyphs + 2 );
-
         for ( ; num_backtrack_glyphs > 0; num_backtrack_glyphs-- )
           otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
 
         num_input_glyphs = OTL_NEXT_USHORT( p );
-        OTL_CHECK( 2 * num_input_glyphs + 2 );
+        OTL_CHECK( num_input_glyphs * 2 + 2 );
 
-        for ( ; num_input_glyphs > 0; num_input_glyphs-- )
+        for ( count = num_input_glyphs; count > 0; count-- )
           otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
 
         num_lookahead_glyphs = OTL_NEXT_USHORT( p );
-        OTL_CHECK( 2 * num_lookahead_glyphs + 2 );
+        OTL_CHECK( num_lookahead_glyphs * 2 + 2 );
 
         for ( ; num_lookahead_glyphs > 0; num_lookahead_glyphs-- )
           otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
@@ -893,7 +976,14 @@
         num_pos = OTL_NEXT_USHORT( p );
         OTL_CHECK( num_pos * 4 );
 
-        /* XXX: check pos lookups */
+        for ( ; num_pos > 0; num_pos-- )
+        {
+          if ( OTL_NEXT_USHORT( p ) >= num_input_glyphs )
+            OTL_INVALID_DATA;
+
+          if ( OTL_NEXT_USHORT( p ) >= lookup_count )
+            OTL_INVALID_DATA;
+        }
       }
       break;
 
@@ -913,6 +1003,8 @@
 
   static void
   otl_gpos_lookup9_validate( OTL_Bytes      table,
+                             OTL_UInt       lookup_count,
+                             OTL_UInt       glyph_count,
                              OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
@@ -937,7 +1029,7 @@
           OTL_INVALID_DATA;
 
         validate = otl_gpos_validate_funcs[lookup_type - 1];
-        validate( table + lookup_offset, valid );
+        validate( table + lookup_offset, lookup_count, glyph_count, valid );
       }
       break;
 
@@ -963,9 +1055,11 @@
 
   OTL_LOCALDEF( void )
   otl_gpos_subtable_validate( OTL_Bytes      table,
+                              OTL_UInt       glyph_count,
                               OTL_Validator  valid )
   {
-    otl_lookup_list_validate( table, 9, otl_gpos_validate_funcs, valid );
+    otl_lookup_list_validate( table, 9, otl_gpos_validate_funcs,
+                              glyph_count, valid );
   }
 
 
@@ -979,6 +1073,7 @@
 
   OTL_LOCALDEF( void )
   otl_gpos_validate( OTL_Bytes      table,
+                     OTL_UInt       glyph_count,
                      OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
@@ -994,7 +1089,7 @@
     features = OTL_NEXT_USHORT( p );
     lookups  = OTL_NEXT_USHORT( p );
 
-    otl_gpos_subtable_validate( table + lookups, valid );
+    otl_gpos_subtable_validate( table + lookups, glyph_count, valid );
     otl_feature_list_validate( table + features, table + lookups, valid );
     otl_script_list_validate( table + scripts, table + features, valid );
   }
--- a/src/otlayout/otlgpos.h
+++ b/src/otlayout/otlgpos.h
@@ -26,10 +26,12 @@
 
   OTL_LOCAL( void )
   otl_gpos_subtable_validate( OTL_Bytes      table,
+                              OTL_UInt       glyph_count,
                               OTL_Validator  valid );
 
   OTL_LOCAL( void )
   otl_gpos_validate( OTL_Bytes      table,
+                     OTL_UInt       glyph_count,
                      OTL_Validator  valid );
 
 
--- a/src/otlayout/otlgsub.c
+++ b/src/otlayout/otlgsub.c
@@ -57,12 +57,16 @@
 
   static void
   otl_gsub_lookup1_validate( OTL_Bytes      table,
+                             OTL_UInt       lookup_count,
+                             OTL_UInt       glyph_count,
                              OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
     OTL_UInt   format;
 
+    OTL_UNUSED( lookup_count );
 
+
     OTL_CHECK( 2 );
     format = OTL_NEXT_USHORT( p );
 
@@ -69,12 +73,26 @@
     switch ( format )
     {
     case 1:
-      OTL_CHECK( 4 );
+      {
+        OTL_Bytes  coverage;
+        OTL_Int    delta;
+        OTL_Long   idx;
 
-      otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
 
-      /* skip delta glyph ID */
+        OTL_CHECK( 4 );
+        coverage = table + OTL_NEXT_USHORT( p );
+        delta    = OTL_NEXT_SHORT( p );
 
+        otl_coverage_validate( coverage, valid );
+
+        idx = otl_coverage_get_first( coverage ) + delta;
+        if ( idx < 0 )
+          OTL_INVALID_DATA;
+
+        idx = otl_coverage_get_last( coverage ) + delta;
+        if ( (OTL_UInt)idx >= glyph_count )
+          OTL_INVALID_DATA;
+      }
       break;
 
     case 2:
@@ -88,11 +106,11 @@
 
         otl_coverage_validate( table + coverage, valid );
 
-        OTL_CHECK( 2 * num_glyphs );
+        OTL_CHECK( num_glyphs * 2 );
 
-        /* We don't check that there are at most `num_glyphs' */
-        /* elements in the coverage table.  This is delayed   */
-        /* to the lookup function.                            */
+        for ( ; num_glyphs > 0; num_glyphs-- )
+          if ( OTL_NEXT_USHORT( p ) >= glyph_count )
+            OTL_INVALID_DATA;
       }
       break;
 
@@ -198,6 +216,7 @@
 
   static void
   otl_sequence_validate( OTL_Bytes      table,
+                         OTL_UInt       glyph_count,
                          OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
@@ -207,23 +226,29 @@
     OTL_CHECK( 2 );
     num_glyphs = OTL_NEXT_USHORT( p );
 
-    /* XXX: according to the spec, `num_glyphs' should be > 0; */
-    /*      we can deal with these cases pretty well, however  */
+    /* according to the specification, `num_glyphs' should be > 0; */
+    /* we can deal with these cases pretty well, however           */
 
-    OTL_CHECK( 2 * num_glyphs );
+    OTL_CHECK( num_glyphs * 2 );
 
-    /* XXX: check glyph indices */
+    for ( ; num_glyphs > 0; num_glyphs-- )
+      if ( OTL_NEXT_USHORT( p ) >= glyph_count )
+        OTL_INVALID_DATA;
   }
 
 
   static void
   otl_gsub_lookup2_validate( OTL_Bytes      table,
+                             OTL_UInt       lookup_count,
+                             OTL_UInt       glyph_count,
                              OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
     OTL_UInt   format;
 
+    OTL_UNUSED( lookup_count );
 
+
     OTL_CHECK( 2 );
     format = OTL_NEXT_USHORT( p );
     switch ( format )
@@ -243,7 +268,8 @@
 
         /* scan sequence records */
         for ( ; num_sequences > 0; num_sequences-- )
-          otl_sequence_validate( table + OTL_NEXT_USHORT( p ), valid );
+          otl_sequence_validate( table + OTL_NEXT_USHORT( p ), glyph_count,
+                                 valid );
       }
       break;
 
@@ -329,29 +355,36 @@
 
   static void
   otl_alternate_set_validate( OTL_Bytes      table,
+                              OTL_UInt       glyph_count,
                               OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
-    OTL_UInt   count;
+    OTL_UInt   num_glyphs;
 
 
     OTL_CHECK( 2 );
-    count = OTL_NEXT_USHORT( p );
+    num_glyphs = OTL_NEXT_USHORT( p );
 
-    OTL_CHECK( 2 * count );
+    OTL_CHECK( num_glyphs * 2 );
 
-    /* XXX: check glyph indices */
+    for ( ; num_glyphs > 0; num_glyphs-- )
+      if ( OTL_NEXT_USHORT( p ) >= glyph_count )
+        OTL_INVALID_DATA;
   }
 
 
   static void
   otl_gsub_lookup3_validate( OTL_Bytes      table,
+                             OTL_UInt       lookup_count,
+                             OTL_UInt       glyph_count,
                              OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
     OTL_UInt   format;
 
+    OTL_UNUSED( lookup_count );
 
+
     OTL_CHECK( 2 );
     format = OTL_NEXT_USHORT( p );
     switch ( format )
@@ -367,11 +400,12 @@
 
         otl_coverage_validate( table + coverage, valid );
 
-        OTL_CHECK( 2 * num_alternate_sets );
+        OTL_CHECK( num_alternate_sets * 2 );
 
         /* scan alternate set records */
         for ( ; num_alternate_sets > 0; num_alternate_sets-- )
-          otl_alternate_set_validate( table + OTL_NEXT_USHORT( p ), valid );
+          otl_alternate_set_validate( table + OTL_NEXT_USHORT( p ),
+                                      glyph_count, valid );
       }
       break;
 
@@ -442,6 +476,7 @@
 
   static void
   otl_ligature_validate( OTL_Bytes      table,
+                         OTL_UInt       glyph_count,
                          OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
@@ -455,14 +490,19 @@
     if ( num_components == 0 )
       OTL_INVALID_DATA;
 
-    OTL_CHECK( 2 * ( num_components - 1 ) );
+    num_components--;
 
-    /* XXX: check glyph indices */
+    OTL_CHECK( num_components * 2 );
+
+    for ( ; num_components > 0; num_components-- )
+      if ( OTL_NEXT_USHORT( p ) >= glyph_count )
+        OTL_INVALID_DATA;
   }
 
 
   static void
   otl_ligature_set_validate( OTL_Bytes      table,
+                             OTL_UInt       glyph_count,
                              OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
@@ -472,22 +512,27 @@
     OTL_CHECK( 2 );
     num_ligatures = OTL_NEXT_USHORT( p );
 
-    OTL_CHECK( 2 * num_ligatures );
+    OTL_CHECK( num_ligatures * 2 );
 
     /* scan ligature records */
     for ( ; num_ligatures > 0; num_ligatures-- )
-      otl_ligature_validate( table + OTL_NEXT_USHORT( p ), valid );
+      otl_ligature_validate( table + OTL_NEXT_USHORT( p ), glyph_count,
+                             valid );
   }
 
 
   static void
   otl_gsub_lookup4_validate( OTL_Bytes      table,
+                             OTL_UInt       lookup_count,
+                             OTL_UInt       glyph_count,
                              OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
     OTL_UInt   format;
 
+    OTL_UNUSED( lookup_count);
 
+
     OTL_CHECK( 2 );
     format = OTL_NEXT_USHORT( p );
     switch ( format )
@@ -503,11 +548,12 @@
 
         otl_coverage_validate( table + coverage, valid );
 
-        OTL_CHECK( 2 * num_ligsets );
+        OTL_CHECK( num_ligsets * 2 );
 
         /* scan ligature set records */
         for ( ; num_ligsets > 0; num_ligsets-- )
-          otl_ligature_set_validate( table + OTL_NEXT_USHORT( p ), valid );
+          otl_ligature_set_validate( table + OTL_NEXT_USHORT( p ),
+                                     glyph_count, valid );
       }
       break;
 
@@ -525,8 +571,10 @@
   /*************************************************************************/
   /*************************************************************************/
 
+  /* used for both format 1 and 2 */
   static void
   otl_sub_rule_validate( OTL_Bytes      table,
+                         OTL_UInt       lookup_count,
                          OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
@@ -542,12 +590,25 @@
 
     OTL_CHECK( ( num_glyphs - 1 ) * 2 + num_subst * 4 );
 
-    /* XXX: check glyph indices and subst lookups */
+    for ( ; num_subst > 0; num_subst-- )
+    {
+      if ( OTL_NEXT_USHORT( p ) >= num_glyphs )
+        OTL_INVALID_DATA;
+
+      if ( OTL_NEXT_USHORT( p ) >= lookup_count )
+        OTL_INVALID_DATA;
+    }
+
+    /* no need to check glyph indices/classes used as input for this  */
+    /* context rule since even invalid glyph indices/classes return a */
+    /* meaningful result                                              */
   }
 
 
+  /* used for both format 1 and 2 */
   static void
   otl_sub_rule_set_validate( OTL_Bytes      table,
+                             OTL_UInt       lookup_count,
                              OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
@@ -557,65 +618,27 @@
     OTL_CHECK( 2 );
     num_subrules = OTL_NEXT_USHORT( p );
 
-    OTL_CHECK( 2 * num_subrules );
+    OTL_CHECK( num_subrules * 2 );
 
-    /* scan sub rule records */
-    for ( ; num_subrules > 0; num_subrules-- )
-      otl_sub_rule_validate( table + OTL_NEXT_USHORT( p ), valid );
-  }
-
-
-  static void
-  otl_sub_class_rule_validate( OTL_Bytes      table,
-                               OTL_Validator  valid )
-  {
-    OTL_Bytes  p = table;
-    OTL_UInt   num_glyphs, num_subst;
-
-
-    OTL_CHECK( 4 );
-    num_glyphs = OTL_NEXT_USHORT( p );
-    num_subst  = OTL_NEXT_USHORT( p );
-
-    if ( num_glyphs == 0 )
-      OTL_INVALID_DATA;
-
-    OTL_CHECK( ( num_glyphs - 1 ) * 2 + num_subst * 4 );
-
-    /* XXX: check subst lookups */
-
-    /* no need to check glyph indices used as input for this context    */
-    /* rule since even invalid glyph indices return a meaningful result */
-  }
-
-
-  static void
-  otl_sub_class_rule_set_validate( OTL_Bytes      table,
-                                   OTL_Validator  valid )
-  {
-    OTL_Bytes  p = table;
-    OTL_UInt   num_subrules;
-
-
-    OTL_CHECK( 2 );
-    num_subrules = OTL_NEXT_USHORT( p );
-
-    OTL_CHECK( 2 * num_subrules );
-
     /* scan subrule records */
     for ( ; num_subrules > 0; num_subrules-- )
-      otl_sub_class_rule_validate( table + OTL_NEXT_USHORT( p ), valid );
+      otl_sub_rule_validate( table + OTL_NEXT_USHORT( p ), lookup_count,
+                             valid );
   }
 
 
   static void
   otl_gsub_lookup5_validate( OTL_Bytes      table,
+                             OTL_UInt       lookup_count,
+                             OTL_UInt       glyph_count,
                              OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
     OTL_UInt   format;
 
+    OTL_UNUSED( glyph_count );
 
+
     OTL_CHECK( 2 );
     format = OTL_NEXT_USHORT( p );
     switch ( format )
@@ -631,11 +654,12 @@
 
         otl_coverage_validate( table + coverage, valid );
 
-        OTL_CHECK( 2 * num_subrulesets );
+        OTL_CHECK( num_subrulesets * 2 );
 
         /* scan subrule set records */
         for ( ; num_subrulesets > 0; num_subrulesets-- )
-          otl_sub_rule_set_validate( table + OTL_NEXT_USHORT( p ), valid );
+          otl_sub_rule_set_validate( table + OTL_NEXT_USHORT( p ),
+                                     lookup_count, valid );
       }
       break;
 
@@ -652,18 +676,23 @@
         otl_coverage_validate( table + coverage, valid );
         otl_class_definition_validate( table + class_def, valid );
 
-        OTL_CHECK( 2 * num_subclass_sets );
+        OTL_CHECK( num_subclass_sets * 2 );
 
         /* scan subclass set records */
         for ( ; num_subclass_sets > 0; num_subclass_sets-- )
-          otl_sub_class_rule_set_validate( table + OTL_NEXT_USHORT( p ),
-                                           valid );
+        {
+          OTL_UInt  offset = OTL_NEXT_USHORT( p );
+
+
+          if ( offset )
+            otl_sub_rule_set_validate( table + offset, lookup_count, valid );
+        }
       }
       break;
 
     case 3:
       {
-        OTL_UInt  num_glyphs, num_subst;
+        OTL_UInt  num_glyphs, num_subst, count;
 
 
         OTL_CHECK( 4 );
@@ -670,12 +699,19 @@
         num_glyphs = OTL_NEXT_USHORT( p );
         num_subst  = OTL_NEXT_USHORT( p );
 
-        OTL_CHECK( 2 * num_glyphs + 4 * num_subst );
+        OTL_CHECK( num_glyphs * 2 + num_subst * 4 );
 
-        for ( ; num_glyphs > 0; num_glyphs-- )
+        for ( count = num_glyphs; count > 0; count-- )
           otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
 
-        /* XXX: check subst lookups */
+        for ( ; num_subst > 0; num_subst-- )
+        {
+          if ( OTL_NEXT_USHORT( p ) >= num_glyphs )
+            OTL_INVALID_DATA;
+
+          if ( OTL_NEXT_USHORT( p ) >= lookup_count )
+            OTL_INVALID_DATA;
+        }
       }
       break;
 
@@ -696,6 +732,7 @@
   /* used for both format 1 and 2 */
   static void
   otl_chain_sub_rule_validate( OTL_Bytes      table,
+                               OTL_UInt       lookup_count,
                                OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
@@ -706,27 +743,35 @@
     OTL_CHECK( 2 );
     num_backtrack_glyphs = OTL_NEXT_USHORT( p );
 
-    OTL_CHECK( 2 * num_backtrack_glyphs + 2 );
-    p += 2 * num_backtrack_glyphs;
+    OTL_CHECK( num_backtrack_glyphs * 2 + 2 );
+    p += num_backtrack_glyphs * 2;
 
     num_input_glyphs = OTL_NEXT_USHORT( p );
     if ( num_input_glyphs == 0 )
       OTL_INVALID_DATA;
 
-    OTL_CHECK( 2 * num_input_glyphs );
-    p += 2 * ( num_input_glyphs - 1 );
+    OTL_CHECK( num_input_glyphs * 2 );
+    p += ( num_input_glyphs - 1 ) * 2;
 
     num_lookahead_glyphs = OTL_NEXT_USHORT( p );
-    OTL_CHECK( 2 * num_lookahead_glyphs + 2 );
-    p += 2 * num_lookahead_glyphs;
+    OTL_CHECK( num_lookahead_glyphs * 2 + 2 );
+    p += num_lookahead_glyphs * 2;
 
     num_subst = OTL_NEXT_USHORT( p );
-    OTL_CHECK( 4 * num_subst );
+    OTL_CHECK( num_subst * 4 );
 
-    /* XXX: check subst lookups */
+    for ( ; num_subst > 0; num_subst-- )
+    {
+      if ( OTL_NEXT_USHORT( p ) >= num_input_glyphs )
+        OTL_INVALID_DATA;
 
-    /* no need to check glyph indices used as input for this context    */
-    /* rule since even invalid glyph indices return a meaningful result */
+      if ( OTL_NEXT_USHORT( p ) >= lookup_count )
+        OTL_INVALID_DATA;
+    }
+
+    /* no need to check glyph indices/classes used as input for this  */
+    /* context rule since even invalid glyph indices/classes return a */
+    /* meaningful result                                              */
   }
 
 
@@ -733,6 +778,7 @@
   /* used for both format 1 and 2 */
   static void
   otl_chain_sub_rule_set_validate( OTL_Bytes      table,
+                                   OTL_UInt       lookup_count,
                                    OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
@@ -742,22 +788,27 @@
     OTL_CHECK( 2 );
     num_chain_subrules = OTL_NEXT_USHORT( p );
 
-    OTL_CHECK( 2 * num_chain_subrules );
+    OTL_CHECK( num_chain_subrules * 2 );
 
-    /* scan chain subrule records */
+    /* scan chain subst rule records */
     for ( ; num_chain_subrules > 0; num_chain_subrules-- )
-      otl_chain_sub_rule_validate( table + OTL_NEXT_USHORT( p ), valid );
+      otl_chain_sub_rule_validate( table + OTL_NEXT_USHORT( p ),
+                                   lookup_count, valid );
   }
 
 
   static void
   otl_gsub_lookup6_validate( OTL_Bytes      table,
+                             OTL_UInt       lookup_count,
+                             OTL_UInt       glyph_count,
                              OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
     OTL_UInt   format;
 
+    OTL_UNUSED( glyph_count );
 
+
     OTL_CHECK( 2 );
     format = OTL_NEXT_USHORT( p );
     switch ( format )
@@ -773,12 +824,12 @@
 
         otl_coverage_validate( table + coverage, valid );
 
-        OTL_CHECK( 2 * num_chain_subrulesets );
+        OTL_CHECK( num_chain_subrulesets * 2 );
 
         /* scan chain subrule set records */
         for ( ; num_chain_subrulesets > 0; num_chain_subrulesets-- )
           otl_chain_sub_rule_set_validate( table + OTL_NEXT_USHORT( p ),
-                                           valid );
+                                           lookup_count, valid );
       }
       break;
 
@@ -801,12 +852,18 @@
         otl_class_definition_validate( table + input_class, valid );
         otl_class_definition_validate( table + ahead_class, valid );
 
-        OTL_CHECK( 2 * num_chain_subclass_sets );
+        OTL_CHECK( num_chain_subclass_sets * 2 );
 
         /* scan chain subclass set records */
         for ( ; num_chain_subclass_sets > 0; num_chain_subclass_sets-- )
-          otl_chain_sub_rule_set_validate( table + OTL_NEXT_USHORT( p ),
-                                           valid );
+        {
+          OTL_UInt  offset = OTL_NEXT_USHORT( p );
+
+
+          if ( offset )
+            otl_chain_sub_rule_set_validate( table + offset, lookup_count,
+                                             valid );
+        }
       }
       break;
 
@@ -813,25 +870,25 @@
     case 3:
       {
         OTL_UInt  num_backtrack_glyphs, num_input_glyphs;
-        OTL_UInt  num_lookahead_glyphs, num_subst;
+        OTL_UInt  num_lookahead_glyphs, num_subst, count;
 
 
         OTL_CHECK( 2 );
 
         num_backtrack_glyphs = OTL_NEXT_USHORT( p );
-        OTL_CHECK( 2 * num_backtrack_glyphs + 2 );
+        OTL_CHECK( num_backtrack_glyphs * 2 + 2 );
 
         for ( ; num_backtrack_glyphs > 0; num_backtrack_glyphs-- )
           otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
 
         num_input_glyphs = OTL_NEXT_USHORT( p );
-        OTL_CHECK( 2 * num_input_glyphs + 2 );
+        OTL_CHECK( num_input_glyphs * 2 + 2 );
 
-        for ( ; num_input_glyphs > 0; num_input_glyphs-- )
+        for ( count = num_input_glyphs; count > 0; count-- )
           otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
 
         num_lookahead_glyphs = OTL_NEXT_USHORT( p );
-        OTL_CHECK( 2 * num_lookahead_glyphs + 2 );
+        OTL_CHECK( num_lookahead_glyphs * 2 + 2 );
 
         for ( ; num_lookahead_glyphs > 0; num_lookahead_glyphs-- )
           otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
@@ -839,7 +896,14 @@
         num_subst = OTL_NEXT_USHORT( p );
         OTL_CHECK( num_subst * 4 );
 
-        /* XXX: check subst lookups */
+        for ( ; num_subst > 0; num_subst-- )
+        {
+          if ( OTL_NEXT_USHORT( p ) >= num_input_glyphs )
+            OTL_INVALID_DATA;
+
+          if ( OTL_NEXT_USHORT( p ) >= lookup_count )
+            OTL_INVALID_DATA;
+        }
       }
       break;
 
@@ -859,6 +923,8 @@
 
   static void
   otl_gsub_lookup7_validate( OTL_Bytes      table,
+                             OTL_UInt       lookup_count,
+                             OTL_UInt       glyph_count,
                              OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
@@ -883,7 +949,7 @@
           OTL_INVALID_DATA;
 
         validate = otl_gsub_validate_funcs[lookup_type - 1];
-        validate( table + lookup_offset, valid );
+        validate( table + lookup_offset, lookup_count, glyph_count, valid );
       }
       break;
 
@@ -903,6 +969,8 @@
 
   static void
   otl_gsub_lookup8_validate( OTL_Bytes      table,
+                             OTL_UInt       lookup_count,
+                             OTL_UInt       glyph_count,
                              OTL_Validator  valid )
   {
     OTL_Bytes  p = table, coverage;
@@ -909,7 +977,9 @@
     OTL_UInt   format;
     OTL_UInt   num_backtrack_glyphs, num_lookahead_glyphs, num_glyphs;
 
+    OTL_UNUSED( lookup_count );
 
+
     OTL_CHECK( 2 );
     format = OTL_NEXT_USHORT( p );
     switch ( format )
@@ -922,13 +992,13 @@
 
       otl_coverage_validate( coverage, valid );
 
-      OTL_CHECK( 2 * num_backtrack_glyphs + 2 );
+      OTL_CHECK( num_backtrack_glyphs * 2 + 2 );
 
       for ( ; num_backtrack_glyphs > 0; num_backtrack_glyphs-- )
         otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
 
       num_lookahead_glyphs = OTL_NEXT_USHORT( p );
-      OTL_CHECK( 2 * num_lookahead_glyphs + 2 );
+      OTL_CHECK( num_lookahead_glyphs * 2 + 2 );
 
       for ( ; num_lookahead_glyphs > 0; num_lookahead_glyphs-- )
         otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
@@ -937,9 +1007,12 @@
       if ( num_glyphs != otl_coverage_get_count( coverage ) )
         OTL_INVALID_DATA;
 
-      OTL_CHECK( 2 * num_glyphs );
+      OTL_CHECK( num_glyphs * 2 );
 
-      /* XXX: check glyph indices */
+      for ( ; num_glyphs > 0; num_glyphs-- )
+        if ( OTL_NEXT_USHORT( p ) >= glyph_count )
+          OTL_INVALID_DATA;
+
       break;
 
     default:
@@ -971,6 +1044,7 @@
 
   OTL_LOCALDEF( void )
   otl_gsub_validate( OTL_Bytes      table,
+                     OTL_UInt       glyph_count,
                      OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
@@ -987,7 +1061,7 @@
     lookups  = OTL_NEXT_USHORT( p );
 
     otl_lookup_list_validate( table + lookups, 8, otl_gsub_validate_funcs,
-                              valid );
+                              glyph_count, valid );
     otl_feature_list_validate( table + features, table + lookups, valid );
     otl_script_list_validate( table + scripts, table + features, valid );
   }
--- a/src/otlayout/otlgsub.h
+++ b/src/otlayout/otlgsub.h
@@ -40,6 +40,7 @@
 
   OTL_LOCAL( void )
   otl_gsub_validate( OTL_Bytes      table,
+                     OTL_UInt       glyph_count,
                      OTL_Validator  valid );
 
 
--- a/src/otlayout/otljstf.c
+++ b/src/otlayout/otljstf.c
@@ -23,6 +23,7 @@
 
   static void
   otl_jstf_extender_validate( OTL_Bytes      table,
+                              OTL_UInt       glyph_count,
                               OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
@@ -35,7 +36,9 @@
 
     OTL_CHECK( num_glyphs * 2 );
 
-    /* XXX: check glyph indices */
+    for ( ; num_glyphs > 0; num_glyphs-- )
+      if ( OTL_NEXT_USHORT( p ) >= glyph_count )
+        OTL_INVALID_DATA;
   }
 
 
@@ -63,6 +66,7 @@
 
   static void
   otl_jstf_max_validate( OTL_Bytes      table,
+                         OTL_UInt       glyph_count,
                          OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
@@ -76,7 +80,8 @@
     /* scan subtable records */
     for ( ; num_lookups > 0; num_lookups-- )
       /* XXX: check lookup types? */
-      otl_gpos_subtable_validate( table + OTL_NEXT_USHORT( p ), valid );
+      otl_gpos_subtable_validate( table + OTL_NEXT_USHORT( p ), glyph_count,
+                                  valid );
   }
 
 
@@ -84,6 +89,7 @@
   otl_jstf_priority_validate( OTL_Bytes      table,
                               OTL_UInt       gsub_lookup_count,
                               OTL_UInt       gpos_lookup_count,
+                              OTL_UInt       glyph_count,
                               OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
@@ -117,7 +123,7 @@
     /* shrinkage JSTF max */
     val = OTL_NEXT_USHORT( p );
     if ( val )
-      otl_jstf_max_validate( table + val, valid );
+      otl_jstf_max_validate( table + val, glyph_count, valid );
 
     /* extension GSUB enable/disable */
     val = OTL_NEXT_USHORT( p );
@@ -144,7 +150,7 @@
     /* extension JSTF max */
     val = OTL_NEXT_USHORT( p );
     if ( val )
-      otl_jstf_max_validate( table + val, valid );
+      otl_jstf_max_validate( table + val, glyph_count, valid );
   }
 
 
@@ -152,6 +158,7 @@
   otl_jstf_lang_validate( OTL_Bytes      table,
                           OTL_UInt       gsub_lookup_count,
                           OTL_UInt       gpos_lookup_count,
+                          OTL_UInt       glyph_count,
                           OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
@@ -166,7 +173,7 @@
     for ( ; num_priorities > 0; num_priorities-- )
       otl_jstf_priority_validate( table + OTL_NEXT_USHORT( p ),
                                   gsub_lookup_count, gpos_lookup_count,
-                                  valid );
+                                  glyph_count, valid );
   }
 
 
@@ -174,6 +181,7 @@
   otl_jstf_script_validate( OTL_Bytes      table,
                             OTL_UInt       gsub_lookup_count,
                             OTL_UInt       gpos_lookup_count,
+                            OTL_UInt       glyph_count,
                             OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
@@ -186,11 +194,12 @@
     num_langsys  = OTL_NEXT_USHORT( p );
 
     if ( extender )
-      otl_jstf_extender_validate( table + extender, valid );
+      otl_jstf_extender_validate( table + extender, glyph_count, valid );
 
     if ( default_lang )
       otl_jstf_lang_validate( table + default_lang,
-                              gsub_lookup_count, gpos_lookup_count, valid );
+                              gsub_lookup_count, gpos_lookup_count,
+                              glyph_count, valid );
 
     OTL_CHECK( 6 * num_langsys );
 
@@ -200,7 +209,8 @@
       p += 4;       /* skip tag */
 
       otl_jstf_lang_validate( table + OTL_NEXT_USHORT( p ),
-                              gsub_lookup_count, gpos_lookup_count, valid );
+                              gsub_lookup_count, gpos_lookup_count,
+                              glyph_count, valid );
     }
   }
 
@@ -209,6 +219,7 @@
   otl_jstf_validate( OTL_Bytes      table,
                      OTL_Bytes      gsub,
                      OTL_Bytes      gpos,
+                     OTL_UInt       glyph_count,
                      OTL_Validator  valid )
   {
     OTL_Bytes  p = table;
@@ -239,7 +250,8 @@
       p += 4;       /* skip tag */
 
       otl_jstf_script_validate( table + OTL_NEXT_USHORT( p ),
-                                gsub_lookup_count, gpos_lookup_count, valid );
+                                gsub_lookup_count, gpos_lookup_count,
+                                glyph_count, valid );
     }
   }
 
--- a/src/otlayout/otljstf.h
+++ b/src/otlayout/otljstf.h
@@ -25,13 +25,14 @@
 OTL_BEGIN_HEADER
 
 
-  /* validate JSTF table                                         */
-  /* GSUB and GPOS tables must already be validated; if table is */
-  /* missing, set value to 0                                     */
+  /* validate JSTF table                               */
+  /* GSUB and GPOS tables should already be validated; */
+  /* if missing, set corresponding argument to 0       */
   OTL_LOCAL( void )
   otl_jstf_validate( OTL_Bytes      table,
                      OTL_Bytes      gsub,
                      OTL_Bytes      gpos,
+                     OTL_UInt       glyph_count,
                      OTL_Validator  valid );