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.c149
1 files changed, 106 insertions, 43 deletions
diff --git a/src/nvim/memory.c b/src/nvim/memory.c
index 8db47b79c1..25fa2f150e 100644
--- a/src/nvim/memory.c
+++ b/src/nvim/memory.c
@@ -17,16 +17,41 @@
// Force je_ prefix on jemalloc functions.
# define JEMALLOC_NO_DEMANGLE
# include <jemalloc/jemalloc.h>
-# define malloc(size) je_malloc(size)
-# define calloc(count, size) je_calloc(count, size)
-# define realloc(ptr, size) je_realloc(ptr, size)
-# define free(ptr) je_free(ptr)
+#endif
+
+#ifdef UNIT_TESTING
+# define malloc(size) mem_malloc(size)
+# define calloc(count, size) mem_calloc(count, size)
+# define realloc(ptr, size) mem_realloc(ptr, size)
+# define free(ptr) mem_free(ptr)
+# ifdef HAVE_JEMALLOC
+MemMalloc mem_malloc = &je_malloc;
+MemFree mem_free = &je_free;
+MemCalloc mem_calloc = &je_calloc;
+MemRealloc mem_realloc = &je_realloc;
+# else
+MemMalloc mem_malloc = &malloc;
+MemFree mem_free = &free;
+MemCalloc mem_calloc = &calloc;
+MemRealloc mem_realloc = &realloc;
+# endif
+#else
+# ifdef HAVE_JEMALLOC
+# define malloc(size) je_malloc(size)
+# define calloc(count, size) je_calloc(count, size)
+# define realloc(ptr, size) je_realloc(ptr, size)
+# define free(ptr) je_free(ptr)
+# endif
#endif
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "memory.c.generated.h"
#endif
+#ifdef EXITFREE
+bool entered_free_all_mem = false;
+#endif
+
/// Try to free memory. Used when trying to recover from out of memory errors.
/// @see {xmalloc}
void try_to_free_memory(void)
@@ -283,18 +308,16 @@ size_t memcnt(const void *data, char c, size_t len)
return cnt;
}
-/// The xstpcpy() function shall copy the string pointed to by src (including
-/// the terminating NUL character) into the array pointed to by dst.
+/// Copies the string pointed to by src (including the terminating NUL
+/// character) into the array pointed to by dst.
///
-/// The xstpcpy() function shall return a pointer to the terminating NUL
-/// character copied into the dst buffer. This is the only difference with
-/// strcpy(), which returns dst.
+/// @returns pointer to the terminating NUL char copied into the dst buffer.
+/// This is the only difference with strcpy(), which returns dst.
///
-/// WARNING: If copying takes place between objects that overlap, the behavior is
-/// undefined.
+/// WARNING: If copying takes place between objects that overlap, the behavior
+/// is undefined.
///
-/// This is the Neovim version of stpcpy(3) as defined in POSIX 2008. We
-/// don't require that supported platforms implement POSIX 2008, so we
+/// Nvim version of POSIX 2008 stpcpy(3). We do not require POSIX 2008, so
/// implement our own version.
///
/// @param dst
@@ -306,16 +329,15 @@ char *xstpcpy(char *restrict dst, const char *restrict src)
return (char *)memcpy(dst, src, len + 1) + len;
}
-/// The xstpncpy() function shall copy not more than n bytes (bytes that follow
-/// a NUL character are not copied) from the array pointed to by src to the
-/// array pointed to by dst.
+/// Copies not more than n bytes (bytes that follow a NUL character are not
+/// copied) from the array pointed to by src to the array pointed to by dst.
///
-/// If a NUL character is written to the destination, the xstpncpy() function
-/// shall return the address of the first such NUL character. Otherwise, it
-/// shall return &dst[maxlen].
+/// If a NUL character is written to the destination, xstpncpy() returns the
+/// address of the first such NUL character. Otherwise, it shall return
+/// &dst[maxlen].
///
-/// WARNING: If copying takes place between objects that overlap, the behavior is
-/// undefined.
+/// WARNING: If copying takes place between objects that overlap, the behavior
+/// is undefined.
///
/// WARNING: xstpncpy will ALWAYS write maxlen bytes. If src is shorter than
/// maxlen, zeroes will be written to the remaining bytes.
@@ -342,29 +364,58 @@ char *xstpncpy(char *restrict dst, const char *restrict src, size_t maxlen)
}
}
-/// xstrlcpy - Copy a %NUL terminated string into a sized buffer
+/// xstrlcpy - Copy a NUL-terminated string into a sized buffer
///
-/// Compatible with *BSD strlcpy: the result is always a valid
-/// NUL-terminated string that fits in the buffer (unless,
-/// of course, the buffer size is zero). It does not pad
-/// out the result like strncpy() does.
+/// Compatible with *BSD strlcpy: the result is always a valid NUL-terminated
+/// string that fits in the buffer (unless, of course, the buffer size is
+/// zero). It does not pad out the result like strncpy() does.
///
-/// @param dst Where to copy the string to
-/// @param src Where to copy the string from
-/// @param size Size of destination buffer
-/// @return Length of the source string (i.e.: strlen(src))
-size_t xstrlcpy(char *restrict dst, const char *restrict src, size_t size)
+/// @param dst Buffer to store the result
+/// @param src String to be copied
+/// @param dsize Size of `dst`
+/// @return strlen(src). If retval >= dstsize, truncation occurs.
+size_t xstrlcpy(char *restrict dst, const char *restrict src, size_t dsize)
FUNC_ATTR_NONNULL_ALL
{
- size_t ret = strlen(src);
+ size_t slen = strlen(src);
- if (size) {
- size_t len = (ret >= size) ? size - 1 : ret;
- memcpy(dst, src, len);
- dst[len] = '\0';
- }
+ if (dsize) {
+ size_t len = MIN(slen, dsize - 1);
+ memcpy(dst, src, len);
+ dst[len] = '\0';
+ }
- return ret;
+ return slen; // Does not include NUL.
+}
+
+/// Appends `src` to string `dst` of size `dsize` (unlike strncat, dsize is the
+/// full size of `dst`, not space left). At most dsize-1 characters
+/// will be copied. Always NUL terminates. `src` and `dst` may overlap.
+///
+/// @see vim_strcat from Vim.
+/// @see strlcat from OpenBSD.
+///
+/// @param dst Buffer to be appended-to. Must have a NUL byte.
+/// @param src String to put at the end of `dst`
+/// @param dsize Size of `dst` including NUL byte. Must be greater than 0.
+/// @return strlen(src) + strlen(initial dst)
+/// If retval >= dsize, truncation occurs.
+size_t xstrlcat(char *const dst, const char *const src, const size_t dsize)
+ FUNC_ATTR_NONNULL_ALL
+{
+ assert(dsize > 0);
+ const size_t dlen = strlen(dst);
+ assert(dlen < dsize);
+ const size_t slen = strlen(src);
+
+ if (slen > dsize - dlen - 1) {
+ memmove(dst + dlen, src, dsize - dlen - 1);
+ dst[dsize - 1] = '\0';
+ } else {
+ memmove(dst + dlen, src, slen + 1);
+ }
+
+ return slen + dlen; // Does not include NUL.
}
/// strdup() wrapper
@@ -374,6 +425,7 @@ size_t xstrlcpy(char *restrict dst, const char *restrict src, size_t size)
/// @return pointer to a copy of the string
char *xstrdup(const char *str)
FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET
+ FUNC_ATTR_NONNULL_ALL
{
return xmemdupz(str, strlen(str));
}
@@ -404,6 +456,7 @@ void *xmemrchr(const void *src, uint8_t c, size_t len)
/// @return pointer to a copy of the string
char *xstrndup(const char *str, size_t len)
FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET
+ FUNC_ATTR_NONNULL_ALL
{
char *p = memchr(str, '\0', len);
return xmemdupz(str, p ? (size_t)(p - str) : len);
@@ -440,6 +493,16 @@ void do_outofmem_msg(size_t size)
}
}
+/// Writes time_t to "buf[8]".
+void time_to_bytes(time_t time_, uint8_t buf[8])
+{
+ // time_t can be up to 8 bytes in size, more than uintmax_t in 32 bits
+ // systems, thus we can't use put_bytes() here.
+ for (size_t i = 7, bufi = 0; bufi < 8; i--, bufi++) {
+ buf[bufi] = (uint8_t)((uint64_t)time_ >> (i * 8));
+ }
+}
+
#if defined(EXITFREE)
#include "nvim/file_search.h"
@@ -481,13 +544,13 @@ void do_outofmem_msg(size_t size)
void free_all_mem(void)
{
buf_T *buf, *nextbuf;
- static bool 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)
+ // When we cause a crash here it is caught and Vim tries to exit cleanly.
+ // Don't try freeing everything again.
+ if (entered_free_all_mem) {
return;
- entered = true;
+ }
+ entered_free_all_mem = true;
// Don't want to trigger autocommands from here on.
block_autocmds();