Marcel Krüger
2018-10-23 08:53:07 UTC
Hi,
another bug in LuaTeX: If LuaTeX tries to calculate the size of a CFF table where the second entry in the table is a real number,
`pack_real` is called with `work_buffer+i` for a small `i`.
This causes aliasing issues because `work_buffer` writes into `work_buffer` using `sprintf`.
So the output from `pack_real` modifies `work_buffer` before the digits are read completely,
causing LuaTeX to complain about a "invalid character".
An example to reproduce the issue:
Run the following plainTeX document with the attached version of `LOGO10.otf` (the font was created by reordering
the Private table entries and has an invalid checksum, but this is ignored by LuaTeX)
\directlua{
font.current(font.define{
name='logo',
embedding='subset',
encodingbytes=2,
format='opentype',
filename='LOGO10.otf',
characters={
[0x41] = {
width = 1000,
height = 1000,
depth = 1000,
index = 0x2,
}
},
})
}
A
\bye
This can be fixed by adding a separate temporary buffer for `pack_real`:
diff --git a/source/texk/web2c/luatexdir/font/writecff.c b/source/texk/web2c/luatexdir/font/writecff.c
index cf0751179..1217d1a52 100644
--- a/source/texk/web2c/luatexdir/font/writecff.c
+++ b/source/texk/web2c/luatexdir/font/writecff.c
@@ -1171,6 +1171,7 @@ static long pack_integer(card8 * dest, long destlen, long value)
static long pack_real(card8 * dest, long destlen, double value)
{
+ static char temp_buffer[22];
long e;
int i = 0, pos = 2;
int res;
@@ -1199,20 +1200,18 @@ static long pack_real(card8 * dest, long destlen, double value)
e--;
}
}
- res = sprintf(work_buffer, "%1.14g", value);
+ res = sprintf(temp_buffer, "%1.14g", value);
if (res<0)
normal_error("cff","invalid conversion");
- if (res>CFF_REAL_MAX_LEN)
- res=CFF_REAL_MAX_LEN;
for (i = 0; i < res; i++) {
unsigned char ch = 0;
- if (work_buffer[i] == '\0') {
+ if (temp_buffer[i] == '\0') {
/*tex In fact |res| should prevent this. */
break;
- } else if (work_buffer[i] == '.') {
+ } else if (temp_buffer[i] == '.') {
ch = 0x0a;
- } else if (work_buffer[i] >= '0' && work_buffer[i] <= '9') {
- ch = (unsigned char) (work_buffer[i] - '0');
+ } else if (temp_buffer[i] >= '0' && temp_buffer[i] <= '9') {
+ ch = (unsigned char) (temp_buffer[i] - '0');
} else {
normal_error("cff","invalid character");
}
@@ -1247,15 +1246,15 @@ static long pack_real(card8 * dest, long destlen, double value)
pos++;
}
if (e != 0) {
- sprintf(work_buffer, "%ld", e);
+ sprintf(temp_buffer, "%ld", e);
for (i = 0; i < CFF_REAL_MAX_LEN; i++) {
unsigned char ch = 0;
- if (work_buffer[i] == '\0') {
+ if (temp_buffer[i] == '\0') {
break;
- } else if (work_buffer[i] == '.') {
+ } else if (temp_buffer[i] == '.') {
ch = 0x0a;
- } else if (work_buffer[i] >= '0' && work_buffer[i] <= '9') {
- ch = (unsigned char) (work_buffer[i] - '0');
+ } else if (temp_buffer[i] >= '0' && temp_buffer[i] <= '9') {
+ ch = (unsigned char) (temp_buffer[i] - '0');
} else {
normal_error("cff","invalid character");
}
another bug in LuaTeX: If LuaTeX tries to calculate the size of a CFF table where the second entry in the table is a real number,
`pack_real` is called with `work_buffer+i` for a small `i`.
This causes aliasing issues because `work_buffer` writes into `work_buffer` using `sprintf`.
So the output from `pack_real` modifies `work_buffer` before the digits are read completely,
causing LuaTeX to complain about a "invalid character".
An example to reproduce the issue:
Run the following plainTeX document with the attached version of `LOGO10.otf` (the font was created by reordering
the Private table entries and has an invalid checksum, but this is ignored by LuaTeX)
\directlua{
font.current(font.define{
name='logo',
embedding='subset',
encodingbytes=2,
format='opentype',
filename='LOGO10.otf',
characters={
[0x41] = {
width = 1000,
height = 1000,
depth = 1000,
index = 0x2,
}
},
})
}
A
\bye
This can be fixed by adding a separate temporary buffer for `pack_real`:
diff --git a/source/texk/web2c/luatexdir/font/writecff.c b/source/texk/web2c/luatexdir/font/writecff.c
index cf0751179..1217d1a52 100644
--- a/source/texk/web2c/luatexdir/font/writecff.c
+++ b/source/texk/web2c/luatexdir/font/writecff.c
@@ -1171,6 +1171,7 @@ static long pack_integer(card8 * dest, long destlen, long value)
static long pack_real(card8 * dest, long destlen, double value)
{
+ static char temp_buffer[22];
long e;
int i = 0, pos = 2;
int res;
@@ -1199,20 +1200,18 @@ static long pack_real(card8 * dest, long destlen, double value)
e--;
}
}
- res = sprintf(work_buffer, "%1.14g", value);
+ res = sprintf(temp_buffer, "%1.14g", value);
if (res<0)
normal_error("cff","invalid conversion");
- if (res>CFF_REAL_MAX_LEN)
- res=CFF_REAL_MAX_LEN;
for (i = 0; i < res; i++) {
unsigned char ch = 0;
- if (work_buffer[i] == '\0') {
+ if (temp_buffer[i] == '\0') {
/*tex In fact |res| should prevent this. */
break;
- } else if (work_buffer[i] == '.') {
+ } else if (temp_buffer[i] == '.') {
ch = 0x0a;
- } else if (work_buffer[i] >= '0' && work_buffer[i] <= '9') {
- ch = (unsigned char) (work_buffer[i] - '0');
+ } else if (temp_buffer[i] >= '0' && temp_buffer[i] <= '9') {
+ ch = (unsigned char) (temp_buffer[i] - '0');
} else {
normal_error("cff","invalid character");
}
@@ -1247,15 +1246,15 @@ static long pack_real(card8 * dest, long destlen, double value)
pos++;
}
if (e != 0) {
- sprintf(work_buffer, "%ld", e);
+ sprintf(temp_buffer, "%ld", e);
for (i = 0; i < CFF_REAL_MAX_LEN; i++) {
unsigned char ch = 0;
- if (work_buffer[i] == '\0') {
+ if (temp_buffer[i] == '\0') {
break;
- } else if (work_buffer[i] == '.') {
+ } else if (temp_buffer[i] == '.') {
ch = 0x0a;
- } else if (work_buffer[i] >= '0' && work_buffer[i] <= '9') {
- ch = (unsigned char) (work_buffer[i] - '0');
+ } else if (temp_buffer[i] >= '0' && temp_buffer[i] <= '9') {
+ ch = (unsigned char) (temp_buffer[i] - '0');
} else {
normal_error("cff","invalid character");
}