1// This is an open source non-commercial project. Dear PVS-Studio, please check
2// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
3
4 // Various routines dealing with allocation and deallocation of memory.
5
6#include <assert.h>
7#include <inttypes.h>
8#include <string.h>
9#include <stdbool.h>
10
11#include "nvim/vim.h"
12#include "nvim/context.h"
13#include "nvim/eval.h"
14#include "nvim/highlight.h"
15#include "nvim/memfile.h"
16#include "nvim/memory.h"
17#include "nvim/message.h"
18#include "nvim/misc1.h"
19#include "nvim/ui.h"
20#include "nvim/sign.h"
21#include "nvim/api/vim.h"
22
23#ifdef UNIT_TESTING
24# define malloc(size) mem_malloc(size)
25# define calloc(count, size) mem_calloc(count, size)
26# define realloc(ptr, size) mem_realloc(ptr, size)
27# define free(ptr) mem_free(ptr)
28MemMalloc mem_malloc = &malloc;
29MemFree mem_free = &free;
30MemCalloc mem_calloc = &calloc;
31MemRealloc mem_realloc = &realloc;
32#endif
33
34#ifdef INCLUDE_GENERATED_DECLARATIONS
35# include "memory.c.generated.h"
36#endif
37
38#ifdef EXITFREE
39bool entered_free_all_mem = false;
40#endif
41
42/// Try to free memory. Used when trying to recover from out of memory errors.
43/// @see {xmalloc}
44void try_to_free_memory(void)
45{
46 static bool trying_to_free = false;
47 // avoid recursive calls
48 if (trying_to_free)
49 return;
50 trying_to_free = true;
51
52 // free any scrollback text
53 clear_sb_text(true);
54 // Try to save all buffers and release as many blocks as possible
55 mf_release_all();
56
57 trying_to_free = false;
58}
59
60/// malloc() wrapper
61///
62/// try_malloc() is a malloc() wrapper that tries to free some memory before
63/// trying again.
64///
65/// @see {try_to_free_memory}
66/// @param size
67/// @return pointer to allocated space. NULL if out of memory
68void *try_malloc(size_t size) FUNC_ATTR_MALLOC FUNC_ATTR_ALLOC_SIZE(1)
69{
70 size_t allocated_size = size ? size : 1;
71 void *ret = malloc(allocated_size);
72 if (!ret) {
73 try_to_free_memory();
74 ret = malloc(allocated_size);
75 }
76 return ret;
77}
78
79/// try_malloc() wrapper that shows an out-of-memory error message to the user
80/// before returning NULL
81///
82/// @see {try_malloc}
83/// @param size
84/// @return pointer to allocated space. NULL if out of memory
85void *verbose_try_malloc(size_t size) FUNC_ATTR_MALLOC FUNC_ATTR_ALLOC_SIZE(1)
86{
87 void *ret = try_malloc(size);
88 if (!ret) {
89 do_outofmem_msg(size);
90 }
91 return ret;
92}
93
94/// malloc() wrapper that never returns NULL
95///
96/// xmalloc() succeeds or gracefully aborts when out of memory.
97/// Before aborting try to free some memory and call malloc again.
98///
99/// @see {try_to_free_memory}
100/// @param size
101/// @return pointer to allocated space. Never NULL
102void *xmalloc(size_t size)
103 FUNC_ATTR_MALLOC FUNC_ATTR_ALLOC_SIZE(1) FUNC_ATTR_NONNULL_RET
104{
105 void *ret = try_malloc(size);
106 if (!ret) {
107 mch_errmsg(e_outofmem);
108 mch_errmsg("\n");
109 preserve_exit();
110 }
111 return ret;
112}
113
114/// free() wrapper that delegates to the backing memory manager
115///
116/// @note Use XFREE_CLEAR() instead, if possible.
117void xfree(void *ptr)
118{
119 free(ptr);
120}
121
122/// calloc() wrapper
123///
124/// @see {xmalloc}
125/// @param count
126/// @param size
127/// @return pointer to allocated space. Never NULL
128void *xcalloc(size_t count, size_t size)
129 FUNC_ATTR_MALLOC FUNC_ATTR_ALLOC_SIZE_PROD(1, 2) FUNC_ATTR_NONNULL_RET
130{
131 size_t allocated_count = count && size ? count : 1;
132 size_t allocated_size = count && size ? size : 1;
133 void *ret = calloc(allocated_count, allocated_size);
134 if (!ret) {
135 try_to_free_memory();
136 ret = calloc(allocated_count, allocated_size);
137 if (!ret) {
138 mch_errmsg(e_outofmem);
139 mch_errmsg("\n");
140 preserve_exit();
141 }
142 }
143 return ret;
144}
145
146/// realloc() wrapper
147///
148/// @see {xmalloc}
149/// @param size
150/// @return pointer to reallocated space. Never NULL
151void *xrealloc(void *ptr, size_t size)
152 FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALLOC_SIZE(2) FUNC_ATTR_NONNULL_RET
153{
154 size_t allocated_size = size ? size : 1;
155 void *ret = realloc(ptr, allocated_size);
156 if (!ret) {
157 try_to_free_memory();
158 ret = realloc(ptr, allocated_size);
159 if (!ret) {
160 mch_errmsg(e_outofmem);
161 mch_errmsg("\n");
162 preserve_exit();
163 }
164 }
165 return ret;
166}
167
168/// xmalloc() wrapper that allocates size + 1 bytes and zeroes the last byte
169///
170/// @see {xmalloc}
171/// @param size
172/// @return pointer to allocated space. Never NULL
173void *xmallocz(size_t size)
174 FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT
175{
176 size_t total_size = size + 1;
177 if (total_size < size) {
178 mch_errmsg(_("Vim: Data too large to fit into virtual memory space\n"));
179 preserve_exit();
180 }
181
182 void *ret = xmalloc(total_size);
183 ((char*)ret)[size] = 0;
184
185 return ret;
186}
187
188/// Allocates (len + 1) bytes of memory, duplicates `len` bytes of
189/// `data` to the allocated memory, zero terminates the allocated memory,
190/// and returns a pointer to the allocated memory. If the allocation fails,
191/// the program dies.
192///
193/// @see {xmalloc}
194/// @param data Pointer to the data that will be copied
195/// @param len number of bytes that will be copied
196void *xmemdupz(const void *data, size_t len)
197 FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT
198 FUNC_ATTR_NONNULL_ALL
199{
200 return memcpy(xmallocz(len), data, len);
201}
202
203/// A version of strchr() that returns a pointer to the terminating NUL if it
204/// doesn't find `c`.
205///
206/// @param str The string to search.
207/// @param c The char to look for.
208/// @returns a pointer to the first instance of `c`, or to the NUL terminator
209/// if not found.
210char *xstrchrnul(const char *str, char c)
211 FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE
212{
213 char *p = strchr(str, c);
214 return p ? p : (char *)(str + strlen(str));
215}
216
217/// A version of memchr() that returns a pointer one past the end
218/// if it doesn't find `c`.
219///
220/// @param addr The address of the memory object.
221/// @param c The char to look for.
222/// @param size The size of the memory object.
223/// @returns a pointer to the first instance of `c`, or one past the end if not
224/// found.
225void *xmemscan(const void *addr, char c, size_t size)
226 FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE
227{
228 char *p = memchr(addr, c, size);
229 return p ? p : (char *)addr + size;
230}
231
232/// Replaces every instance of `c` with `x`.
233///
234/// @warning Will read past `str + strlen(str)` if `c == NUL`.
235///
236/// @param str A NUL-terminated string.
237/// @param c The unwanted byte.
238/// @param x The replacement.
239void strchrsub(char *str, char c, char x)
240 FUNC_ATTR_NONNULL_ALL
241{
242 assert(c != '\0');
243 while ((str = strchr(str, c))) {
244 *str++ = x;
245 }
246}
247
248/// Replaces every instance of `c` with `x`.
249///
250/// @param data An object in memory. May contain NULs.
251/// @param c The unwanted byte.
252/// @param x The replacement.
253/// @param len The length of data.
254void memchrsub(void *data, char c, char x, size_t len)
255 FUNC_ATTR_NONNULL_ALL
256{
257 char *p = data, *end = (char *)data + len;
258 while ((p = memchr(p, c, (size_t)(end - p)))) {
259 *p++ = x;
260 }
261}
262
263/// Counts the number of occurrences of `c` in `str`.
264///
265/// @warning Unsafe if `c == NUL`.
266///
267/// @param str Pointer to the string to search.
268/// @param c The byte to search for.
269/// @returns the number of occurrences of `c` in `str`.
270size_t strcnt(const char *str, char c)
271 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE
272{
273 assert(c != 0);
274 size_t cnt = 0;
275 while ((str = strchr(str, c))) {
276 cnt++;
277 str++; // Skip the instance of c.
278 }
279 return cnt;
280}
281
282/// Counts the number of occurrences of byte `c` in `data[len]`.
283///
284/// @param data Pointer to the data to search.
285/// @param c The byte to search for.
286/// @param len The length of `data`.
287/// @returns the number of occurrences of `c` in `data[len]`.
288size_t memcnt(const void *data, char c, size_t len)
289 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE
290{
291 size_t cnt = 0;
292 const char *ptr = data, *end = ptr + len;
293 while ((ptr = memchr(ptr, c, (size_t)(end - ptr))) != NULL) {
294 cnt++;
295 ptr++; // Skip the instance of c.
296 }
297 return cnt;
298}
299
300/// Copies the string pointed to by src (including the terminating NUL
301/// character) into the array pointed to by dst.
302///
303/// @returns pointer to the terminating NUL char copied into the dst buffer.
304/// This is the only difference with strcpy(), which returns dst.
305///
306/// WARNING: If copying takes place between objects that overlap, the behavior
307/// is undefined.
308///
309/// Nvim version of POSIX 2008 stpcpy(3). We do not require POSIX 2008, so
310/// implement our own version.
311///
312/// @param dst
313/// @param src
314char *xstpcpy(char *restrict dst, const char *restrict src)
315 FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
316{
317 const size_t len = strlen(src);
318 return (char *)memcpy(dst, src, len + 1) + len;
319}
320
321/// Copies not more than n bytes (bytes that follow a NUL character are not
322/// copied) from the array pointed to by src to the array pointed to by dst.
323///
324/// If a NUL character is written to the destination, xstpncpy() returns the
325/// address of the first such NUL character. Otherwise, it shall return
326/// &dst[maxlen].
327///
328/// WARNING: If copying takes place between objects that overlap, the behavior
329/// is undefined.
330///
331/// WARNING: xstpncpy will ALWAYS write maxlen bytes. If src is shorter than
332/// maxlen, zeroes will be written to the remaining bytes.
333///
334/// @param dst
335/// @param src
336/// @param maxlen
337char *xstpncpy(char *restrict dst, const char *restrict src, size_t maxlen)
338 FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
339{
340 const char *p = memchr(src, '\0', maxlen);
341 if (p) {
342 size_t srclen = (size_t)(p - src);
343 memcpy(dst, src, srclen);
344 memset(dst + srclen, 0, maxlen - srclen);
345 return dst + srclen;
346 } else {
347 memcpy(dst, src, maxlen);
348 return dst + maxlen;
349 }
350}
351
352/// xstrlcpy - Copy a NUL-terminated string into a sized buffer
353///
354/// Compatible with *BSD strlcpy: the result is always a valid NUL-terminated
355/// string that fits in the buffer (unless, of course, the buffer size is
356/// zero). It does not pad out the result like strncpy() does.
357///
358/// @param[out] dst Buffer to store the result.
359/// @param[in] src String to be copied.
360/// @param[in] dsize Size of `dst`.
361///
362/// @return Length of `src`. May be greater than `dsize - 1`, which would mean
363/// that string was truncated.
364size_t xstrlcpy(char *restrict dst, const char *restrict src, size_t dsize)
365 FUNC_ATTR_NONNULL_ALL
366{
367 size_t slen = strlen(src);
368
369 if (dsize) {
370 size_t len = MIN(slen, dsize - 1);
371 memcpy(dst, src, len);
372 dst[len] = '\0';
373 }
374
375 return slen; // Does not include NUL.
376}
377
378/// Appends `src` to string `dst` of size `dsize` (unlike strncat, dsize is the
379/// full size of `dst`, not space left). At most dsize-1 characters
380/// will be copied. Always NUL terminates. `src` and `dst` may overlap.
381///
382/// @see vim_strcat from Vim.
383/// @see strlcat from OpenBSD.
384///
385/// @param[in,out] dst Buffer to be appended-to. Must have a NUL byte.
386/// @param[in] src String to put at the end of `dst`.
387/// @param[in] dsize Size of `dst` including NUL byte. Must be greater than 0.
388///
389/// @return Length of the resulting string as if destination size was #SIZE_MAX.
390/// May be greater than `dsize - 1`, which would mean that string was
391/// truncated.
392size_t xstrlcat(char *const dst, const char *const src, const size_t dsize)
393 FUNC_ATTR_NONNULL_ALL
394{
395 assert(dsize > 0);
396 const size_t dlen = strlen(dst);
397 assert(dlen < dsize);
398 const size_t slen = strlen(src);
399
400 if (slen > dsize - dlen - 1) {
401 memmove(dst + dlen, src, dsize - dlen - 1);
402 dst[dsize - 1] = '\0';
403 } else {
404 memmove(dst + dlen, src, slen + 1);
405 }
406
407 return slen + dlen; // Does not include NUL.
408}
409
410/// strdup() wrapper
411///
412/// @see {xmalloc}
413/// @param str 0-terminated string that will be copied
414/// @return pointer to a copy of the string
415char *xstrdup(const char *str)
416 FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET
417 FUNC_ATTR_NONNULL_ALL
418{
419 return xmemdupz(str, strlen(str));
420}
421
422/// strdup() wrapper
423///
424/// Unlike xstrdup() allocates a new empty string if it receives NULL.
425char *xstrdupnul(const char *const str)
426 FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET
427{
428 if (str == NULL) {
429 return xmallocz(0);
430 } else {
431 return xstrdup(str);
432 }
433}
434
435/// A version of memchr that starts the search at `src + len`.
436///
437/// Based on glibc's memrchr.
438///
439/// @param src The source memory object.
440/// @param c The byte to search for.
441/// @param len The length of the memory object.
442/// @returns a pointer to the found byte in src[len], or NULL.
443void *xmemrchr(const void *src, uint8_t c, size_t len)
444 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE
445{
446 while (len--) {
447 if (((uint8_t *)src)[len] == c) {
448 return (uint8_t *) src + len;
449 }
450 }
451 return NULL;
452}
453
454/// strndup() wrapper
455///
456/// @see {xmalloc}
457/// @param str 0-terminated string that will be copied
458/// @return pointer to a copy of the string
459char *xstrndup(const char *str, size_t len)
460 FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET
461 FUNC_ATTR_NONNULL_ALL
462{
463 char *p = memchr(str, '\0', len);
464 return xmemdupz(str, p ? (size_t)(p - str) : len);
465}
466
467/// Duplicates a chunk of memory using xmalloc
468///
469/// @see {xmalloc}
470/// @param data pointer to the chunk
471/// @param len size of the chunk
472/// @return a pointer
473void *xmemdup(const void *data, size_t len)
474 FUNC_ATTR_MALLOC FUNC_ATTR_ALLOC_SIZE(2) FUNC_ATTR_NONNULL_RET
475 FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
476{
477 return memcpy(xmalloc(len), data, len);
478}
479
480/// Returns true if strings `a` and `b` are equal. Arguments may be NULL.
481bool strequal(const char *a, const char *b)
482 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
483{
484 return (a == NULL && b == NULL) || (a && b && strcmp(a, b) == 0);
485}
486
487/// Case-insensitive `strequal`.
488bool striequal(const char *a, const char *b)
489 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
490{
491 return (a == NULL && b == NULL) || (a && b && STRICMP(a, b) == 0);
492}
493
494/*
495 * Avoid repeating the error message many times (they take 1 second each).
496 * Did_outofmem_msg is reset when a character is read.
497 */
498void do_outofmem_msg(size_t size)
499{
500 if (!did_outofmem_msg) {
501 /* Don't hide this message */
502 emsg_silent = 0;
503
504 /* Must come first to avoid coming back here when printing the error
505 * message fails, e.g. when setting v:errmsg. */
506 did_outofmem_msg = true;
507
508 EMSGU(_("E342: Out of memory! (allocating %" PRIu64 " bytes)"), size);
509 }
510}
511
512/// Writes time_t to "buf[8]".
513void time_to_bytes(time_t time_, uint8_t buf[8])
514{
515 // time_t can be up to 8 bytes in size, more than uintmax_t in 32 bits
516 // systems, thus we can't use put_bytes() here.
517 for (size_t i = 7, bufi = 0; bufi < 8; i--, bufi++) {
518 buf[bufi] = (uint8_t)((uint64_t)time_ >> (i * 8));
519 }
520}
521
522#if defined(EXITFREE)
523
524#include "nvim/file_search.h"
525#include "nvim/buffer.h"
526#include "nvim/charset.h"
527#include "nvim/diff.h"
528#include "nvim/edit.h"
529#include "nvim/ex_cmds.h"
530#include "nvim/ex_docmd.h"
531#include "nvim/ex_getln.h"
532#include "nvim/fileio.h"
533#include "nvim/fold.h"
534#include "nvim/getchar.h"
535#include "nvim/mark.h"
536#include "nvim/mbyte.h"
537#include "nvim/memline.h"
538#include "nvim/move.h"
539#include "nvim/option.h"
540#include "nvim/ops.h"
541#include "nvim/os_unix.h"
542#include "nvim/path.h"
543#include "nvim/quickfix.h"
544#include "nvim/regexp.h"
545#include "nvim/screen.h"
546#include "nvim/search.h"
547#include "nvim/spell.h"
548#include "nvim/syntax.h"
549#include "nvim/tag.h"
550#include "nvim/window.h"
551#include "nvim/os/os.h"
552#include "nvim/eval/typval.h"
553
554/*
555 * Free everything that we allocated.
556 * Can be used to detect memory leaks, e.g., with ccmalloc.
557 * NOTE: This is tricky! Things are freed that functions depend on. Don't be
558 * surprised if Vim crashes...
559 * Some things can't be freed, esp. things local to a library function.
560 */
561void free_all_mem(void)
562{
563 buf_T *buf, *nextbuf;
564
565 // When we cause a crash here it is caught and Vim tries to exit cleanly.
566 // Don't try freeing everything again.
567 if (entered_free_all_mem) {
568 return;
569 }
570 entered_free_all_mem = true;
571
572 // Don't want to trigger autocommands from here on.
573 block_autocmds();
574
575 /* Close all tabs and windows. Reset 'equalalways' to avoid redraws. */
576 p_ea = false;
577 if (first_tabpage->tp_next != NULL)
578 do_cmdline_cmd("tabonly!");
579
580 if (!ONE_WINDOW) {
581 // to keep things simple, don't perform this
582 // ritual inside a float
583 curwin = firstwin;
584 do_cmdline_cmd("only!");
585 }
586
587 /* Free all spell info. */
588 spell_free_all();
589
590 /* Clear user commands (before deleting buffers). */
591 ex_comclear(NULL);
592
593 /* Clear menus. */
594 do_cmdline_cmd("aunmenu *");
595 do_cmdline_cmd("menutranslate clear");
596
597 /* Clear mappings, abbreviations, breakpoints. */
598 do_cmdline_cmd("lmapclear");
599 do_cmdline_cmd("xmapclear");
600 do_cmdline_cmd("mapclear");
601 do_cmdline_cmd("mapclear!");
602 do_cmdline_cmd("abclear");
603 do_cmdline_cmd("breakdel *");
604 do_cmdline_cmd("profdel *");
605 do_cmdline_cmd("set keymap=");
606
607 free_titles();
608 free_findfile();
609
610 /* Obviously named calls. */
611 free_all_autocmds();
612 free_all_marks();
613 alist_clear(&global_alist);
614 free_homedir();
615 free_users();
616 free_search_patterns();
617 free_old_sub();
618 free_last_insert();
619 free_prev_shellcmd();
620 free_regexp_stuff();
621 free_tag_stuff();
622 free_cd_dir();
623 free_signs();
624 set_expr_line(NULL);
625 diff_clear(curtab);
626 clear_sb_text(true); // free any scrollback text
627
628 /* Free some global vars. */
629 xfree(last_cmdline);
630 xfree(new_last_cmdline);
631 set_keep_msg(NULL, 0);
632
633 /* Clear cmdline history. */
634 p_hi = 0;
635 init_history();
636
637 qf_free_all(NULL);
638 /* Free all location lists */
639 FOR_ALL_TAB_WINDOWS(tab, win) {
640 qf_free_all(win);
641 }
642
643 /* Close all script inputs. */
644 close_all_scripts();
645
646 /* Destroy all windows. Must come before freeing buffers. */
647 win_free_all();
648
649 // Free all option values. Must come after closing windows.
650 free_all_options();
651
652 free_arshape_buf();
653
654 /* Clear registers. */
655 clear_registers();
656 ResetRedobuff();
657 ResetRedobuff();
658
659
660 /* highlight info */
661 free_highlight();
662
663 reset_last_sourcing();
664
665 free_tabpage(first_tabpage);
666 first_tabpage = NULL;
667
668 /* message history */
669 for (;; )
670 if (delete_first_msg() == FAIL)
671 break;
672
673 eval_clear();
674 api_vim_free_all_mem();
675 ctx_free_all();
676
677 // Free all buffers. Reset 'autochdir' to avoid accessing things that
678 // were freed already.
679 // Must be after eval_clear to avoid it trying to access b:changedtick after
680 // freeing it.
681 p_acd = false;
682 for (buf = firstbuf; buf != NULL; ) {
683 bufref_T bufref;
684 set_bufref(&bufref, buf);
685 nextbuf = buf->b_next;
686 close_buffer(NULL, buf, DOBUF_WIPE, false);
687 // Didn't work, try next one.
688 buf = bufref_valid(&bufref) ? nextbuf : firstbuf;
689 }
690
691 // free screenlines (can't display anything now!)
692 screen_free_all_mem();
693
694 clear_hl_tables(false);
695 list_free_log();
696}
697
698#endif
699
700