Skip to content

Commit

Permalink
Prevent overflow errors in integer lifts (#1980)
Browse files Browse the repository at this point in the history
* Prevent overflow errors in integer lifts
  • Loading branch information
Cisphyx committed Dec 2, 2020
1 parent f2b4bd8 commit 430aa45
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 9 deletions.
38 changes: 32 additions & 6 deletions synapse/lib/layer.py
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,8 @@ def __init__(self, layr, stortype, size, signed):
if signed:
self.offset = 2 ** ((self.size * 8) - 1) - 1

self.maxval = 2 ** (self.size * 8) - 1

self.lifters.update({
'=': self._liftIntEq,
'<': self._liftIntLt,
Expand All @@ -625,16 +627,26 @@ def indx(self, valu):
return (self.getIntIndx(valu),)

async def _liftIntEq(self, liftby, valu):
indx = (valu + self.offset).to_bytes(self.size, 'big')
for item in liftby.buidsByDups(indx):
indx = valu + self.offset
if indx < 0 or indx > self.maxval:
return

pkey = indx.to_bytes(self.size, 'big')
for item in liftby.buidsByDups(pkey):
yield item

async def _liftIntGt(self, liftby, valu):
async for item in self._liftIntGe(liftby, valu + 1):
yield item

async def _liftIntGe(self, liftby, valu):
pkeymin = (valu + self.offset).to_bytes(self.size, 'big')
minv = valu + self.offset
if minv > self.maxval:
return

minv = max(minv, 0)

pkeymin = minv.to_bytes(self.size, 'big')
pkeymax = self.fullbyts
for item in liftby.buidsByRange(pkeymin, pkeymax):
yield item
Expand All @@ -644,14 +656,28 @@ async def _liftIntLt(self, liftby, valu):
yield item

async def _liftIntLe(self, liftby, valu):
maxv = valu + self.offset
if maxv < 0:
return

maxv = min(maxv, self.maxval)

pkeymin = self.zerobyts
pkeymax = (valu + self.offset).to_bytes(self.size, 'big')
pkeymax = maxv.to_bytes(self.size, 'big')
for item in liftby.buidsByRange(pkeymin, pkeymax):
yield item

async def _liftIntRange(self, liftby, valu):
pkeymin = (valu[0] + self.offset).to_bytes(self.size, 'big')
pkeymax = (valu[1] + self.offset).to_bytes(self.size, 'big')
minv = valu[0] + self.offset
maxv = valu[1] + self.offset
if minv > self.maxval or maxv < 0:
return

minv = max(minv, 0)
maxv = min(maxv, self.maxval)

pkeymin = minv.to_bytes(self.size, 'big')
pkeymax = maxv.to_bytes(self.size, 'big')
for item in liftby.buidsByRange(pkeymin, pkeymax):
yield item

Expand Down
80 changes: 79 additions & 1 deletion synapse/tests/test_lib_layer.py
Original file line number Diff line number Diff line change
Expand Up @@ -527,13 +527,91 @@ async def test_layer_splices(self):
async with await s_telepath.openurl(url) as layrprox:
await self.agenlen(26, layrprox.splices())

async def test_layer_stortype_int(self):
async with self.getTestCore() as core:

layr = core.view.layers[0]
tmpdb = layr.layrslab.initdb('temp', dupsort=True)

stor = s_layer.StorTypeInt(layr, s_layer.STOR_TYPE_I32, 8, True)
minv = -2 ** 63 + 1
maxv = 2 ** 63
vals = [minv, 0, 1, maxv]

indxby = s_layer.IndxBy(layr, b'', tmpdb)

for key, val in ((stor.indx(v), s_msgpack.en(v)) for v in vals):
layr.layrslab.put(key[0], val, db=tmpdb)

retn = [s_msgpack.un(valu) async for valu in stor.indxBy(indxby, '=', minv)]
self.eq(retn, [minv])

retn = [s_msgpack.un(valu) async for valu in stor.indxBy(indxby, '=', maxv)]
self.eq(retn, [maxv])

retn = [s_msgpack.un(valu) async for valu in stor.indxBy(indxby, '<', minv + 1)]
self.eq(retn, [minv])

retn = [s_msgpack.un(valu) async for valu in stor.indxBy(indxby, '>', maxv - 1)]
self.eq(retn, [maxv])

retn = [s_msgpack.un(valu) async for valu in stor.indxBy(indxby, '<=', minv)]
self.eq(retn, [minv])

retn = [s_msgpack.un(valu) async for valu in stor.indxBy(indxby, '>=', maxv)]
self.eq(retn, [maxv])

retn = [s_msgpack.un(valu) async for valu in stor.indxBy(indxby, 'range=', (minv, maxv))]
self.eq(retn, vals)

# Should get no results instead of overflowing
retn = [s_msgpack.un(valu) async for valu in stor.indxBy(indxby, '=', minv - 1)]
self.eq(retn, [])

retn = [s_msgpack.un(valu) async for valu in stor.indxBy(indxby, '=', maxv + 1)]
self.eq(retn, [])

retn = [s_msgpack.un(valu) async for valu in stor.indxBy(indxby, '<', minv)]
self.eq(retn, [])

retn = [s_msgpack.un(valu) async for valu in stor.indxBy(indxby, '>', maxv)]
self.eq(retn, [])

retn = [s_msgpack.un(valu) async for valu in stor.indxBy(indxby, '<=', minv - 1)]
self.eq(retn, [])

retn = [s_msgpack.un(valu) async for valu in stor.indxBy(indxby, '>=', maxv + 1)]
self.eq(retn, [])

retn = [s_msgpack.un(valu) async for valu in stor.indxBy(indxby, 'range=', (minv - 2, minv - 1))]
self.eq(retn, [])

retn = [s_msgpack.un(valu) async for valu in stor.indxBy(indxby, 'range=', (maxv + 1, maxv + 2))]
self.eq(retn, [])

# Value is out of range but there are still valid results
retn = [s_msgpack.un(valu) async for valu in stor.indxBy(indxby, '<', maxv + 2)]
self.eq(retn, vals)

retn = [s_msgpack.un(valu) async for valu in stor.indxBy(indxby, '>', minv - 2)]
self.eq(retn, vals)

retn = [s_msgpack.un(valu) async for valu in stor.indxBy(indxby, '<=', maxv + 1)]
self.eq(retn, vals)

retn = [s_msgpack.un(valu) async for valu in stor.indxBy(indxby, '>=', minv - 1)]
self.eq(retn, vals)

retn = [s_msgpack.un(valu) async for valu in stor.indxBy(indxby, 'range=', (minv - 1, maxv + 1))]
self.eq(retn, vals)

async def test_layer_stortype_float(self):
async with self.getTestCore() as core:

layr = core.view.layers[0]
tmpdb = layr.layrslab.initdb('temp', dupsort=True)

stor = s_layer.StorTypeFloat(s_layer.STOR_TYPE_FLOAT64, 8)
stor = s_layer.StorTypeFloat(layr, s_layer.STOR_TYPE_FLOAT64, 8)
vals = [math.nan, -math.inf, -99999.9, -0.0000000001, -42.1, -0.0, 0.0, 0.000001, 42.1, 99999.9, math.inf]

indxby = s_layer.IndxBy(layr, b'', tmpdb)
Expand Down
3 changes: 1 addition & 2 deletions synapse/tests/test_model_inet.py
Original file line number Diff line number Diff line change
Expand Up @@ -721,8 +721,7 @@ async def test_ipv4(self):
# > / < lifts and filters
self.len(4, await core.nodes('[inet:ipv4=0 inet:ipv4=1 inet:ipv4=2 inet:ipv4=3]'))
# Lifts
with self.raises(OverflowError):
await core.nodes('inet:ipv4<0')
self.len(0, await core.nodes('inet:ipv4<0'))
self.len(1, await core.nodes('inet:ipv4<=0'))
self.len(1, await core.nodes('inet:ipv4<1'))
self.len(3, await core.nodes('inet:ipv4<=2'))
Expand Down

0 comments on commit 430aa45

Please sign in to comment.