Mercurial > octave
view libgui/qterminal/libqterminal/unix/BlockArray.cpp @ 30264:de3275323dff
libqterminal: Avoid integer overflow in multiplication.
* libgui/qterminal/libqterminal/unix/BlockArray.cpp (moveBlock,
BlockArray::increaseBuffer): Cast integer offset argument of fseek to long int
before multiplication to avoid integer overflow. The overflow is very
unlikely to happen and this is adopted code (not actually maintained). But
it's an easy fix that doesn't clutter the code too much.
author | Markus Mützel <markus.muetzel@gmx.de> |
---|---|
date | Sun, 31 Oct 2021 18:06:22 +0100 |
parents | 194eb4bd202b |
children |
line wrap: on
line source
/* This file is part of Konsole, an X terminal. Copyright (C) 2000, 2013 by Stephan Kulow <coolo@kde.org> Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008 This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ // Own #include "unix/BlockArray.h" #include <QtCore> // System #include <assert.h> #include <sys/mman.h> #include <sys/param.h> #include <unistd.h> #include <stdio.h> static int blocksize = 0; BlockArray::BlockArray() : size(0), current(size_t(-1)), index(size_t(-1)), lastmap(nullptr), lastmap_index(size_t(-1)), lastblock(nullptr), ion(-1), length(0) { // lastmap_index = index = current = size_t(-1); if (blocksize == 0) blocksize = ((sizeof(Block) / getpagesize()) + 1) * getpagesize(); } BlockArray::~BlockArray() { setHistorySize(0); assert(!lastblock); } size_t BlockArray::append(Block *block) { if (!size) return size_t(-1); ++current; if (current >= size) current = 0; int rc; rc = lseek(ion, current * blocksize, SEEK_SET); if (rc < 0) { perror("HistoryBuffer::add.seek"); setHistorySize(0); return size_t(-1); } rc = write(ion, block, blocksize); if (rc < 0) { perror("HistoryBuffer::add.write"); setHistorySize(0); return size_t(-1); } length++; if (length > size) length = size; ++index; delete block; return current; } size_t BlockArray::newBlock() { if (!size) return size_t(-1); append(lastblock); lastblock = new Block(); return index + 1; } Block *BlockArray::lastBlock() const { return lastblock; } bool BlockArray::has(size_t i) const { if (i == index + 1) return true; if (i > index) return false; if (index - i >= length) return false; return true; } const Block* BlockArray::at(size_t i) { if (i == index + 1) return lastblock; if (i == lastmap_index) return lastmap; if (i > index) { qDebug() << "BlockArray::at() i > index\n"; return nullptr; } // if (index - i >= length) { // kDebug(1211) << "BlockArray::at() index - i >= length\n"; // return 0; // } size_t j = i; // (current - (index - i) + (index/size+1)*size) % size ; assert(j < size); unmap(); Block *block = (Block*)mmap(nullptr, blocksize, PROT_READ, MAP_PRIVATE, ion, j * blocksize); if (block == (Block*)-1) { perror("mmap"); return nullptr; } lastmap = block; lastmap_index = i; return block; } void BlockArray::unmap() { if (lastmap) { int res = munmap((char*)lastmap, blocksize); if (res < 0) perror("munmap"); } lastmap = nullptr; lastmap_index = size_t(-1); } bool BlockArray::setSize(size_t newsize) { return setHistorySize(newsize * 1024 / blocksize); } bool BlockArray::setHistorySize(size_t newsize) { // kDebug(1211) << "setHistorySize " << size << " " << newsize; if (size == newsize) return false; unmap(); if (!newsize) { delete lastblock; lastblock = nullptr; if (ion >= 0) close(ion); ion = -1; current = size_t(-1); return true; } if (!size) { FILE* tmp = tmpfile(); if (!tmp) { perror("konsole: cannot open temp file.\n"); } else { ion = dup(fileno(tmp)); if (ion<0) { perror("konsole: cannot dup temp file.\n"); fclose(tmp); } } if (ion < 0) return false; assert(!lastblock); lastblock = new Block(); size = newsize; return false; } if (newsize > size) { increaseBuffer(); size = newsize; return false; } else { decreaseBuffer(newsize); if (ftruncate(ion, length*blocksize) == -1) perror("ftruncate"); size = newsize; return true; } } void moveBlock(FILE *fion, int cursor, int newpos, char *buffer2) { int res = fseek(fion, static_cast<long int> (cursor) * blocksize, SEEK_SET); if (res) perror("fseek"); res = fread(buffer2, blocksize, 1, fion); if (res != 1) perror("fread"); res = fseek(fion, static_cast<long int> (newpos) * blocksize, SEEK_SET); if (res) perror("fseek"); res = fwrite(buffer2, blocksize, 1, fion); if (res != 1) perror("fwrite"); // printf("moving block %d to %d\n", cursor, newpos); } void BlockArray::decreaseBuffer(size_t newsize) { if (index < newsize) // still fits in whole return; int offset = (current - (newsize - 1) + size) % size; if (!offset) return; // The Block constructor could do somthing in future... char *buffer1 = new char[blocksize]; FILE *fion = fdopen(dup(ion), "w+b"); if (!fion) { delete [] buffer1; perror("fdopen/dup"); return; } int firstblock; if (current <= newsize) { firstblock = current + 1; } else { firstblock = 0; } size_t oldpos; for (size_t i = 0, cursor=firstblock; i < newsize; i++) { oldpos = (size + cursor + offset) % size; moveBlock(fion, oldpos, cursor, buffer1); if (oldpos < newsize) { cursor = oldpos; } else cursor++; } current = newsize - 1; length = newsize; delete [] buffer1; fclose(fion); } void BlockArray::increaseBuffer() { if (index < size) // not even wrapped once return; int offset = (current + size + 1) % size; if (!offset) // no moving needed return; // The Block constructor could do somthing in future... char *buffer1 = new char[blocksize]; char *buffer2 = new char[blocksize]; int runs = 1; int bpr = size; // blocks per run if (size % offset == 0) { bpr = size / offset; runs = offset; } FILE *fion = fdopen(dup(ion), "w+b"); if (!fion) { perror("fdopen/dup"); delete [] buffer1; delete [] buffer2; return; } int res; for (int i = 0; i < runs; i++) { // free one block in chain int firstblock = (offset + i) % size; res = fseek(fion, static_cast<long int> (firstblock) * blocksize, SEEK_SET); if (res) perror("fseek"); res = fread(buffer1, blocksize, 1, fion); if (res != 1) perror("fread"); int newpos = 0; for (int j = 1, cursor=firstblock; j < bpr; j++) { cursor = (cursor + offset) % size; newpos = (cursor - offset + size) % size; moveBlock(fion, cursor, newpos, buffer2); } res = fseek(fion, static_cast<long int> (i) * blocksize, SEEK_SET); if (res) perror("fseek"); res = fwrite(buffer1, blocksize, 1, fion); if (res != 1) perror("fwrite"); } current = size - 1; length = size; delete [] buffer1; delete [] buffer2; fclose(fion); }