diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2014-10-10 11:42:09 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2014-10-11 16:15:56 +0100 |
commit | 70a1710e18f874f9efd8e97f0f873d65bf1b46ca (patch) | |
tree | 3629edb0af164d235321406c8b03664265a20f0a /src/sna | |
parent | 069f7878dc57dca39ad79b2f3ad5248244090b70 (diff) |
sna/trapezoids: Sacrifice precision to avoid 64bit overflow
References: https://bugs.freedesktop.org/show_bug.cgi?id=70461#c71
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'src/sna')
-rw-r--r-- | src/sna/sna_trapezoids_imprecise.c | 11 | ||||
-rw-r--r-- | src/sna/sna_trapezoids_precise.c | 10 |
2 files changed, 19 insertions, 2 deletions
diff --git a/src/sna/sna_trapezoids_imprecise.c b/src/sna/sna_trapezoids_imprecise.c index 414e80a2..0887d4fd 100644 --- a/src/sna/sna_trapezoids_imprecise.c +++ b/src/sna/sna_trapezoids_imprecise.c @@ -502,6 +502,7 @@ polygon_add_edge(struct polygon *polygon, Ex = (int64_t)(edge->p2.x - edge->p1.x) * FAST_SAMPLES_X; Ey = (int64_t)(edge->p2.y - edge->p1.y) * FAST_SAMPLES_Y * (2 << 16); + assert(Ey > 0); e->dxdy.quo = Ex * (2 << 16) / Ey; e->dxdy.rem = Ex * (2 << 16) % Ey; @@ -514,7 +515,14 @@ polygon_add_edge(struct polygon *polygon, tmp = (int64_t)edge->p1.x * FAST_SAMPLES_X; e->x.quo += tmp / (1 << 16) + dx; - e->x.rem += ((tmp & ((1 << 16) - 1)) * Ey) / (1 << 16); + tmp &= (1 << 16) - 1; + if (tmp) { + if (Ey < INT64_MAX >> 16) + tmp = (tmp * Ey) / (1 << 16); + else /* Handle overflow by losing precision */ + tmp = tmp * (Ey / (1 << 16)); + e->x.rem += tmp; + } if (e->x.rem < 0) { --e->x.quo; @@ -523,6 +531,7 @@ polygon_add_edge(struct polygon *polygon, ++e->x.quo; e->x.rem -= Ey; } + assert(e->x.rem >= 0 && e->x.rem < Ey); e->cell = e->x.quo + (e->x.rem >= Ey/2); e->dy = Ey; diff --git a/src/sna/sna_trapezoids_precise.c b/src/sna/sna_trapezoids_precise.c index c595bfdd..2c5dad55 100644 --- a/src/sna/sna_trapezoids_precise.c +++ b/src/sna/sna_trapezoids_precise.c @@ -555,6 +555,7 @@ polygon_add_edge(struct polygon *polygon, Ex = (int64_t)(edge->p2.x - edge->p1.x) * SAMPLES_X; Ey = (int64_t)(edge->p2.y - edge->p1.y) * SAMPLES_Y * (2 << 16); + assert(Ey > 0); e->dxdy.quo = Ex * (2 << 16) / Ey; e->dxdy.rem = Ex * (2 << 16) % Ey; @@ -566,7 +567,14 @@ polygon_add_edge(struct polygon *polygon, tmp = (int64_t)edge->p1.x * SAMPLES_X; e->x.quo += (tmp >> 16) + dx; - e->x.rem += ((tmp & ((1 << 16) - 1)) * Ey) / (1 << 16); + tmp &= (1 << 16) - 1; + if (tmp) { + if (Ey < INT64_MAX >> 16) + tmp = (tmp * Ey) / (1 << 16); + else /* Handle overflow by losing precision */ + tmp = tmp * (Ey / (1 << 16)); + e->x.rem += tmp; + } if (e->x.rem < 0) { e->x.quo--; |