mirror of
https://github.com/luau-lang/luau.git
synced 2024-11-15 22:35:43 +08:00
74c532053f
New Solver * New algorithm for inferring the types of locals that have no annotations. This algorithm is very conservative by default, but is augmented with some control flow awareness to handle most common scenarios. * Fix bugs in type inference of tables * Improve performance of by switching out standard C++ containers for `DenseHashMap` * Infrastructure to support clearer error messages in strict mode Native Code Generation * Fix a lowering issue with buffer.writeu8 and 0x80-0xff values: A constant argument wasn't truncated to the target type range and that causes an assertion failure in `build.mov`. * Store full lightuserdata value in loop iteration protocol lowering * Add analysis to compute function bytecode distribution * This includes a class to analyze the bytecode operator distribution per function and a CLI tool that produces a JSON report. See the new cmake target `Luau.Bytecode.CLI` --------- Co-authored-by: Aaron Weiss <aaronweiss@roblox.com> Co-authored-by: Alexander McCord <amccord@roblox.com> Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Aviral Goel <agoel@roblox.com> Co-authored-by: Lily Brown <lbrown@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
627 lines
27 KiB
Lua
627 lines
27 KiB
Lua
-- This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
|
print("testing byte buffer library")
|
|
|
|
function call(fn, ...)
|
|
local ok, res = pcall(fn, ...)
|
|
assert(ok)
|
|
return res
|
|
end
|
|
|
|
function ecall(fn, ...)
|
|
local ok, err = pcall(fn, ...)
|
|
assert(not ok)
|
|
return err:sub((err:find(": ") or -1) + 2, #err)
|
|
end
|
|
|
|
local function simple_byte_reads()
|
|
local b = buffer.create(1024)
|
|
|
|
assert(buffer.len(b) == 1024)
|
|
|
|
assert(buffer.readi8(b, 5) == 0)
|
|
buffer.writei8(b, 10, 32)
|
|
assert(buffer.readi8(b, 10) == 32)
|
|
buffer.writei8(b, 15, 5)
|
|
buffer.writei8(b, 14, 4)
|
|
buffer.writei8(b, 13, 3)
|
|
buffer.writei8(b, 12, 2)
|
|
buffer.writei8(b, 11, 1)
|
|
assert(buffer.readi8(b, 11) == 1)
|
|
assert(buffer.readi8(b, 12) == 2)
|
|
assert(buffer.readi8(b, 13) == 3)
|
|
assert(buffer.readi8(b, 14) == 4)
|
|
assert(buffer.readi8(b, 15) == 5)
|
|
|
|
local x = buffer.readi8(b, 14) + buffer.readi8(b, 13)
|
|
assert(x == 7)
|
|
|
|
buffer.writei8(b, 16, x)
|
|
end
|
|
|
|
simple_byte_reads()
|
|
|
|
local function offset_byte_reads(start: number)
|
|
local b = buffer.create(1024)
|
|
|
|
buffer.writei8(b, start, 32)
|
|
assert(buffer.readi8(b, start) == 32)
|
|
buffer.writei8(b, start + 5, 5)
|
|
buffer.writei8(b, start + 4, 4)
|
|
buffer.writei8(b, start + 3, 3)
|
|
buffer.writei8(b, start + 2, 2)
|
|
buffer.writei8(b, start + 1, 1)
|
|
assert(buffer.readi8(b, start + 1) == 1)
|
|
assert(buffer.readi8(b, start + 2) == 2)
|
|
assert(buffer.readi8(b, start + 3) == 3)
|
|
assert(buffer.readi8(b, start + 4) == 4)
|
|
assert(buffer.readi8(b, start + 5) == 5)
|
|
|
|
local x = buffer.readi8(b, start + 4) + buffer.readi8(b, start + 3)
|
|
assert(x == 7)
|
|
end
|
|
|
|
offset_byte_reads(5)
|
|
offset_byte_reads(30)
|
|
|
|
local function simple_float_reinterpret()
|
|
local b = buffer.create(1024)
|
|
|
|
buffer.writei32(b, 10, 0x3f800000)
|
|
local one = buffer.readf32(b, 10)
|
|
assert(one == 1.0)
|
|
|
|
buffer.writef32(b, 10, 2.75197)
|
|
local magic = buffer.readi32(b, 10)
|
|
assert(magic == 0x40302047)
|
|
|
|
buffer.writef32(b, 10, one)
|
|
local magic2 = buffer.readi32(b, 10)
|
|
|
|
assert(magic2 == 0x3f800000)
|
|
end
|
|
|
|
simple_float_reinterpret()
|
|
|
|
local function simple_double_reinterpret()
|
|
local b = buffer.create(1024)
|
|
|
|
buffer.writei32(b, 10, 0x00000000)
|
|
buffer.writei32(b, 14, 0x3ff00000)
|
|
local one = buffer.readf64(b, 10)
|
|
assert(one == 1.0)
|
|
|
|
buffer.writef64(b, 10, 1.437576533064206)
|
|
local magic1 = buffer.readi32(b, 10)
|
|
local magic2 = buffer.readi32(b, 14)
|
|
|
|
assert(magic1 == 0x40302010)
|
|
assert(magic2 == 0x3ff70050)
|
|
|
|
buffer.writef64(b, 10, one)
|
|
local magic3 = buffer.readi32(b, 10)
|
|
local magic4 = buffer.readi32(b, 14)
|
|
|
|
assert(magic3 == 0x00000000)
|
|
assert(magic4 == 0x3ff00000)
|
|
end
|
|
|
|
simple_double_reinterpret()
|
|
|
|
local function simple_string_ops()
|
|
local b = buffer.create(1024)
|
|
|
|
buffer.writestring(b, 15, " world")
|
|
buffer.writestring(b, 10, "hello")
|
|
buffer.writei8(b, 21, string.byte('!'))
|
|
assert(buffer.readstring(b, 10, 12) == "hello world!")
|
|
|
|
buffer.writestring(b, 10, "hellommm", 5)
|
|
assert(buffer.readstring(b, 10, 12) == "hello world!")
|
|
|
|
buffer.writestring(b, 10, string.rep("hellommm", 1000), 5)
|
|
assert(buffer.readstring(b, 10, 12) == "hello world!")
|
|
end
|
|
|
|
simple_string_ops()
|
|
|
|
local function simple_copy_ops()
|
|
local b1 = buffer.create(1024)
|
|
local b2 = buffer.create(1024)
|
|
|
|
buffer.writestring(b1, 200, "hello")
|
|
buffer.writestring(b1, 100, "world")
|
|
|
|
buffer.copy(b1, 300, b1, 100, 5)
|
|
|
|
buffer.writei8(b2, 35, string.byte(' '))
|
|
buffer.writei8(b2, 41, string.byte('!'))
|
|
|
|
buffer.copy(b2, 30, b1, 200, 5)
|
|
buffer.copy(b2, 36, b1, 300, 5)
|
|
|
|
assert(buffer.readstring(b2, 30, 12) == "hello world!")
|
|
|
|
local b3 = buffer.create(9)
|
|
buffer.writestring(b3, 0, "say hello")
|
|
buffer.copy(b2, 36, b3, 4)
|
|
assert(buffer.readstring(b2, 30, 12) == "hello hello!")
|
|
|
|
local b4 = buffer.create(5)
|
|
buffer.writestring(b4, 0, "world")
|
|
buffer.copy(b2, 36, b4)
|
|
assert(buffer.readstring(b2, 30, 12) == "hello world!")
|
|
|
|
buffer.writestring(b1, 200, "abcdefgh");
|
|
buffer.copy(b1, 200, b1, 202, 6)
|
|
assert(buffer.readstring(b1, 200, 8) == "cdefghgh")
|
|
buffer.copy(b1, 202, b1, 200, 6)
|
|
assert(buffer.readstring(b1, 200, 8) == "cdcdefgh")
|
|
end
|
|
|
|
simple_copy_ops()
|
|
|
|
-- bounds checking
|
|
|
|
local function createchecks()
|
|
assert(ecall(function() buffer.create(-1) end) == "invalid argument #1 to 'create' (size)")
|
|
assert(ecall(function() buffer.create(-1000000) end) == "invalid argument #1 to 'create' (size)")
|
|
end
|
|
|
|
createchecks()
|
|
|
|
local function boundchecks()
|
|
local b = buffer.create(1024)
|
|
|
|
assert(call(function() return buffer.readi8(b, 1023) end) == 0)
|
|
assert(ecall(function() buffer.readi8(b, 1024) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readi8(b, -1) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readi8(b, -100000) end) == "buffer access out of bounds")
|
|
|
|
call(function() buffer.writei8(b, 1023, 0) end)
|
|
assert(ecall(function() buffer.writei8(b, 1024, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writei8(b, -1, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writei8(b, -100000, 0) end) == "buffer access out of bounds")
|
|
|
|
-- i16
|
|
assert(call(function() return buffer.readi16(b, 1022) end) == 0)
|
|
assert(ecall(function() buffer.readi16(b, 1023) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readi16(b, -1) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readi16(b, -100000) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readi16(b, 0x7fffffff) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readi16(b, 0x7ffffffe) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readi16(b, 0x7ffffffd) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readi16(b, 0x80000000) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readi16(b, 0x0fffffff) end) == "buffer access out of bounds")
|
|
|
|
call(function() buffer.writei16(b, 1022, 0) end)
|
|
assert(ecall(function() buffer.writei16(b, 1023, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writei16(b, -1, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writei16(b, -100000, 0) end) == "buffer access out of bounds")
|
|
|
|
-- i32
|
|
assert(call(function() return buffer.readi32(b, 1020) end) == 0)
|
|
assert(ecall(function() buffer.readi32(b, 1021) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readi32(b, -1) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readi32(b, -100000) end) == "buffer access out of bounds")
|
|
|
|
call(function() buffer.writei32(b, 1020, 0) end)
|
|
assert(ecall(function() buffer.writei32(b, 1021, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writei32(b, -1, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writei32(b, -100000, 0) end) == "buffer access out of bounds")
|
|
|
|
-- f32
|
|
assert(call(function() return buffer.readf32(b, 1020) end) == 0)
|
|
assert(ecall(function() buffer.readf32(b, 1021) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readf32(b, -1) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readf32(b, -100000) end) == "buffer access out of bounds")
|
|
|
|
call(function() buffer.writef32(b, 1020, 0) end)
|
|
assert(ecall(function() buffer.writef32(b, 1021, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writef32(b, -1, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writef32(b, -100000, 0) end) == "buffer access out of bounds")
|
|
|
|
-- f64
|
|
assert(call(function() return buffer.readf64(b, 1016) end) == 0)
|
|
assert(ecall(function() buffer.readf64(b, 1017) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readf64(b, -1) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readf64(b, -100000) end) == "buffer access out of bounds")
|
|
|
|
call(function() buffer.writef64(b, 1016, 0) end)
|
|
assert(ecall(function() buffer.writef64(b, 1017, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writef64(b, -1, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writef64(b, -100000, 0) end) == "buffer access out of bounds")
|
|
|
|
-- string
|
|
assert(call(function() return buffer.readstring(b, 1016, 8) end) == "\0\0\0\0\0\0\0\0")
|
|
assert(ecall(function() buffer.readstring(b, 1017, 8) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readstring(b, -1, -8) end) == "invalid argument #3 to 'readstring' (size)")
|
|
assert(ecall(function() buffer.readstring(b, -100000, 8) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readstring(b, -100000, 8) end) == "buffer access out of bounds")
|
|
|
|
call(function() buffer.writestring(b, 1016, "abcdefgh") end)
|
|
assert(ecall(function() buffer.writestring(b, 1017, "abcdefgh") end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writestring(b, -1, "abcdefgh") end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writestring(b, -100000, "abcdefgh") end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writestring(b, 100, "abcd", -5) end) == "invalid argument #4 to 'writestring' (count)")
|
|
assert(ecall(function() buffer.writestring(b, 100, "abcd", 50) end) == "string length overflow")
|
|
|
|
-- copy
|
|
assert(ecall(function() buffer.copy(b, 30, b, 200, 1000) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.copy(b, 30, b, 200, -5) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.copy(b, 30, b, 2000, 10) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.copy(b, 30, b, -1, 10) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.copy(b, 30, b, -10, 10) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.copy(b, 30, b, -100000, 10) end) == "buffer access out of bounds")
|
|
|
|
local b2 = buffer.create(1024)
|
|
assert(ecall(function() buffer.copy(b, -200, b, 200, 200) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.copy(b, 825, b, 200, 200) end) == "buffer access out of bounds")
|
|
end
|
|
|
|
boundchecks()
|
|
|
|
local function boundchecksnonconst(size, minus1, minusbig, intmax)
|
|
local b = buffer.create(size)
|
|
|
|
assert(call(function() return buffer.readi8(b, size-1) end) == 0)
|
|
assert(ecall(function() buffer.readi8(b, size) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readi8(b, minus1) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readi8(b, minusbig) end) == "buffer access out of bounds")
|
|
|
|
call(function() buffer.writei8(b, size-1, 0) end)
|
|
assert(ecall(function() buffer.writei8(b, size, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writei8(b, minus1, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writei8(b, minusbig, 0) end) == "buffer access out of bounds")
|
|
|
|
-- i16
|
|
assert(call(function() return buffer.readi16(b, size-2) end) == 0)
|
|
assert(ecall(function() buffer.readi16(b, size-1) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readi16(b, minus1) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readi16(b, minusbig) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readi16(b, intmax) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readi16(b, intmax-1) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readi16(b, intmax-2) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readi16(b, intmax+1) end) == "buffer access out of bounds")
|
|
|
|
call(function() buffer.writei16(b, size-2, 0) end)
|
|
assert(ecall(function() buffer.writei16(b, size-1, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writei16(b, minus1, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writei16(b, minusbig, 0) end) == "buffer access out of bounds")
|
|
|
|
-- i32
|
|
assert(call(function() return buffer.readi32(b, size-4) end) == 0)
|
|
assert(ecall(function() buffer.readi32(b, size-3) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readi32(b, minus1) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readi32(b, minusbig) end) == "buffer access out of bounds")
|
|
|
|
call(function() buffer.writei32(b, size-4, 0) end)
|
|
assert(ecall(function() buffer.writei32(b, size-3, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writei32(b, minus1, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writei32(b, minusbig, 0) end) == "buffer access out of bounds")
|
|
|
|
-- f32
|
|
assert(call(function() return buffer.readf32(b, size-4) end) == 0)
|
|
assert(ecall(function() buffer.readf32(b, size-3) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readf32(b, minus1) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readf32(b, minusbig) end) == "buffer access out of bounds")
|
|
|
|
call(function() buffer.writef32(b, size-4, 0) end)
|
|
assert(ecall(function() buffer.writef32(b, size-3, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writef32(b, minus1, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writef32(b, minusbig, 0) end) == "buffer access out of bounds")
|
|
|
|
-- f64
|
|
assert(call(function() return buffer.readf64(b, size-8) end) == 0)
|
|
assert(ecall(function() buffer.readf64(b, size-7) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readf64(b, minus1) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readf64(b, minusbig) end) == "buffer access out of bounds")
|
|
|
|
call(function() buffer.writef64(b, size-8, 0) end)
|
|
assert(ecall(function() buffer.writef64(b, size-7, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writef64(b, minus1, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writef64(b, minusbig, 0) end) == "buffer access out of bounds")
|
|
|
|
-- string
|
|
assert(call(function() return buffer.readstring(b, size-8, 8) end) == "\0\0\0\0\0\0\0\0")
|
|
assert(ecall(function() buffer.readstring(b, size-7, 8) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readstring(b, minus1, 8) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readstring(b, minusbig, 8) end) == "buffer access out of bounds")
|
|
|
|
call(function() buffer.writestring(b, size-8, "abcdefgh") end)
|
|
assert(ecall(function() buffer.writestring(b, size-7, "abcdefgh") end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writestring(b, minus1, "abcdefgh") end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writestring(b, minusbig, "abcdefgh") end) == "buffer access out of bounds")
|
|
end
|
|
|
|
boundchecksnonconst(1024, -1, -100000, 0x7fffffff)
|
|
|
|
local function boundcheckssmall()
|
|
local b = buffer.create(1)
|
|
|
|
assert(call(function() return buffer.readi8(b, 0) end) == 0)
|
|
assert(ecall(function() buffer.readi8(b, 1) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readi8(b, -1) end) == "buffer access out of bounds")
|
|
|
|
call(function() buffer.writei8(b, 0, 0) end)
|
|
assert(ecall(function() buffer.writei8(b, 1, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writei8(b, -1, 0) end) == "buffer access out of bounds")
|
|
|
|
-- i16
|
|
assert(ecall(function() buffer.readi16(b, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readi16(b, -1) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readi16(b, -2) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writei16(b, 0, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writei16(b, -1, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writei16(b, -2, 0) end) == "buffer access out of bounds")
|
|
|
|
-- i32
|
|
assert(ecall(function() buffer.readi32(b, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readi32(b, -1) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readi32(b, -4) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writei32(b, 0, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writei32(b, -1, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writei32(b, -4, 0) end) == "buffer access out of bounds")
|
|
|
|
-- f32
|
|
assert(ecall(function() buffer.readf32(b, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readf32(b, -1) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readf32(b, -4) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writef32(b, 0, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writef32(b, -1, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writef32(b, -4, 0) end) == "buffer access out of bounds")
|
|
|
|
-- f64
|
|
assert(ecall(function() buffer.readf64(b, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readf64(b, -1) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readf64(b, -8) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writef64(b, 0, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writef64(b, -1, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writef64(b, -7, 0) end) == "buffer access out of bounds")
|
|
|
|
-- string
|
|
assert(ecall(function() buffer.readstring(b, 0, 8) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readstring(b, -1, 8) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readstring(b, -8, 8) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writestring(b, 0, "abcdefgh") end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writestring(b, -1, "abcdefgh") end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writestring(b, -7, "abcdefgh") end) == "buffer access out of bounds")
|
|
end
|
|
|
|
boundcheckssmall()
|
|
|
|
local function boundcheckssmallnonconst(zero, one, minus1, minus2, minus4, minus7, minus8)
|
|
local b = buffer.create(1)
|
|
|
|
assert(call(function() return buffer.readi8(b, 0) end) == 0)
|
|
assert(ecall(function() buffer.readi8(b, one) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readi8(b, minus1) end) == "buffer access out of bounds")
|
|
|
|
call(function() buffer.writei8(b, 0, 0) end)
|
|
assert(ecall(function() buffer.writei8(b, one, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writei8(b, minus1, 0) end) == "buffer access out of bounds")
|
|
|
|
-- i16
|
|
assert(ecall(function() buffer.readi16(b, zero) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readi16(b, minus1) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readi16(b, minus2) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writei16(b, zero, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writei16(b, minus1, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writei16(b, minus2, 0) end) == "buffer access out of bounds")
|
|
|
|
-- i32
|
|
assert(ecall(function() buffer.readi32(b, zero) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readi32(b, minus1) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readi32(b, minus4) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writei32(b, zero, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writei32(b, minus1, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writei32(b, minus4, 0) end) == "buffer access out of bounds")
|
|
|
|
-- f32
|
|
assert(ecall(function() buffer.readf32(b, zero) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readf32(b, minus1) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readf32(b, minus4) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writef32(b, zero, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writef32(b, minus1, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writef32(b, minus4, 0) end) == "buffer access out of bounds")
|
|
|
|
-- f64
|
|
assert(ecall(function() buffer.readf64(b, zero) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readf64(b, minus1) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readf64(b, minus8) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writef64(b, zero, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writef64(b, minus1, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writef64(b, minus7, 0) end) == "buffer access out of bounds")
|
|
|
|
-- string
|
|
assert(ecall(function() buffer.readstring(b, zero, 8) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readstring(b, minus1, 8) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readstring(b, minus8, 8) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writestring(b, zero, "abcdefgh") end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writestring(b, minus1, "abcdefgh") end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writestring(b, minus7, "abcdefgh") end) == "buffer access out of bounds")
|
|
end
|
|
|
|
boundcheckssmallnonconst(0, 1, -1, -2, -4, -7, -8)
|
|
|
|
local function boundchecksempty()
|
|
local b = buffer.create(0) -- useless, but probably more generic
|
|
|
|
assert(ecall(function() buffer.readi8(b, 1) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readi8(b, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readi8(b, -1) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writei8(b, 1, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writei8(b, 0, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.writei8(b, -1, 0) end) == "buffer access out of bounds")
|
|
|
|
assert(ecall(function() buffer.readi16(b, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readi32(b, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readf32(b, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readf64(b, 0) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readstring(b, 0, 1) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.readstring(b, 0, 8) end) == "buffer access out of bounds")
|
|
end
|
|
|
|
boundchecksempty()
|
|
|
|
local function intuint()
|
|
local b = buffer.create(32)
|
|
|
|
buffer.writeu32(b, 0, 0xffffffff)
|
|
assert(buffer.readi8(b, 0) == -1)
|
|
assert(buffer.readu8(b, 0) == 255)
|
|
assert(buffer.readi16(b, 0) == -1)
|
|
assert(buffer.readu16(b, 0) == 65535)
|
|
assert(buffer.readi32(b, 0) == -1)
|
|
assert(buffer.readu32(b, 0) == 4294967295)
|
|
|
|
buffer.writei32(b, 0, -1)
|
|
assert(buffer.readi8(b, 0) == -1)
|
|
assert(buffer.readu8(b, 0) == 255)
|
|
assert(buffer.readi16(b, 0) == -1)
|
|
assert(buffer.readu16(b, 0) == 65535)
|
|
assert(buffer.readi32(b, 0) == -1)
|
|
assert(buffer.readu32(b, 0) == 4294967295)
|
|
|
|
buffer.writei16(b, 0, 65535)
|
|
buffer.writei16(b, 2, -1)
|
|
assert(buffer.readi8(b, 0) == -1)
|
|
assert(buffer.readu8(b, 0) == 255)
|
|
assert(buffer.readi16(b, 0) == -1)
|
|
assert(buffer.readu16(b, 0) == 65535)
|
|
assert(buffer.readi32(b, 0) == -1)
|
|
assert(buffer.readu32(b, 0) == 4294967295)
|
|
|
|
buffer.writeu16(b, 0, 65535)
|
|
buffer.writeu16(b, 2, -1)
|
|
assert(buffer.readi8(b, 0) == -1)
|
|
assert(buffer.readu8(b, 0) == 255)
|
|
assert(buffer.readi16(b, 0) == -1)
|
|
assert(buffer.readu16(b, 0) == 65535)
|
|
assert(buffer.readi32(b, 0) == -1)
|
|
assert(buffer.readu32(b, 0) == 4294967295)
|
|
end
|
|
|
|
intuint()
|
|
|
|
local function intuinttricky()
|
|
local b = buffer.create(32)
|
|
|
|
buffer.writeu8(b, 0, 0xffffffff)
|
|
assert(buffer.readi8(b, 0) == -1)
|
|
assert(buffer.readu8(b, 0) == 255)
|
|
assert(buffer.readi16(b, 0) == 255)
|
|
assert(buffer.readu16(b, 0) == 255)
|
|
assert(buffer.readi32(b, 0) == 255)
|
|
assert(buffer.readu32(b, 0) == 255)
|
|
|
|
buffer.writeu16(b, 0, 0xffffffff)
|
|
assert(buffer.readi8(b, 0) == -1)
|
|
assert(buffer.readu8(b, 0) == 255)
|
|
assert(buffer.readi16(b, 0) == -1)
|
|
assert(buffer.readu16(b, 0) == 65535)
|
|
assert(buffer.readi32(b, 0) == 65535)
|
|
assert(buffer.readu32(b, 0) == 65535)
|
|
|
|
buffer.writei32(b, 8, 0xffffffff)
|
|
buffer.writeu32(b, 12, 0xffffffff)
|
|
assert(buffer.readstring(b, 8, 4) == buffer.readstring(b, 12, 4))
|
|
|
|
buffer.writei32(b, 8, -2147483648)
|
|
buffer.writeu32(b, 12, 0x80000000)
|
|
assert(buffer.readstring(b, 8, 4) == buffer.readstring(b, 12, 4))
|
|
end
|
|
|
|
intuinttricky()
|
|
|
|
local function fromtostring()
|
|
local b = buffer.fromstring("1234567890")
|
|
assert(buffer.tostring(b) == "1234567890")
|
|
|
|
buffer.writestring(b, 4, "xyz")
|
|
assert(buffer.tostring(b) == "1234xyz890")
|
|
|
|
local b2 = buffer.fromstring("abcd\0ef")
|
|
assert(buffer.tostring(b2) == "abcd\0ef")
|
|
end
|
|
|
|
fromtostring()
|
|
|
|
local function fill()
|
|
local b = buffer.create(10)
|
|
|
|
buffer.fill(b, 0, 0x61)
|
|
assert(buffer.tostring(b) == "aaaaaaaaaa")
|
|
|
|
buffer.fill(b, 0, 0x62, 5)
|
|
assert(buffer.tostring(b) == "bbbbbaaaaa")
|
|
|
|
buffer.fill(b, 4, 0x63)
|
|
assert(buffer.tostring(b) == "bbbbcccccc")
|
|
|
|
buffer.fill(b, 6, 0x64, 3)
|
|
assert(buffer.tostring(b) == "bbbbccdddc")
|
|
|
|
buffer.fill(b, 2, 0xffffff65, 8)
|
|
assert(buffer.tostring(b) == "bbeeeeeeee")
|
|
|
|
-- out of bounds
|
|
assert(ecall(function() buffer.fill(b, -10, 1) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.fill(b, 11, 1) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.fill(b, 0, 1, 11) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.fill(b, 5, 1, 6) end) == "buffer access out of bounds")
|
|
assert(ecall(function() buffer.fill(b, 5, 1, -1) end) == "buffer access out of bounds")
|
|
end
|
|
|
|
fill()
|
|
|
|
local function misc(t16)
|
|
local b = buffer.create(1000)
|
|
|
|
assert(select('#', buffer.writei32(b, 10, 40)) == 0)
|
|
assert(select('#', buffer.writef32(b, 20, 40.0)) == 0)
|
|
|
|
-- some extra operation to place '#t16' into a linear block
|
|
t16[1] = 10
|
|
t16[15] = 20
|
|
|
|
buffer.writei32(b, #t16, 10)
|
|
assert(buffer.readi32(b, 16) == 10)
|
|
|
|
buffer.writeu8(b, 100, 0xff)
|
|
buffer.writeu8(b, 110, 0x80)
|
|
assert(buffer.readu32(b, 100) == 255)
|
|
assert(buffer.readu32(b, 110) == 128)
|
|
buffer.writeu16(b, 200, 0xffff)
|
|
buffer.writeu16(b, 210, 0x8000)
|
|
assert(buffer.readu32(b, 200) == 65535)
|
|
assert(buffer.readu32(b, 210) == 32768)
|
|
end
|
|
|
|
misc(table.create(16, 0))
|
|
|
|
local function testslowcalls()
|
|
getfenv()
|
|
|
|
simple_byte_reads()
|
|
offset_byte_reads(5)
|
|
offset_byte_reads(30)
|
|
simple_float_reinterpret()
|
|
simple_double_reinterpret()
|
|
simple_string_ops()
|
|
createchecks()
|
|
boundchecks()
|
|
boundchecksnonconst(1024, -1, -100000, 0x7fffffff)
|
|
boundcheckssmall()
|
|
boundcheckssmallnonconst(0, 1, -1, -2, -4, -7, -8)
|
|
boundchecksempty()
|
|
intuint()
|
|
intuinttricky()
|
|
fromtostring()
|
|
fill()
|
|
misc(table.create(16, 0))
|
|
end
|
|
|
|
testslowcalls()
|
|
|
|
return('OK')
|