Here's what happens:
- read1 reads the #[] and proceeds to create a vector of zero
length
- allocate_vectorlike has a special case for zero length vectors:
if (len == 0)
p = XVECTOR (zero_vector);
- zero_vector is a global variable, so all zero length vectors
point to it. This can be seen when evalling:
(eq [] []) ; Evalutes to t
(eq [1 2 3] [1 2 3]) ; Evaluates to nil
- After read1 creates the zero_vector, it sets bits in the size
field to indicate it is a PVEC_COMPILED pseudo vector
- The global zero_vector is thereafter a PVEC_COMPILED pseudo
vector, including the empty vector of the font data
- Later, the font_list_entities function checks the size of the
font data vector using ASIZE. It does not expect a pseudo vector,
so it makes no such checks.
- Because the pseudo vector bits are set, the size is very large
- Indexing too far into the font data vector results in a core dump
What should the behavior be? Perhaps (eval #[]) should evaluate to []
instead of #[]?
Maybe an eassert in font_list_entities that its vector is not a pseudo
vector couldn't hurt either?