[cff] Support negative offsets

Fixes https://github.com/harfbuzz/harfbuzz/issues/4508
This commit is contained in:
Behdad Esfahbod 2023-12-05 11:58:21 -05:00
parent 7160c5b9e5
commit bf84135edd
4 changed files with 31 additions and 30 deletions

View file

@ -54,8 +54,8 @@ struct top_dict_values_t : dict_values_t<OPSTR>
}
void fini () { dict_values_t<OPSTR>::fini (); }
unsigned int charStringsOffset;
unsigned int FDArrayOffset;
int charStringsOffset;
int FDArrayOffset;
};
struct dict_opset_t : opset_t<number_t>
@ -157,11 +157,11 @@ struct top_dict_opset_t : dict_opset_t
{
switch (op) {
case OpCode_CharStrings:
dictval.charStringsOffset = env.argStack.pop_uint ();
dictval.charStringsOffset = env.argStack.pop_int ();
env.clear_args ();
break;
case OpCode_FDArray:
dictval.FDArrayOffset = env.argStack.pop_uint ();
dictval.FDArrayOffset = env.argStack.pop_int ();
env.clear_args ();
break;
case OpCode_FontMatrix:

View file

@ -41,10 +41,11 @@ using namespace OT;
using objidx_t = hb_serialize_context_t::objidx_t;
using whence_t = hb_serialize_context_t::whence_t;
/* utility macro */
/* CFF offsets can technically be negative */
template<typename Type>
static inline const Type& StructAtOffsetOrNull (const void *P, unsigned int offset)
{ return offset ? StructAtOffset<Type> (P, offset) : Null (Type); }
static inline const Type& StructAtOffsetOrNull (const void *P, int offset)
{ return offset ? * reinterpret_cast<const Type*> ((const char *) P + offset) : Null (Type); }
struct code_pair_t
{

View file

@ -763,9 +763,9 @@ struct cff1_top_dict_values_t : top_dict_values_t<cff1_top_dict_val_t>
unsigned int ros_supplement;
unsigned int cidCount;
unsigned int EncodingOffset;
unsigned int CharsetOffset;
unsigned int FDSelectOffset;
int EncodingOffset;
int CharsetOffset;
int FDSelectOffset;
table_info_t privateDictInfo;
};
@ -821,24 +821,24 @@ struct cff1_top_dict_opset_t : top_dict_opset_t<cff1_top_dict_val_t>
break;
case OpCode_Encoding:
dictval.EncodingOffset = env.argStack.pop_uint ();
dictval.EncodingOffset = env.argStack.pop_int ();
env.clear_args ();
if (unlikely (dictval.EncodingOffset == 0)) return;
break;
case OpCode_charset:
dictval.CharsetOffset = env.argStack.pop_uint ();
dictval.CharsetOffset = env.argStack.pop_int ();
env.clear_args ();
if (unlikely (dictval.CharsetOffset == 0)) return;
break;
case OpCode_FDSelect:
dictval.FDSelectOffset = env.argStack.pop_uint ();
dictval.FDSelectOffset = env.argStack.pop_int ();
env.clear_args ();
break;
case OpCode_Private:
dictval.privateDictInfo.offset = env.argStack.pop_uint ();
dictval.privateDictInfo.offset = env.argStack.pop_int ();
dictval.privateDictInfo.size = env.argStack.pop_uint ();
env.clear_args ();
break;
@ -913,7 +913,7 @@ struct cff1_private_dict_values_base_t : dict_values_t<VAL>
}
void fini () { dict_values_t<VAL>::fini (); }
unsigned int subrsOffset;
int subrsOffset;
const CFF1Subrs *localSubrs;
};
@ -948,7 +948,7 @@ struct cff1_private_dict_opset_t : dict_opset_t
env.clear_args ();
break;
case OpCode_Subrs:
dictval.subrsOffset = env.argStack.pop_uint ();
dictval.subrsOffset = env.argStack.pop_int ();
env.clear_args ();
break;
@ -990,7 +990,7 @@ struct cff1_private_dict_opset_subset_t : dict_opset_t
break;
case OpCode_Subrs:
dictval.subrsOffset = env.argStack.pop_uint ();
dictval.subrsOffset = env.argStack.pop_int ();
env.clear_args ();
break;
@ -1090,7 +1090,7 @@ struct cff1
goto fail;
hb_barrier ();
topDictIndex = &StructAtOffset<CFF1TopDictIndex> (nameIndex, nameIndex->get_size ());
topDictIndex = &StructAtOffsetOrNull<CFF1TopDictIndex> (nameIndex, nameIndex->get_size ());
if ((topDictIndex == &Null (CFF1TopDictIndex)) || !topDictIndex->sanitize (&sc) || (topDictIndex->count == 0))
goto fail;
hb_barrier ();
@ -1146,12 +1146,12 @@ struct cff1
}
}
stringIndex = &StructAtOffset<CFF1StringIndex> (topDictIndex, topDictIndex->get_size ());
stringIndex = &StructAtOffsetOrNull<CFF1StringIndex> (topDictIndex, topDictIndex->get_size ());
if ((stringIndex == &Null (CFF1StringIndex)) || !stringIndex->sanitize (&sc))
goto fail;
hb_barrier ();
globalSubrs = &StructAtOffset<CFF1Subrs> (stringIndex, stringIndex->get_size ());
globalSubrs = &StructAtOffsetOrNull<CFF1Subrs> (stringIndex, stringIndex->get_size ());
if ((globalSubrs != &Null (CFF1Subrs)) && !globalSubrs->sanitize (&sc))
goto fail;
hb_barrier ();
@ -1188,7 +1188,7 @@ struct cff1
font->init ();
if (unlikely (!font_interp.interpret (*font))) goto fail;
PRIVDICTVAL *priv = &privateDicts[i];
const hb_ubytes_t privDictStr = StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size);
const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size);
if (unlikely (!privDictStr.sanitize (&sc))) goto fail;
hb_barrier ();
num_interp_env_t env2 (privDictStr);
@ -1208,7 +1208,7 @@ struct cff1
cff1_top_dict_values_t *font = &topDict;
PRIVDICTVAL *priv = &privateDicts[0];
const hb_ubytes_t privDictStr = StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size);
const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size);
if (unlikely (!privDictStr.sanitize (&sc))) goto fail;
hb_barrier ();
num_interp_env_t env (privDictStr);

View file

@ -150,8 +150,8 @@ struct cff2_top_dict_values_t : top_dict_values_t<>
}
void fini () { top_dict_values_t<>::fini (); }
unsigned int vstoreOffset;
unsigned int FDSelectOffset;
int vstoreOffset;
int FDSelectOffset;
};
struct cff2_top_dict_opset_t : top_dict_opset_t<>
@ -169,11 +169,11 @@ struct cff2_top_dict_opset_t : top_dict_opset_t<>
break;
case OpCode_vstore:
dictval.vstoreOffset = env.argStack.pop_uint ();
dictval.vstoreOffset = env.argStack.pop_int ();
env.clear_args ();
break;
case OpCode_FDSelect:
dictval.FDSelectOffset = env.argStack.pop_uint ();
dictval.FDSelectOffset = env.argStack.pop_int ();
env.clear_args ();
break;
@ -241,7 +241,7 @@ struct cff2_private_dict_values_base_t : dict_values_t<VAL>
}
void fini () { dict_values_t<VAL>::fini (); }
unsigned int subrsOffset;
int subrsOffset;
const CFF2Subrs *localSubrs;
unsigned int ivs;
};
@ -295,7 +295,7 @@ struct cff2_private_dict_opset_t : dict_opset_t
env.clear_args ();
break;
case OpCode_Subrs:
dictval.subrsOffset = env.argStack.pop_uint ();
dictval.subrsOffset = env.argStack.pop_int ();
env.clear_args ();
break;
case OpCode_vsindexdict:
@ -344,7 +344,7 @@ struct cff2_private_dict_opset_subset_t : dict_opset_t
return;
case OpCode_Subrs:
dictval.subrsOffset = env.argStack.pop_uint ();
dictval.subrsOffset = env.argStack.pop_int ();
env.clear_args ();
break;
@ -426,7 +426,7 @@ struct cff2
if (unlikely (!top_interp.interpret (topDict))) goto fail;
}
globalSubrs = &StructAtOffset<CFF2Subrs> (cff2, cff2->topDict + cff2->topDictSize);
globalSubrs = &StructAtOffsetOrNull<CFF2Subrs> (cff2, cff2->topDict + cff2->topDictSize);
varStore = &StructAtOffsetOrNull<CFF2VariationStore> (cff2, topDict.vstoreOffset);
charStrings = &StructAtOffsetOrNull<CFF2CharStrings> (cff2, topDict.charStringsOffset);
fdArray = &StructAtOffsetOrNull<CFF2FDArray> (cff2, topDict.FDArrayOffset);