Range-check all values passed to C code.
This commit is contained in:
parent
daf42fdc0d
commit
603fbdf239
@ -28,12 +28,13 @@ from PyQt5.QtCore import pyqtSlot, Qt, QObject, QProcess
|
||||
from PyQt5.QtGui import QClipboard
|
||||
from PyQt5.QtPrintSupport import QPrintDialog, QPrintPreviewDialog
|
||||
|
||||
import qutebrowser.utils.url as urlutils
|
||||
import qutebrowser.utils.message as message
|
||||
import qutebrowser.commands.utils as cmdutils
|
||||
import qutebrowser.utils.webelem as webelem
|
||||
import qutebrowser.config.config as config
|
||||
import qutebrowser.browser.hints as hints
|
||||
import qutebrowser.utils.url as urlutils
|
||||
import qutebrowser.utils.message as message
|
||||
import qutebrowser.utils.webelem as webelem
|
||||
import qutebrowser.utils.misc as utils
|
||||
from qutebrowser.utils.misc import shell_escape
|
||||
from qutebrowser.commands.exceptions import CommandError
|
||||
|
||||
@ -75,6 +76,7 @@ class CurCommandDispatcher(QObject):
|
||||
perc = int(count)
|
||||
else:
|
||||
perc = float(perc)
|
||||
perc = utils.check_overflow(perc, 'int', fatal=False)
|
||||
frame = self._tabs.currentWidget().page_.currentFrame()
|
||||
m = frame.scrollBarMaximum(orientation)
|
||||
if m == 0:
|
||||
@ -294,6 +296,8 @@ class CurCommandDispatcher(QObject):
|
||||
"""
|
||||
dx = int(int(count) * float(dx))
|
||||
dy = int(int(count) * float(dy))
|
||||
cmdutils.check_overflow(dx, 'int')
|
||||
cmdutils.check_overflow(dy, 'int')
|
||||
self._tabs.currentWidget().page_.currentFrame().scroll(dx, dy)
|
||||
|
||||
@cmdutils.register(instance='mainwindow.tabs.cur', name='scroll_perc_x',
|
||||
@ -333,8 +337,11 @@ class CurCommandDispatcher(QObject):
|
||||
"""
|
||||
frame = self._tabs.currentWidget().page_.currentFrame()
|
||||
size = frame.geometry()
|
||||
frame.scroll(int(count) * float(mx) * size.width(),
|
||||
int(count) * float(my) * size.height())
|
||||
dx = int(count) * float(mx) * size.width()
|
||||
dy = int(count) * float(my) * size.height()
|
||||
cmdutils.check_overflow(dx, 'int')
|
||||
cmdutils.check_overflow(dy, 'int')
|
||||
frame.scroll(dx, dy)
|
||||
|
||||
@cmdutils.register(instance='mainwindow.tabs.cur')
|
||||
def yank(self, sel=False):
|
||||
|
@ -24,11 +24,32 @@ Module attributes:
|
||||
import inspect
|
||||
from collections import Iterable
|
||||
|
||||
import qutebrowser.utils.misc as utils
|
||||
from qutebrowser.commands._command import Command
|
||||
from qutebrowser.commands.exceptions import CommandError
|
||||
|
||||
cmd_dict = {}
|
||||
|
||||
|
||||
def check_overflow(arg, ctype):
|
||||
"""Check if the given argument is in bounds for the given type.
|
||||
|
||||
Args:
|
||||
arg: The argument to check
|
||||
ctype: The C/Qt type to check as a string.
|
||||
|
||||
Raise:
|
||||
CommandError if the argument is out of bounds.
|
||||
ValueError if the given ctype is unknown.
|
||||
"""
|
||||
# FIXME we somehow should have nicer exceptions...
|
||||
try:
|
||||
utils.check_overflow(arg, ctype)
|
||||
except OverflowError:
|
||||
raise CommandError("Numeric argument is too large for internal {} "
|
||||
"representation.".format(ctype))
|
||||
|
||||
|
||||
def arg_or_count(arg, count, default=None, countzero=None):
|
||||
"""Get a value based on an argument and count given to a command.
|
||||
|
||||
|
@ -568,6 +568,8 @@ class WebKitBytes(BaseType):
|
||||
if self.maxsize is not None and val > self.maxsize:
|
||||
raise ValidationError(value, "must be {} "
|
||||
"maximum!".format(self.maxsize))
|
||||
if val < 0:
|
||||
raise ValidationError(value, "must be 0 minimum!")
|
||||
|
||||
def transform(self, value):
|
||||
if value == '':
|
||||
|
@ -25,16 +25,12 @@ DATA: The config defaults, an OrderedDict of sections.
|
||||
"""
|
||||
|
||||
import re
|
||||
import struct
|
||||
from collections import OrderedDict
|
||||
|
||||
from qutebrowser.config._value import SettingValue
|
||||
import qutebrowser.config._conftypes as types
|
||||
import qutebrowser.config._sections as sect
|
||||
|
||||
|
||||
INT_MAX = 2 ** (8 * struct.calcsize('@i')) // 2 - 1
|
||||
INT64_MAX = 2 ** 64 // 2 - 1
|
||||
from qutebrowser.utils.misc import MAXVALS
|
||||
|
||||
|
||||
FIRST_COMMENT = r"""
|
||||
@ -253,7 +249,7 @@ DATA = OrderedDict([
|
||||
|
||||
('input', sect.KeyValue(
|
||||
('timeout',
|
||||
SettingValue(types.Int(minval=0), '500'),
|
||||
SettingValue(types.Int(minval=0, maxval=MAXVALS['int']), '500'),
|
||||
"Timeout for ambiguous keybindings."),
|
||||
|
||||
('insert-mode-on-plugins',
|
||||
@ -301,11 +297,11 @@ DATA = OrderedDict([
|
||||
"Whether to wrap when changing tabs."),
|
||||
|
||||
('min-tab-width',
|
||||
SettingValue(types.Int(), '100'),
|
||||
SettingValue(types.Int(minval=1), '100'),
|
||||
"The minimum width of a tab."),
|
||||
|
||||
('max-tab-width',
|
||||
SettingValue(types.Int(), '200'),
|
||||
SettingValue(types.Int(minval=1), '200'),
|
||||
"The maximum width of a tab."),
|
||||
|
||||
('show-favicons',
|
||||
@ -477,37 +473,43 @@ DATA = OrderedDict([
|
||||
"Font family for fantasy fonts."),
|
||||
|
||||
('font-size-minimum',
|
||||
SettingValue(types.Int(none=True), ''),
|
||||
SettingValue(types.Int(none=True, minval=1, maxval=MAXVALS['int']),
|
||||
''),
|
||||
"The hard minimum font size."),
|
||||
|
||||
('font-size-minimum-logical',
|
||||
SettingValue(types.Int(none=True), ''),
|
||||
SettingValue(types.Int(none=True, minval=1, maxval=MAXVALS['int']),
|
||||
''),
|
||||
"The minimum logical font size that is applied when zooming out."),
|
||||
|
||||
('font-size-default',
|
||||
SettingValue(types.Int(none=True), ''),
|
||||
SettingValue(types.Int(none=True, minval=1, maxval=MAXVALS['int']),
|
||||
''),
|
||||
"The default font size for regular text."),
|
||||
|
||||
('font-size-default-fixed',
|
||||
SettingValue(types.Int(none=True), ''),
|
||||
SettingValue(types.Int(none=True, minval=1, maxval=MAXVALS['int']),
|
||||
''),
|
||||
"The default font size for fixed-pitch text."),
|
||||
|
||||
('maximum-pages-in-cache',
|
||||
SettingValue(types.Int(none=True), ''),
|
||||
SettingValue(types.Int(none=True, minval=0, maxval=MAXVALS['int']),
|
||||
''),
|
||||
"Sets the maximum number of pages to hold in the memory page cache."),
|
||||
|
||||
('object-cache-capacities',
|
||||
SettingValue(types.WebKitBytesList(length=3, maxsize=INT_MAX), ''),
|
||||
SettingValue(types.WebKitBytesList(length=3, maxsize=MAXVALS['int']),
|
||||
''),
|
||||
"Specifies the capacities for the memory cache for dead objects "
|
||||
"such as stylesheets or scripts. Three values are expected: "
|
||||
"cacheMinDeadCapacity, cacheMaxDead, totalCapacity"),
|
||||
|
||||
('offline-storage-default-quota',
|
||||
SettingValue(types.WebKitBytes(maxsize=INT64_MAX), ''),
|
||||
SettingValue(types.WebKitBytes(maxsize=MAXVALS['int64']), ''),
|
||||
"Default quota for new offline storage databases."),
|
||||
|
||||
('offline-web-application-cache-quota',
|
||||
SettingValue(types.WebKitBytes(maxsize=INT64_MAX), ''),
|
||||
SettingValue(types.WebKitBytes(maxsize=MAXVALS['int64']), ''),
|
||||
"Quota for the offline web application cache."),
|
||||
)),
|
||||
|
||||
|
@ -34,6 +34,48 @@ import qutebrowser.utils.misc as utils
|
||||
from qutebrowser.test.helpers import environ_set_temp
|
||||
|
||||
|
||||
class CheckOverflowTests(TestCase):
|
||||
|
||||
"""Test check_overflow."""
|
||||
|
||||
INT32_MIN = -(2 ** 31)
|
||||
INT32_MAX = 2 ** 31 - 1
|
||||
INT64_MIN = -(2 ** 63)
|
||||
INT64_MAX = 2 ** 63 - 1
|
||||
|
||||
GOOD_VALUES = {
|
||||
'int': [-1, 0, 1, 23.42, INT32_MIN, INT32_MAX],
|
||||
'int64': [-1, 0, 1, 23.42, INT64_MIN, INT64_MAX],
|
||||
}
|
||||
|
||||
BAD_VALUES = {
|
||||
'int': [(INT32_MIN - 1, INT32_MIN),
|
||||
(INT32_MAX + 1, INT32_MAX),
|
||||
(float(INT32_MAX + 1), INT32_MAX)],
|
||||
'int64': [(INT64_MIN - 1, INT64_MIN),
|
||||
(INT64_MAX + 1, INT64_MAX),
|
||||
(float(INT64_MAX + 1), INT64_MAX)],
|
||||
}
|
||||
|
||||
def test_good_values(self):
|
||||
for ctype, vals in self.GOOD_VALUES.items():
|
||||
for val in vals:
|
||||
utils.check_overflow(val, ctype)
|
||||
|
||||
def test_bad_values_fatal(self):
|
||||
for ctype, vals in self.BAD_VALUES.items():
|
||||
for (val, _) in vals:
|
||||
with self.assertRaises(OverflowError, msg=ctype):
|
||||
utils.check_overflow(val, ctype)
|
||||
|
||||
def test_bad_values_nonfatal(self):
|
||||
for ctype, vals in self.BAD_VALUES.items():
|
||||
for (val, replacement) in vals:
|
||||
newval = utils.check_overflow(val, ctype, fatal=False)
|
||||
self.assertEqual(newval, replacement,
|
||||
"{}: {}".format(ctype, val))
|
||||
|
||||
|
||||
class ReadFileTests(TestCase):
|
||||
|
||||
"""Test read_file."""
|
||||
|
@ -15,7 +15,12 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Other utilities which don't fit anywhere else."""
|
||||
"""Other utilities which don't fit anywhere else.
|
||||
|
||||
Module attributes:
|
||||
MAXVAL: A dictionary of C/Qt types (as string) mapped to their maximum
|
||||
value.
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
@ -31,6 +36,49 @@ from PyQt5.QtCore import QCoreApplication, QStandardPaths
|
||||
import qutebrowser
|
||||
|
||||
|
||||
MAXVALS = {
|
||||
'int': 2 ** 31 - 1,
|
||||
'int64': 2 ** 63 - 1,
|
||||
}
|
||||
|
||||
MINVALS = {
|
||||
'int': -(2 ** 31),
|
||||
'int64': -(2 ** 63),
|
||||
}
|
||||
|
||||
|
||||
def check_overflow(arg, ctype, fatal=True):
|
||||
"""Check if the given argument is in bounds for the given type.
|
||||
|
||||
Args:
|
||||
arg: The argument to check
|
||||
ctype: The C/Qt type to check as a string.
|
||||
fatal: Wether to raise exceptions (True) or truncate values (False)
|
||||
|
||||
Return
|
||||
The truncated argument if fatal=False
|
||||
The original argument if it's in bounds.
|
||||
|
||||
Raise:
|
||||
OverflowError if the argument is out of bounds and fatal=True.
|
||||
"""
|
||||
# FIXME we somehow should have nicer exceptions...
|
||||
maxval = MAXVALS[ctype]
|
||||
minval = MINVALS[ctype]
|
||||
if arg > maxval:
|
||||
if fatal:
|
||||
raise OverflowError(arg)
|
||||
else:
|
||||
return maxval
|
||||
elif arg < minval:
|
||||
if fatal:
|
||||
raise OverflowError(arg)
|
||||
else:
|
||||
return minval
|
||||
else:
|
||||
return arg
|
||||
|
||||
|
||||
def read_file(filename):
|
||||
"""Get the contents of a file contained with qutebrowser.
|
||||
|
||||
|
@ -246,6 +246,7 @@ class TabbedBrowser(TabWidget):
|
||||
if count is None:
|
||||
return self.currentWidget()
|
||||
elif 1 <= count <= self.count():
|
||||
cmdutils.check_overflow(count + 1, 'int')
|
||||
return self.widget(count - 1)
|
||||
else:
|
||||
return None
|
||||
@ -418,6 +419,7 @@ class TabbedBrowser(TabWidget):
|
||||
countzero=self.count())
|
||||
except ValueError as e:
|
||||
raise CommandError(e)
|
||||
cmdutils.check_overflow(idx + 1, 'int')
|
||||
if 1 <= idx <= self.count():
|
||||
self.setCurrentIndex(idx - 1)
|
||||
else:
|
||||
@ -448,6 +450,8 @@ class TabbedBrowser(TabWidget):
|
||||
cur_idx = self.currentIndex()
|
||||
icon = self.tabIcon(cur_idx)
|
||||
label = self.tabText(cur_idx)
|
||||
cmdutils.check_overflow(cur_idx, 'int')
|
||||
cmdutils.check_overflow(next_idx, 'int')
|
||||
self.removeTab(cur_idx)
|
||||
self.insertTab(new_idx, tab, icon, label)
|
||||
self.setCurrentIndex(new_idx)
|
||||
|
@ -24,11 +24,12 @@ from PyQt5.QtCore import pyqtSlot, QRect, QPoint, QCoreApplication
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout
|
||||
from PyQt5.QtWebKitWidgets import QWebInspector
|
||||
|
||||
import qutebrowser.commands.utils as cmdutils
|
||||
import qutebrowser.config.config as config
|
||||
import qutebrowser.utils.misc as utils
|
||||
from qutebrowser.widgets.statusbar.bar import StatusBar
|
||||
from qutebrowser.widgets._tabbedbrowser import TabbedBrowser
|
||||
from qutebrowser.widgets._completion import CompletionView
|
||||
import qutebrowser.commands.utils as cmdutils
|
||||
import qutebrowser.config.config as config
|
||||
|
||||
|
||||
class MainWindow(QWidget):
|
||||
@ -102,7 +103,9 @@ class MainWindow(QWidget):
|
||||
height = int(confheight)
|
||||
# hpoint now would be the bottom-left edge of the widget if it was on
|
||||
# the top of the main window.
|
||||
topleft = QPoint(0, self.height() - self.status.height() - height)
|
||||
topleft_y = self.height() - self.status.height() - height
|
||||
topleft_y = utils.check_overflow(topleft_y, 'int', fatal=False)
|
||||
topleft = QPoint(0, topleft_y)
|
||||
bottomright = self.status.geometry().topRight()
|
||||
if self.inspector.isVisible():
|
||||
topleft -= QPoint(0, self.inspector.height())
|
||||
|
Loading…
Reference in New Issue
Block a user