summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrian Johnson <ajohnson@redneon.com>2014-10-19 11:34:34 +1030
committerAdrian Johnson <ajohnson@redneon.com>2014-10-19 11:54:25 +1030
commit99a35dd273f3deb4ae54310f1ed1746bfd9fae70 (patch)
treeca70b52ccead6e24f71421207c2d5db79df9b0d9
parent5c17bf1a33b8e76edeb23121342e0f163fe9d6ad (diff)
downloadcairo-99a35dd273f3deb4ae54310f1ed1746bfd9fae70.tar.gz
CFF: Fix unaligned access
Debian bug 712836 reported bus errors in cff subsetting when running on a sparc. This is because unlike truetype, all data in the compact font format is not aligned. https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=712836
-rw-r--r--src/cairo-cff-subset.c35
-rw-r--r--src/cairo-image-info.c32
-rw-r--r--src/cairoint.h26
3 files changed, 58 insertions, 35 deletions
diff --git a/src/cairo-cff-subset.c b/src/cairo-cff-subset.c
index 4660d6e09..f15deb5ea 100644
--- a/src/cairo-cff-subset.c
+++ b/src/cairo-cff-subset.c
@@ -433,7 +433,7 @@ cff_index_read (cairo_array_t *index, unsigned char **ptr, unsigned char *end_pt
p = *ptr;
if (p + 2 > end_ptr)
return CAIRO_INT_STATUS_UNSUPPORTED;
- count = be16_to_cpu( *((uint16_t *)p) );
+ count = get_unaligned_be16 (p);
p += 2;
if (count > 0) {
offset_size = *p++;
@@ -984,14 +984,14 @@ cairo_cff_font_read_fdselect (cairo_cff_font_t *font, unsigned char *p)
for (i = 0; i < font->num_glyphs; i++)
font->fdselect[i] = *p++;
} else if (type == 3) {
- num_ranges = be16_to_cpu( *((uint16_t *)p) );
+ num_ranges = get_unaligned_be16 (p);
p += 2;
for (i = 0; i < num_ranges; i++)
{
- first = be16_to_cpu( *((uint16_t *)p) );
+ first = get_unaligned_be16 (p);
p += 2;
fd = *p++;
- last = be16_to_cpu( *((uint16_t *)p) );
+ last = get_unaligned_be16 (p);
for (j = first; j < last; j++)
font->fdselect[j] = fd;
}
@@ -1722,7 +1722,7 @@ cairo_cff_font_get_gid_for_cid (cairo_cff_font_t *font, unsigned long cid, unsi
p = font->charset + 1;
g = 1;
while (g <= (unsigned)font->num_glyphs && p < font->data_end) {
- c = be16_to_cpu( *((uint16_t *)p) );
+ c = get_unaligned_be16 (p);
if (c == cid) {
*gid = g;
return CAIRO_STATUS_SUCCESS;
@@ -1737,7 +1737,7 @@ cairo_cff_font_get_gid_for_cid (cairo_cff_font_t *font, unsigned long cid, unsi
first_gid = 1;
p = font->charset + 1;
while (first_gid <= (unsigned)font->num_glyphs && p + 2 < font->data_end) {
- first_cid = be16_to_cpu( *((uint16_t *)p) );
+ first_cid = get_unaligned_be16 (p);
num_left = p[2];
if (cid >= first_cid && cid <= first_cid + num_left) {
*gid = first_gid + cid - first_cid;
@@ -1753,8 +1753,8 @@ cairo_cff_font_get_gid_for_cid (cairo_cff_font_t *font, unsigned long cid, unsi
first_gid = 1;
p = font->charset + 1;
while (first_gid <= (unsigned)font->num_glyphs && p + 3 < font->data_end) {
- first_cid = be16_to_cpu( *((uint16_t *)p) );
- num_left = be16_to_cpu( *((uint16_t *)(p+2)) );
+ first_cid = get_unaligned_be16 (p);
+ num_left = get_unaligned_be16 (p+2);
if (cid >= first_cid && cid <= first_cid + num_left) {
*gid = first_gid + cid - first_cid;
return CAIRO_STATUS_SUCCESS;
@@ -2328,7 +2328,7 @@ cairo_cff_font_write_cid_fontdict (cairo_cff_font_t *font)
unsigned int i;
cairo_int_status_t status;
unsigned int offset_array;
- uint32_t *offset_array_ptr;
+ unsigned char *offset_array_ptr;
int offset_base;
uint16_t count;
uint8_t offset_size = 4;
@@ -2349,7 +2349,7 @@ cairo_cff_font_write_cid_fontdict (cairo_cff_font_t *font)
if (unlikely (status))
return status;
offset_base = _cairo_array_num_elements (&font->output) - 1;
- *offset_array_ptr = cpu_to_be32(1);
+ put_unaligned_be32(1, offset_array_ptr);
offset_array += sizeof(uint32_t);
for (i = 0; i < font->num_subset_fontdicts; i++) {
status = cff_dict_write (font->fd_dict[font->fd_subset_map[i]],
@@ -2357,8 +2357,9 @@ cairo_cff_font_write_cid_fontdict (cairo_cff_font_t *font)
if (unlikely (status))
return status;
- offset_array_ptr = (uint32_t *) _cairo_array_index (&font->output, offset_array);
- *offset_array_ptr = cpu_to_be32(_cairo_array_num_elements (&font->output) - offset_base);
+ offset_array_ptr = _cairo_array_index (&font->output, offset_array);
+ put_unaligned_be32 (_cairo_array_num_elements (&font->output) - offset_base,
+ offset_array_ptr);
offset_array += sizeof(uint32_t);
}
@@ -2609,7 +2610,7 @@ cairo_cff_font_create_set_widths (cairo_cff_font_t *font)
unsigned int i;
tt_hhea_t hhea;
int num_hmetrics;
- unsigned char buf[10];
+ uint16_t short_entry;
int glyph_index;
cairo_int_status_t status;
@@ -2629,7 +2630,8 @@ cairo_cff_font_create_set_widths (cairo_cff_font_t *font)
status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
TT_TAG_hmtx,
glyph_index * long_entry_size,
- buf, &short_entry_size);
+ (unsigned char *) &short_entry,
+ &short_entry_size);
if (unlikely (status))
return status;
}
@@ -2638,11 +2640,12 @@ cairo_cff_font_create_set_widths (cairo_cff_font_t *font)
status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
TT_TAG_hmtx,
(num_hmetrics - 1) * long_entry_size,
- buf, &short_entry_size);
+ (unsigned char *) &short_entry,
+ &short_entry_size);
if (unlikely (status))
return status;
}
- font->widths[i] = be16_to_cpu (*((int16_t*)buf));
+ font->widths[i] = be16_to_cpu (short_entry);
}
return CAIRO_STATUS_SUCCESS;
diff --git a/src/cairo-image-info.c b/src/cairo-image-info.c
index 64053a218..26e7ae5af 100644
--- a/src/cairo-image-info.c
+++ b/src/cairo-image-info.c
@@ -39,12 +39,6 @@
#include "cairo-error-private.h"
#include "cairo-image-info-private.h"
-static uint32_t
-_get_be32 (const unsigned char *p)
-{
- return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
-}
-
/* JPEG (image/jpeg)
*
* http://www.w3.org/Graphics/JPEG/itu-t81.pdf
@@ -170,7 +164,7 @@ static const unsigned char _jpx_signature[] = {
static const unsigned char *
_jpx_next_box (const unsigned char *p)
{
- return p + _get_be32 (p);
+ return p + get_unaligned_be32 (p);
}
static const unsigned char *
@@ -185,8 +179,8 @@ _jpx_match_box (const unsigned char *p, const unsigned char *end, uint32_t type)
uint32_t length;
if (p + 8 < end) {
- length = _get_be32 (p);
- if (_get_be32 (p + 4) == type && p + length < end)
+ length = get_unaligned_be32 (p);
+ if (get_unaligned_be32 (p + 4) == type && p + length < end)
return TRUE;
}
@@ -208,8 +202,8 @@ _jpx_find_box (const unsigned char *p, const unsigned char *end, uint32_t type)
static void
_jpx_extract_info (const unsigned char *p, cairo_image_info_t *info)
{
- info->height = _get_be32 (p);
- info->width = _get_be32 (p + 4);
+ info->height = get_unaligned_be32 (p);
+ info->width = get_unaligned_be32 (p + 4);
info->num_components = (p[8] << 8) + p[9];
info->bits_per_component = p[10];
}
@@ -281,13 +275,13 @@ _cairo_image_info_get_png_info (cairo_image_info_t *info,
return CAIRO_INT_STATUS_UNSUPPORTED;
p += 4;
- if (_get_be32 (p) != PNG_IHDR)
+ if (get_unaligned_be32 (p) != PNG_IHDR)
return CAIRO_INT_STATUS_UNSUPPORTED;
p += 4;
- info->width = _get_be32 (p);
+ info->width = get_unaligned_be32 (p);
p += 4;
- info->height = _get_be32 (p);
+ info->height = get_unaligned_be32 (p);
return CAIRO_STATUS_SUCCESS;
}
@@ -347,14 +341,14 @@ _jbig2_get_next_segment (const unsigned char *p,
if (p + 6 >= end)
return NULL;
- seg_num = _get_be32 (p);
+ seg_num = get_unaligned_be32 (p);
*type = p[4] & 0x3f;
big_page_size = (p[4] & 0x40) != 0;
p += 5;
num_segs = p[0] >> 5;
if (num_segs == 7) {
- num_segs = _get_be32 (p) & 0x1fffffff;
+ num_segs = get_unaligned_be32 (p) & 0x1fffffff;
ref_seg_bytes = 4 + ((num_segs + 1)/8);
} else {
ref_seg_bytes = 1;
@@ -373,7 +367,7 @@ _jbig2_get_next_segment (const unsigned char *p,
if (p + 4 >= end)
return NULL;
- *data_len = _get_be32 (p);
+ *data_len = get_unaligned_be32 (p);
p += 4;
*data = p;
@@ -397,8 +391,8 @@ _jbig2_get_next_segment (const unsigned char *p,
static void
_jbig2_extract_info (cairo_image_info_t *info, const unsigned char *p)
{
- info->width = _get_be32 (p);
- info->height = _get_be32 (p + 4);
+ info->width = get_unaligned_be32 (p);
+ info->height = get_unaligned_be32 (p + 4);
info->num_components = 1;
info->bits_per_component = 1;
}
diff --git a/src/cairoint.h b/src/cairoint.h
index b4e8ac87f..07ced422d 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -240,6 +240,32 @@ be32_to_cpu(uint32_t v)
#endif
+/* Unaligned big endian access
+ */
+
+static inline uint16_t get_unaligned_be16 (const unsigned char *p)
+{
+ return p[0] << 8 | p[1];
+}
+
+static inline uint32_t get_unaligned_be32 (const unsigned char *p)
+{
+ return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
+}
+
+static inline void put_unaligned_be16 (uint16_t v, unsigned char *p)
+{
+ p[0] = (v >> 8) & 0xff;
+ p[1] = v & 0xff;
+}
+
+static inline void put_unaligned_be32 (uint32_t v, unsigned char *p)
+{
+ p[0] = (v >> 24) & 0xff;
+ p[1] = (v >> 16) & 0xff;
+ p[2] = (v >> 8) & 0xff;
+ p[3] = v & 0xff;
+}
/* The glibc versions of ispace() and isdigit() are slow in UTF-8 locales.
*/