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.QtGui import QClipboard
|
||||||
from PyQt5.QtPrintSupport import QPrintDialog, QPrintPreviewDialog
|
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.commands.utils as cmdutils
|
||||||
import qutebrowser.utils.webelem as webelem
|
|
||||||
import qutebrowser.config.config as config
|
import qutebrowser.config.config as config
|
||||||
import qutebrowser.browser.hints as hints
|
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.utils.misc import shell_escape
|
||||||
from qutebrowser.commands.exceptions import CommandError
|
from qutebrowser.commands.exceptions import CommandError
|
||||||
|
|
||||||
@ -75,6 +76,7 @@ class CurCommandDispatcher(QObject):
|
|||||||
perc = int(count)
|
perc = int(count)
|
||||||
else:
|
else:
|
||||||
perc = float(perc)
|
perc = float(perc)
|
||||||
|
perc = utils.check_overflow(perc, 'int', fatal=False)
|
||||||
frame = self._tabs.currentWidget().page_.currentFrame()
|
frame = self._tabs.currentWidget().page_.currentFrame()
|
||||||
m = frame.scrollBarMaximum(orientation)
|
m = frame.scrollBarMaximum(orientation)
|
||||||
if m == 0:
|
if m == 0:
|
||||||
@ -294,6 +296,8 @@ class CurCommandDispatcher(QObject):
|
|||||||
"""
|
"""
|
||||||
dx = int(int(count) * float(dx))
|
dx = int(int(count) * float(dx))
|
||||||
dy = int(int(count) * float(dy))
|
dy = int(int(count) * float(dy))
|
||||||
|
cmdutils.check_overflow(dx, 'int')
|
||||||
|
cmdutils.check_overflow(dy, 'int')
|
||||||
self._tabs.currentWidget().page_.currentFrame().scroll(dx, dy)
|
self._tabs.currentWidget().page_.currentFrame().scroll(dx, dy)
|
||||||
|
|
||||||
@cmdutils.register(instance='mainwindow.tabs.cur', name='scroll_perc_x',
|
@cmdutils.register(instance='mainwindow.tabs.cur', name='scroll_perc_x',
|
||||||
@ -333,8 +337,11 @@ class CurCommandDispatcher(QObject):
|
|||||||
"""
|
"""
|
||||||
frame = self._tabs.currentWidget().page_.currentFrame()
|
frame = self._tabs.currentWidget().page_.currentFrame()
|
||||||
size = frame.geometry()
|
size = frame.geometry()
|
||||||
frame.scroll(int(count) * float(mx) * size.width(),
|
dx = int(count) * float(mx) * size.width()
|
||||||
int(count) * float(my) * size.height())
|
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')
|
@cmdutils.register(instance='mainwindow.tabs.cur')
|
||||||
def yank(self, sel=False):
|
def yank(self, sel=False):
|
||||||
|
@ -24,11 +24,32 @@ Module attributes:
|
|||||||
import inspect
|
import inspect
|
||||||
from collections import Iterable
|
from collections import Iterable
|
||||||
|
|
||||||
|
import qutebrowser.utils.misc as utils
|
||||||
from qutebrowser.commands._command import Command
|
from qutebrowser.commands._command import Command
|
||||||
|
from qutebrowser.commands.exceptions import CommandError
|
||||||
|
|
||||||
cmd_dict = {}
|
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):
|
def arg_or_count(arg, count, default=None, countzero=None):
|
||||||
"""Get a value based on an argument and count given to a command.
|
"""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:
|
if self.maxsize is not None and val > self.maxsize:
|
||||||
raise ValidationError(value, "must be {} "
|
raise ValidationError(value, "must be {} "
|
||||||
"maximum!".format(self.maxsize))
|
"maximum!".format(self.maxsize))
|
||||||
|
if val < 0:
|
||||||
|
raise ValidationError(value, "must be 0 minimum!")
|
||||||
|
|
||||||
def transform(self, value):
|
def transform(self, value):
|
||||||
if value == '':
|
if value == '':
|
||||||
|
@ -25,16 +25,12 @@ DATA: The config defaults, an OrderedDict of sections.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import struct
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
from qutebrowser.config._value import SettingValue
|
from qutebrowser.config._value import SettingValue
|
||||||
import qutebrowser.config._conftypes as types
|
import qutebrowser.config._conftypes as types
|
||||||
import qutebrowser.config._sections as sect
|
import qutebrowser.config._sections as sect
|
||||||
|
from qutebrowser.utils.misc import MAXVALS
|
||||||
|
|
||||||
INT_MAX = 2 ** (8 * struct.calcsize('@i')) // 2 - 1
|
|
||||||
INT64_MAX = 2 ** 64 // 2 - 1
|
|
||||||
|
|
||||||
|
|
||||||
FIRST_COMMENT = r"""
|
FIRST_COMMENT = r"""
|
||||||
@ -253,7 +249,7 @@ DATA = OrderedDict([
|
|||||||
|
|
||||||
('input', sect.KeyValue(
|
('input', sect.KeyValue(
|
||||||
('timeout',
|
('timeout',
|
||||||
SettingValue(types.Int(minval=0), '500'),
|
SettingValue(types.Int(minval=0, maxval=MAXVALS['int']), '500'),
|
||||||
"Timeout for ambiguous keybindings."),
|
"Timeout for ambiguous keybindings."),
|
||||||
|
|
||||||
('insert-mode-on-plugins',
|
('insert-mode-on-plugins',
|
||||||
@ -301,11 +297,11 @@ DATA = OrderedDict([
|
|||||||
"Whether to wrap when changing tabs."),
|
"Whether to wrap when changing tabs."),
|
||||||
|
|
||||||
('min-tab-width',
|
('min-tab-width',
|
||||||
SettingValue(types.Int(), '100'),
|
SettingValue(types.Int(minval=1), '100'),
|
||||||
"The minimum width of a tab."),
|
"The minimum width of a tab."),
|
||||||
|
|
||||||
('max-tab-width',
|
('max-tab-width',
|
||||||
SettingValue(types.Int(), '200'),
|
SettingValue(types.Int(minval=1), '200'),
|
||||||
"The maximum width of a tab."),
|
"The maximum width of a tab."),
|
||||||
|
|
||||||
('show-favicons',
|
('show-favicons',
|
||||||
@ -477,37 +473,43 @@ DATA = OrderedDict([
|
|||||||
"Font family for fantasy fonts."),
|
"Font family for fantasy fonts."),
|
||||||
|
|
||||||
('font-size-minimum',
|
('font-size-minimum',
|
||||||
SettingValue(types.Int(none=True), ''),
|
SettingValue(types.Int(none=True, minval=1, maxval=MAXVALS['int']),
|
||||||
|
''),
|
||||||
"The hard minimum font size."),
|
"The hard minimum font size."),
|
||||||
|
|
||||||
('font-size-minimum-logical',
|
('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."),
|
"The minimum logical font size that is applied when zooming out."),
|
||||||
|
|
||||||
('font-size-default',
|
('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."),
|
"The default font size for regular text."),
|
||||||
|
|
||||||
('font-size-default-fixed',
|
('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."),
|
"The default font size for fixed-pitch text."),
|
||||||
|
|
||||||
('maximum-pages-in-cache',
|
('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."),
|
"Sets the maximum number of pages to hold in the memory page cache."),
|
||||||
|
|
||||||
('object-cache-capacities',
|
('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 "
|
"Specifies the capacities for the memory cache for dead objects "
|
||||||
"such as stylesheets or scripts. Three values are expected: "
|
"such as stylesheets or scripts. Three values are expected: "
|
||||||
"cacheMinDeadCapacity, cacheMaxDead, totalCapacity"),
|
"cacheMinDeadCapacity, cacheMaxDead, totalCapacity"),
|
||||||
|
|
||||||
('offline-storage-default-quota',
|
('offline-storage-default-quota',
|
||||||
SettingValue(types.WebKitBytes(maxsize=INT64_MAX), ''),
|
SettingValue(types.WebKitBytes(maxsize=MAXVALS['int64']), ''),
|
||||||
"Default quota for new offline storage databases."),
|
"Default quota for new offline storage databases."),
|
||||||
|
|
||||||
('offline-web-application-cache-quota',
|
('offline-web-application-cache-quota',
|
||||||
SettingValue(types.WebKitBytes(maxsize=INT64_MAX), ''),
|
SettingValue(types.WebKitBytes(maxsize=MAXVALS['int64']), ''),
|
||||||
"Quota for the offline web application cache."),
|
"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
|
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):
|
class ReadFileTests(TestCase):
|
||||||
|
|
||||||
"""Test read_file."""
|
"""Test read_file."""
|
||||||
|
@ -15,7 +15,12 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
|
# 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 os
|
||||||
import re
|
import re
|
||||||
@ -31,6 +36,49 @@ from PyQt5.QtCore import QCoreApplication, QStandardPaths
|
|||||||
import qutebrowser
|
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):
|
def read_file(filename):
|
||||||
"""Get the contents of a file contained with qutebrowser.
|
"""Get the contents of a file contained with qutebrowser.
|
||||||
|
|
||||||
|
@ -246,6 +246,7 @@ class TabbedBrowser(TabWidget):
|
|||||||
if count is None:
|
if count is None:
|
||||||
return self.currentWidget()
|
return self.currentWidget()
|
||||||
elif 1 <= count <= self.count():
|
elif 1 <= count <= self.count():
|
||||||
|
cmdutils.check_overflow(count + 1, 'int')
|
||||||
return self.widget(count - 1)
|
return self.widget(count - 1)
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
@ -418,6 +419,7 @@ class TabbedBrowser(TabWidget):
|
|||||||
countzero=self.count())
|
countzero=self.count())
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
raise CommandError(e)
|
raise CommandError(e)
|
||||||
|
cmdutils.check_overflow(idx + 1, 'int')
|
||||||
if 1 <= idx <= self.count():
|
if 1 <= idx <= self.count():
|
||||||
self.setCurrentIndex(idx - 1)
|
self.setCurrentIndex(idx - 1)
|
||||||
else:
|
else:
|
||||||
@ -448,6 +450,8 @@ class TabbedBrowser(TabWidget):
|
|||||||
cur_idx = self.currentIndex()
|
cur_idx = self.currentIndex()
|
||||||
icon = self.tabIcon(cur_idx)
|
icon = self.tabIcon(cur_idx)
|
||||||
label = self.tabText(cur_idx)
|
label = self.tabText(cur_idx)
|
||||||
|
cmdutils.check_overflow(cur_idx, 'int')
|
||||||
|
cmdutils.check_overflow(next_idx, 'int')
|
||||||
self.removeTab(cur_idx)
|
self.removeTab(cur_idx)
|
||||||
self.insertTab(new_idx, tab, icon, label)
|
self.insertTab(new_idx, tab, icon, label)
|
||||||
self.setCurrentIndex(new_idx)
|
self.setCurrentIndex(new_idx)
|
||||||
|
@ -24,11 +24,12 @@ from PyQt5.QtCore import pyqtSlot, QRect, QPoint, QCoreApplication
|
|||||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout
|
from PyQt5.QtWidgets import QWidget, QVBoxLayout
|
||||||
from PyQt5.QtWebKitWidgets import QWebInspector
|
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.statusbar.bar import StatusBar
|
||||||
from qutebrowser.widgets._tabbedbrowser import TabbedBrowser
|
from qutebrowser.widgets._tabbedbrowser import TabbedBrowser
|
||||||
from qutebrowser.widgets._completion import CompletionView
|
from qutebrowser.widgets._completion import CompletionView
|
||||||
import qutebrowser.commands.utils as cmdutils
|
|
||||||
import qutebrowser.config.config as config
|
|
||||||
|
|
||||||
|
|
||||||
class MainWindow(QWidget):
|
class MainWindow(QWidget):
|
||||||
@ -102,7 +103,9 @@ class MainWindow(QWidget):
|
|||||||
height = int(confheight)
|
height = int(confheight)
|
||||||
# hpoint now would be the bottom-left edge of the widget if it was on
|
# hpoint now would be the bottom-left edge of the widget if it was on
|
||||||
# the top of the main window.
|
# 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()
|
bottomright = self.status.geometry().topRight()
|
||||||
if self.inspector.isVisible():
|
if self.inspector.isVisible():
|
||||||
topleft -= QPoint(0, self.inspector.height())
|
topleft -= QPoint(0, self.inspector.height())
|
||||||
|
Loading…
Reference in New Issue
Block a user