diff options
author | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2024-09-28 00:30:09 +0200 |
---|---|---|
committer | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2024-09-28 05:02:34 +0200 |
commit | 5395a7da901e4af9758762215b75d943ef253ef3 (patch) | |
tree | dcc0f2298e1e0d6a118b6b63347d3bd5baa596b7 | |
parent | 973e50d1f43b680863551f1aea30d88616488e84 (diff) | |
download | sciteco-5395a7da901e4af9758762215b75d943ef253ef3.tar.gz |
check the memory limit and allow interruptions when loading files
* Previously you could open files of arbitrary size and the limit would be checked only afterwards.
* Many, but not all, cases should now be detected earlier.
Since Scintilla allocates lots of memory as part of rendering,
you can still run into memory limits even after successfully loading the file.
* Loading extremely large files can also be potentially slow.
Therefore, it is now possible to interrupt via CTRL+C.
Again, if the UI is blocking because of stuff done as part of rendering,
you still may not be able to interrupt the "blocking" operation.
-rw-r--r-- | src/view.c | 28 | ||||
-rw-r--r-- | tests/testsuite.at | 5 |
2 files changed, 28 insertions, 5 deletions
@@ -45,6 +45,7 @@ #include "error.h" #include "qreg.h" #include "eol.h" +#include "memory.h" #include "view.h" /** @memberof teco_view_t */ @@ -216,8 +217,11 @@ teco_view_load_from_channel(teco_view_t *ctx, GIOChannel *channel, GError **erro */ struct stat stat_buf = {.st_size = 0}; if (!fstat(g_io_channel_unix_get_fd(channel), &stat_buf) && - stat_buf.st_size > 0) + stat_buf.st_size > 0) { + if (!teco_memory_check(stat_buf.st_size, error)) + goto error; teco_view_ssm(ctx, SCI_ALLOCATE, stat_buf.st_size, 0); + } g_auto(teco_eol_reader_t) reader; teco_eol_reader_init_gio(&reader, channel); @@ -230,14 +234,24 @@ teco_view_load_from_channel(teco_view_t *ctx, GIOChannel *channel, GError **erro teco_string_t str; GIOStatus rc = teco_eol_reader_convert(&reader, &str.data, &str.len, error); - if (rc == G_IO_STATUS_ERROR) { - teco_view_ssm(ctx, SCI_ENDUNDOACTION, 0, 0); - return FALSE; - } + if (rc == G_IO_STATUS_ERROR) + goto error; if (rc == G_IO_STATUS_EOF) break; teco_view_ssm(ctx, SCI_APPENDTEXT, str.len, (sptr_t)str.data); + + /* + * Even if we checked initially, knowing the file size, + * Scintilla could allocate much more bytes. + */ + if (!teco_memory_check(0, error)) + goto error; + + if (G_UNLIKELY(teco_interface_is_interrupted())) { + teco_error_interrupted_set(error); + goto error; + } } /* @@ -259,6 +273,10 @@ teco_view_load_from_channel(teco_view_t *ctx, GIOChannel *channel, GError **erro teco_view_ssm(ctx, SCI_ENDUNDOACTION, 0, 0); return TRUE; + +error: + teco_view_ssm(ctx, SCI_ENDUNDOACTION, 0, 0); + return FALSE; } /** diff --git a/tests/testsuite.at b/tests/testsuite.at index 8a3ba96..fc7de4f 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -160,6 +160,11 @@ AT_SETUP([Memory limiting during spawning]) AT_CHECK([$SCITECO -e "50*1000*1000,2EJ 0,128ED @EC'dd if=/dev/zero'"], 1, ignore, ignore) AT_CLEANUP +AT_SETUP([Memory limiting during file reading]) +AT_CHECK([dd if=/dev/zero of=big-file.txt bs=1000 count=50000], 0, ignore, ignore) +AT_CHECK([$SCITECO -8e "50*1000*1000,2EJ @EB'big-file.txt'"], 1, ignore, ignore) +AT_CLEANUP + AT_SETUP([Q-Register stack cleanup]) AT_CHECK([$SCITECO -e '@<:@a'], 0, ignore, ignore) AT_CLEANUP |