aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/memory.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/memory.c')
-rw-r--r--src/nvim/memory.c388
1 files changed, 388 insertions, 0 deletions
diff --git a/src/nvim/memory.c b/src/nvim/memory.c
new file mode 100644
index 0000000000..53214d5265
--- /dev/null
+++ b/src/nvim/memory.c
@@ -0,0 +1,388 @@
+ // Various routines dealing with allocation and deallocation of memory.
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "vim.h"
+#include "misc2.h"
+#include "file_search.h"
+#include "blowfish.h"
+#include "buffer.h"
+#include "charset.h"
+#include "diff.h"
+#include "edit.h"
+#include "eval.h"
+#include "ex_cmds.h"
+#include "ex_docmd.h"
+#include "ex_getln.h"
+#include "fileio.h"
+#include "fold.h"
+#include "getchar.h"
+#include "mark.h"
+#include "mbyte.h"
+#include "memfile.h"
+#include "memline.h"
+#include "memory.h"
+#include "message.h"
+#include "misc1.h"
+#include "move.h"
+#include "option.h"
+#include "ops.h"
+#include "os_unix.h"
+#include "path.h"
+#include "quickfix.h"
+#include "regexp.h"
+#include "screen.h"
+#include "search.h"
+#include "spell.h"
+#include "syntax.h"
+#include "tag.h"
+#include "term.h"
+#include "ui.h"
+#include "window.h"
+#include "os/os.h"
+
+static void try_to_free_memory();
+
+/*
+ * Note: if unsigned is 16 bits we can only allocate up to 64K with alloc().
+ */
+char_u *alloc(unsigned size)
+{
+ return xmalloc(size);
+}
+
+/// Try to free memory. Used when trying to recover from out of memory errors.
+/// @see {xmalloc}
+static void try_to_free_memory()
+{
+ static bool trying_to_free = false;
+ // avoid recursive calls
+ if (trying_to_free)
+ return;
+ trying_to_free = true;
+
+ // free any scrollback text
+ clear_sb_text();
+ // Try to save all buffers and release as many blocks as possible
+ mf_release_all();
+ // cleanup recursive lists/dicts
+ garbage_collect();
+
+ trying_to_free = false;
+}
+
+void *try_malloc(size_t size)
+{
+ void *ret = malloc(size);
+
+ if (!ret && !size) {
+ ret = malloc(1);
+ }
+ if (!ret) {
+ try_to_free_memory();
+ ret = malloc(size);
+ if (!ret && !size) {
+ ret = malloc(1);
+ }
+ }
+ return ret;
+}
+
+void *verbose_try_malloc(size_t size)
+{
+ void *ret = try_malloc(size);
+ if (!ret) {
+ do_outofmem_msg((long_u)size);
+ }
+ return ret;
+}
+
+void *xmalloc(size_t size)
+{
+ void *ret = try_malloc(size);
+
+ if (!ret) {
+ OUT_STR("Vim: Error: Out of memory.\n");
+ preserve_exit();
+ }
+ return ret;
+}
+
+void *xcalloc(size_t count, size_t size)
+{
+ void *ret = calloc(count, size);
+
+ if (!ret && (!count || !size))
+ ret = calloc(1, 1);
+
+ if (!ret) {
+ try_to_free_memory();
+ ret = calloc(count, size);
+ if (!ret && (!count || !size))
+ ret = calloc(1, 1);
+ if (!ret) {
+ OUT_STR("Vim: Error: Out of memory.\n");
+ preserve_exit();
+ }
+ }
+
+ return ret;
+}
+
+void *xrealloc(void *ptr, size_t size)
+{
+ void *ret = realloc(ptr, size);
+
+ if (!ret && !size)
+ ret = realloc(ptr, 1);
+
+ if (!ret) {
+ try_to_free_memory();
+ ret = realloc(ptr, size);
+ if (!ret && !size)
+ ret = realloc(ptr, 1);
+ if (!ret) {
+ OUT_STR("Vim: Error: Out of memory.\n");
+ preserve_exit();
+ }
+ }
+
+ return ret;
+}
+
+void *xmallocz(size_t size)
+{
+ size_t total_size = size + 1;
+ void *ret;
+
+ if (total_size < size) {
+ OUT_STR("Vim: Data too large to fit into virtual memory space\n");
+ preserve_exit();
+ }
+
+ ret = xmalloc(total_size);
+ ((char*)ret)[size] = 0;
+
+ return ret;
+}
+
+void *xmemdupz(const void *data, size_t len)
+{
+ return memcpy(xmallocz(len), data, len);
+}
+
+char *xstpcpy(char *restrict dst, const char *restrict src)
+{
+ const size_t len = strlen(src);
+ return (char *)memcpy(dst, src, len + 1) + len;
+}
+
+char *xstpncpy(char *restrict dst, const char *restrict src, size_t maxlen)
+{
+ const char *p = memchr(src, '\0', maxlen);
+ if (p) {
+ size_t srclen = (size_t)(p - src);
+ memcpy(dst, src, srclen);
+ memset(dst + srclen, 0, maxlen - srclen);
+ return dst + srclen;
+ } else {
+ memcpy(dst, src, maxlen);
+ return dst + maxlen;
+ }
+}
+
+char * xstrdup(const char *str)
+{
+ char *ret = strdup(str);
+
+ if (!ret) {
+ try_to_free_memory();
+ ret = strdup(str);
+ if (!ret) {
+ OUT_STR("Vim: Error: Out of memory.\n");
+ preserve_exit();
+ }
+ }
+
+ return ret;
+}
+
+char *xstrndup(const char *str, size_t len)
+{
+ char *p = memchr(str, '\0', len);
+ return xmemdupz(str, p ? (size_t)(p - str) : len);
+}
+
+char *xmemdup(const char *data, size_t len)
+{
+ return memcpy(xmalloc(len), data, len);
+}
+
+/*
+ * Avoid repeating the error message many times (they take 1 second each).
+ * Did_outofmem_msg is reset when a character is read.
+ */
+void do_outofmem_msg(long_u size)
+{
+ if (!did_outofmem_msg) {
+ /* Don't hide this message */
+ emsg_silent = 0;
+
+ /* Must come first to avoid coming back here when printing the error
+ * message fails, e.g. when setting v:errmsg. */
+ did_outofmem_msg = TRUE;
+
+ EMSGU(_("E342: Out of memory! (allocating %" PRIu64 " bytes)"), size);
+ }
+}
+
+#if defined(EXITFREE) || defined(PROTO)
+
+/*
+ * Free everything that we allocated.
+ * Can be used to detect memory leaks, e.g., with ccmalloc.
+ * NOTE: This is tricky! Things are freed that functions depend on. Don't be
+ * surprised if Vim crashes...
+ * Some things can't be freed, esp. things local to a library function.
+ */
+void free_all_mem(void)
+{
+ buf_T *buf, *nextbuf;
+ static int entered = FALSE;
+
+ /* When we cause a crash here it is caught and Vim tries to exit cleanly.
+ * Don't try freeing everything again. */
+ if (entered)
+ return;
+ entered = TRUE;
+
+ block_autocmds(); /* don't want to trigger autocommands here */
+
+ /* Close all tabs and windows. Reset 'equalalways' to avoid redraws. */
+ p_ea = FALSE;
+ if (first_tabpage->tp_next != NULL)
+ do_cmdline_cmd((char_u *)"tabonly!");
+ if (firstwin != lastwin)
+ do_cmdline_cmd((char_u *)"only!");
+
+ /* Free all spell info. */
+ spell_free_all();
+
+ /* Clear user commands (before deleting buffers). */
+ ex_comclear(NULL);
+
+ /* Clear menus. */
+ do_cmdline_cmd((char_u *)"aunmenu *");
+ do_cmdline_cmd((char_u *)"menutranslate clear");
+
+ /* Clear mappings, abbreviations, breakpoints. */
+ do_cmdline_cmd((char_u *)"lmapclear");
+ do_cmdline_cmd((char_u *)"xmapclear");
+ do_cmdline_cmd((char_u *)"mapclear");
+ do_cmdline_cmd((char_u *)"mapclear!");
+ do_cmdline_cmd((char_u *)"abclear");
+ do_cmdline_cmd((char_u *)"breakdel *");
+ do_cmdline_cmd((char_u *)"profdel *");
+ do_cmdline_cmd((char_u *)"set keymap=");
+
+ free_titles();
+ free_findfile();
+
+ /* Obviously named calls. */
+ free_all_autocmds();
+ clear_termcodes();
+ free_all_options();
+ free_all_marks();
+ alist_clear(&global_alist);
+ free_homedir();
+ free_users();
+ free_search_patterns();
+ free_old_sub();
+ free_last_insert();
+ free_prev_shellcmd();
+ free_regexp_stuff();
+ free_tag_stuff();
+ free_cd_dir();
+ free_signs();
+ set_expr_line(NULL);
+ diff_clear(curtab);
+ clear_sb_text(); /* free any scrollback text */
+
+ /* Free some global vars. */
+ free(last_cmdline);
+ free(new_last_cmdline);
+ set_keep_msg(NULL, 0);
+
+ /* Clear cmdline history. */
+ p_hi = 0;
+ init_history();
+
+ {
+ win_T *win;
+ tabpage_T *tab;
+
+ qf_free_all(NULL);
+ /* Free all location lists */
+ FOR_ALL_TAB_WINDOWS(tab, win)
+ qf_free_all(win);
+ }
+
+ /* Close all script inputs. */
+ close_all_scripts();
+
+ /* Destroy all windows. Must come before freeing buffers. */
+ win_free_all();
+
+ /* Free all buffers. Reset 'autochdir' to avoid accessing things that
+ * were freed already. */
+ p_acd = FALSE;
+ for (buf = firstbuf; buf != NULL; ) {
+ nextbuf = buf->b_next;
+ close_buffer(NULL, buf, DOBUF_WIPE, FALSE);
+ if (buf_valid(buf))
+ buf = nextbuf; /* didn't work, try next one */
+ else
+ buf = firstbuf;
+ }
+
+ free_cmdline_buf();
+
+ /* Clear registers. */
+ clear_registers();
+ ResetRedobuff();
+ ResetRedobuff();
+
+
+ /* highlight info */
+ free_highlight();
+
+ reset_last_sourcing();
+
+ free_tabpage(first_tabpage);
+ first_tabpage = NULL;
+
+# ifdef UNIX
+ /* Machine-specific free. */
+ mch_free_mem();
+# endif
+
+ /* message history */
+ for (;; )
+ if (delete_first_msg() == FAIL)
+ break;
+
+ eval_clear();
+
+ free_termoptions();
+
+ /* screenlines (can't display anything now!) */
+ free_screenlines();
+
+ clear_hl_tables();
+
+ free(NameBuff);
+}
+
+#endif
+