Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions 09-fuzz/flat-azam-shaprunov/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Bekhruz Azam Flat Buffers solution Node.js

_student_generated.js file should be in the same folder as solution.js_

$ sha256sum data/students.bin
0c016dc4ca1a8b24b34daa6c05472d16b401fd3c0c5417da18e9810b136704a6 data/students.bin
$ node solution.js data/students.bin
Reading binary student data from data/students.bin...
3 students read...
written to data/students.flat
$ rm -f data/students.bin
$ node solution.js data/students.flat
Reading flatbuffers student data from data/students.flat...
3 students read...
written to data/students.bin
$ sha256sum data/students.bin
0c016dc4ca1a8b24b34daa6c05472d16b401fd3c0c5417da18e9810b136704a6 data/students.bin

# Shaprunov Kirill Flat buffers Node.js fuzzer
To fuzz for correctness run ```node fuzzer.jz``` setupable TEST_COUNT variable.
All tests completed for me, i fuzzed 100000 times in context of proper input file.
The only change i made was check for input file size for dividing by 128 without any remains.
136 changes: 136 additions & 0 deletions 09-fuzz/flat-azam-shaprunov/fuzzer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
const fs = require('fs');
const { exec } = require('child_process');
const crypto = require('crypto');
const { v4: uuidv4 } = require('uuid');
const { getFlat } = require('./solution');
const { dumpBin } = require('./solution');
const { parseDataToJson } = require('./solution');
var flatbuffers = require('flatbuffers').flatbuffers;
var ds = require('./student_generated').ds
var Buffer = require('buffer/').Buffer

function randomCharString(length, charSet) {
let randomString = '';
const characters = charSet || 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
const charactersLength = characters.length;
for (let i = 0; i < length; i++) {
randomString += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return randomString;
}

function randomUtf8String(length) {
return randomCharString(length).padEnd(length, '\0');
}

function randomAsciiString(length) {
return randomCharString(length, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789').padEnd(length, '\0');
}

function randomUrl(length) {
return 'http://'.concat(randomCharString(length - 7, 'abcdefghijklmnopqrstuvwxyz')).padEnd(length, '\0');
}

function generateRandomStudentData() {
const name = Buffer.from(randomUtf8String(32), 'utf8');
const login = Buffer.from(randomAsciiString(16), 'utf8');
const group = Buffer.from(randomAsciiString(8), 'utf8');
const practice = crypto.randomBytes(8).map(x => x % 2); // Генерация 8 случайных битовых значений (0 или 1)
const projectRepo = Buffer.from(randomUrl(59), 'utf8');
const projectMark = Buffer.allocUnsafe(1); // Генерация одного случайного байта для оценки
projectMark.writeUInt8(Math.floor(Math.random() * 100), 0); // Записываем случайное число от 0 до 100 в буфер
const mark = Buffer.allocUnsafe(4);
mark.writeFloatLE(Math.random() * 100, 0); // Записываем случайную оценку в буфер как 32-битное число с плавающей точкой

const data = Buffer.concat([name, login, group, Buffer.from(practice), projectRepo, projectMark, mark]);

return data;
}

function generateMultipleStudentsData(count) {
let studentsData = [];
for (let i = 0; i < count; i++) {
studentsData.push(generateRandomStudentData());
}
return Buffer.concat(studentsData);
}

const COUNT = 5;
const studentsData = generateMultipleStudentsData(COUNT);
// console.log(studentsData);
// console.log("Generated data length:", studentsData.length);

function runCommand(command, callback) {
exec(command, (error, stdout, stderr) => {
if (error) {
console.error(`exec error: ${error}`);
return;
}
// console.log(`stdout: ${stdout}`);
// console.error(`stderr: ${stderr}`);
callback();
});
}

function testConversion(callback) {
const uniqueId = uuidv4();
const originalFilename = `temp_original_${uniqueId}.bin`;
let fuken = originalFilename.split('.');
const convertedFilename = `${fuken[0]}.flat`;

const originalData = generateMultipleStudentsData(1);
fs.writeFileSync(originalFilename, originalData);

runCommand(`node solution.js ${originalFilename}`, () => {
runCommand(`node solution.js ${convertedFilename}`, () => {
const convertedData = fs.readFileSync(originalFilename);
const result = originalData.compare(convertedData) == 0 ? "Тест пройден: Данные совпадают" : "Ошибка теста: Данные не совпадают";
const completed = originalData.compare(convertedData) == 0 ? true : false;
// console.log(result);
fs.unlinkSync(originalFilename);
fs.unlinkSync(convertedFilename);
callback(completed);
});
});

}

function runTests(testCount) {
let completedTests = 0;
const testCompletedCallback = (completed) => {
completedTests++;
if (!completed) {
console.log(`Выполнено тестов: ${completedTests} из ${testCount}`);
console.log("Тест не пройден");
return;
}
console.log(`Выполнено тестов: ${completedTests}`);
if (completedTests === testCount) {
console.log("Все тесты завершены");
}
};

for (let i = 0; i < testCount; i++) {
testConversion(testCompletedCallback);
}
}

const TEST_COUNT = 100;
// runTests(TEST_COUNT);

function fuzz(data) {
try {
let parsedData = parseDataToJson(data);
let flatBuf = getFlat(parsedData);
const resultData = dumpBin(flatBuf);
if (data.compare(resultData) != 0) {
console.log("Ошибка теста: Данные не совпадают");
}
} catch (error) {
console.error(`Malformed input`);
}
};

module.exports = {
fuzz
};
157 changes: 157 additions & 0 deletions 09-fuzz/flat-azam-shaprunov/solution.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
var flatbuffers = require('flatbuffers');
var fs = require('fs');
var ds = require('./student_generated').ds
var Buffer = require('buffer/').Buffer


function parseBin(path) {
var data = fs.readFileSync(path);
return parseDataToJson(data);
}

function safelyReadFloatLE(buffer, offset) {
const FLOAT_SIZE = 4;
if (offset + FLOAT_SIZE > buffer.length) {
throw new Error("Trying to read beyond buffer length");
}
return buffer.readFloatLE(offset);
}

function parseDataToJson(data) {
var fileData = Buffer.from(data, "utf8");
var N = Buffer.byteLength(data, "utf8");
if (N % 128 != 0) {
// console.error("Parsing error: invalid file size to input .bin");
throw new Error("Invalid file size to input .bin");
}
var res = [];
for (var i = 0; i < N; i += 128) {
var name = fileData.slice(i + 0, i + 32).toString();
var login = fileData.slice(i + 32, i + 48).toString();
var group = fileData.slice(i + 48, i + 56).toString();
var practice = Array.from(new TextEncoder().encode(fileData.slice(i + 56, i + 64)));
var repo = fileData.slice(i + 64, i + 123).toString();
var markk = new TextEncoder().encode(fileData.slice(i + 123, i + 124))[0];
try {
var mark = safelyReadFloatLE(fileData, 124);
} catch (e) {
console.log(e.message);
throw e;
}
res.push({
'name' : name,
'login' : login,
'group' : group,
'practice' : practice,
'project' : {
'repo' : repo,
'mark' : markk
},
'mark' : mark
});

}
return res;
}

function getFlat(binStudent) {
studs = []
var builder = new flatbuffers.Builder(1024);
for (var i = 0; i < N; i++) {
var stud = binStudent[i]

var name = builder.createString(stud.name);
var login = builder.createString(stud.login);
var group = builder.createString(stud.group);

var repo = builder.createString(stud.project.repo);
ds.Proj.startProj(builder);
ds.Proj.addRepo(builder, repo);
ds.Proj.addMark(builder, stud.project.mark)
var project = ds.Proj.endProj(builder);

var practice = ds.Student.createPracticeVector(builder, stud.practice);

ds.Student.startStudent(builder);
ds.Student.addName(builder, name);
ds.Student.addLogin(builder, login);
ds.Student.addGroup(builder, group);
ds.Student.addPractice(builder, practice);

ds.Student.addProject(builder, project);

ds.Student.addMark(builder, stud.mark);
var student = ds.Student.endStudent(builder);
studs.push(student)
}
var kings = ds.Students.createKingsVector(builder, studs);
ds.Students.startStudents(builder);
ds.Students.addKings(builder, kings);
var students = ds.Students.endStudents(builder);
builder.finish(students);
var buf = builder.asUint8Array();
var kek = builder.dataBuffer();
return kek;
}

function dumpBin(buf) {
var students = ds.Students.getRootAsStudents(buf);
var N = students.kingsLength();
res = []
for (var i = 0; i < N; i++) {
var king = studs.kings(i);
var name = Buffer.from(king.name());
var login = Buffer.from(king.login());
var group = Buffer.from(king.group());
var practice = [];
for (var j = 0; j < 8; ++j) {
practice.push(king.practice(j));
}
practice = Buffer.from(practice)
var repo = Buffer.from(king.project().repo());
var markk = Buffer.from([king.project().mark()]);
var mark = Buffer.allocUnsafe(4);
mark.writeFloatLE(king.mark());
res.push(Buffer.concat([name, login, group, practice, repo, markk, mark]));
}
return Buffer.concat(res);
}


if (process.argv.length < 3) {
console.log("provide arguments")
return;
}

if (process.argv[2].split('.').pop() == 'bin') {
console.log(`Reading binary student data from ${process.argv[2]}...`);
var binStudents = parseBin(process.argv[2]);
var N = binStudents.length;
console.log(`${N} student${N > 1 ? 's' : ''} read...`);
var fileName = process.argv[2].split('.');
fileName.pop();
fileName.push('flat');
fileName = fileName.join('.');

buf = getFlat(binStudents);
fs.writeFileSync(fileName, buf, 'binary');
console.log(`written to ${fileName}`);
} else if (process.argv[2].split('.').pop() == 'flat') {
console.log(`Reading flatbuffers student data from ${process.argv[2]}...`);
var bytes = new Uint8Array(fs.readFileSync(process.argv[2]));
var buf = new flatbuffers.ByteBuffer(bytes);
console.log(`${N} student${N > 1 ? 's' : ''} read...`);
var fileName = process.argv[2].split('.');
fileName.pop();
fileName.push('bin');
fileName = fileName.join('.');
let bufNew = dumpBin(buf);
fs.writeFileSync(fileName, bufNew, 'binary');
console.log(`written to ${fileName}`);
} else {
console.log("wrong format");
}

module.exports.parseDataToJson = parseDataToJson;
module.exports.dumpBin = dumpBin;
module.exports.getFlat = getFlat;
21 changes: 21 additions & 0 deletions 09-fuzz/flat-azam-shaprunov/student.fbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
namespace ds;

table Proj {
repo : string;
mark : ubyte;
}

table Student {
name : string;
login : string;
group : string;
practice : [ubyte];
project : Proj;
mark : float;
}

table Students {
kings : [Student];
}

root_type Students;
Loading