diff options
author | Ken Sharp <ken.sharp@artifex.com> | 2020-03-08 00:26:16 +0000 |
---|---|---|
committer | Ken Sharp <ken.sharp@artifex.com> | 2020-03-08 00:26:16 +0000 |
commit | 56840269a9df474a029f12ce8e4e41bb2abea313 (patch) | |
tree | 27ea01e9d83c6b5b425a6c8dcedd9250ba20dc80 | |
parent | 933a09069dea35d570694e157013f272995ca5c4 (diff) | |
download | ghostpdl-56840269a9df474a029f12ce8e4e41bb2abea313.tar.gz |
PS interpreter some 64-bit integer fixes
Bug #702194 "cvi produces incorrect results"
This was simply caused by a cast through long. However its not enough
merely to change the cast, we must also check for running in CPSI mode
and throw an error if the returned integer cannot be represented in a
32-bit word, for compatibility with test suites.
In addition (see bug #702134) when exp throws an undefinedresult error
delay setting the stack variable until after we have tested the result,
so that we do not end up returning a INF on the stack, as is done in
other code paths which check for NaN and INF.
Thirdly; in div cater for the case of an integer divided by a real and
check the result for NaN and INF (as the other cases do). This now
properly throws an error and does not return NaN or INF on the stack.
-rw-r--r-- | psi/zarith.c | 8 | ||||
-rw-r--r-- | psi/zmath.c | 2 | ||||
-rw-r--r-- | psi/ztype.c | 13 |
3 files changed, 21 insertions, 2 deletions
diff --git a/psi/zarith.c b/psi/zarith.c index fce9686e8..cb624a438 100644 --- a/psi/zarith.c +++ b/psi/zarith.c @@ -148,6 +148,14 @@ zdiv(i_ctx_t *i_ctx_p) break; case t_integer: result = (double)op1->value.intval / op->value.realval; +#ifdef HAVE_ISINF + if (isinf(result)) + return_error(gs_error_undefinedresult); +#endif +#ifdef HAVE_ISNAN + if (isnan(result)) + return_error(gs_error_undefinedresult); +#endif make_real(op1, result); } break; diff --git a/psi/zmath.c b/psi/zmath.c index d6ecae233..f6bf3a787 100644 --- a/psi/zmath.c +++ b/psi/zmath.c @@ -157,11 +157,11 @@ zexp(i_ctx_t *i_ctx_p) result = 1.0; /* match Adobe; can't rely on C library */ else result = pow(args[0], args[1]); - make_real(op - 1, result); #ifdef HAVE_ISINF if (isinf((op - 1)->value.realval)) return_error(gs_error_undefinedresult); #endif + make_real(op - 1, result); pop(1); return 0; } diff --git a/psi/ztype.c b/psi/ztype.c index 94e5e032a..df334abd7 100644 --- a/psi/ztype.c +++ b/psi/ztype.c @@ -281,7 +281,18 @@ zcvi(i_ctx_t *i_ctx_p) } if (!REAL_CAN_BE_INT(fval)) return_error(gs_error_rangecheck); - make_int(op, (long)fval); /* truncates towards 0 */ + if (sizeof(ps_int) != 4 && gs_currentcpsimode(imemory)) { + if ((double)fval > (double)MAX_PS_INT32) /* (double)0x7fffffff */ + return_error(gs_error_rangecheck); + else if ((double)fval < (double)MIN_PS_INT32) /* (double)(int)0x80000000 */ + return_error(gs_error_rangecheck); + else { + make_int(op, (ps_int) fval); + } + } + else + make_int(op, (ps_int) fval); + return 0; } |