aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/README.md57
-rw-r--r--src/nvim/api/vim.c46
-rw-r--r--src/nvim/eval.c3
3 files changed, 73 insertions, 33 deletions
diff --git a/src/nvim/README.md b/src/nvim/README.md
index da87a0208e..1ece92e44d 100644
--- a/src/nvim/README.md
+++ b/src/nvim/README.md
@@ -1,10 +1,22 @@
-Nvim core source
-================
+Nvim core
+=========
Module-specific details are documented at the top of each module (`terminal.c`,
-`screen.c`, ...).
+`screen.c`, …).
-See `:help development` for more guidelines.
+See `:help dev` for guidelines.
+
+Filename conventions
+--------------------
+
+The source files use extensions to hint about their purpose.
+
+- `*.c`, `*.generated.c` - full C files, with all includes, etc.
+- `*.c.h` - parametrized C files, contain all necessary includes, but require
+ defining macros before actually using. Example: `typval_encode.c.h`
+- `*.h` - full headers, with all includes. Does *not* apply to `*.generated.h`.
+- `*.h.generated.h` - exported functions’ declarations.
+- `*.c.generated.h` - static functions’ declarations.
Logs
----
@@ -20,17 +32,36 @@ UI events are logged at level 0 (`DEBUG_LOG_LEVEL`).
rm -rf build/
make CMAKE_EXTRA_FLAGS="-DMIN_LOG_LEVEL=0"
-Filename conventions
---------------------
+Build with ASAN
+---------------
-The source files use extensions to hint about their purpose.
+Building Nvim with Clang sanitizers (Address Sanitizer: ASan, Undefined
+Behavior Sanitizer: UBSan, Memory Sanitizer: MSan, Thread Sanitizer: TSan) is
+a good way to catch undefined behavior, leaks and other errors as soon as they
+happen. It's significantly faster than Valgrind.
-- `*.c`, `*.generated.c` - full C files, with all includes, etc.
-- `*.c.h` - parametrized C files, contain all necessary includes, but require
- defining macros before actually using. Example: `typval_encode.c.h`
-- `*.h` - full headers, with all includes. Does *not* apply to `*.generated.h`.
-- `*.h.generated.h` - exported functions’ declarations.
-- `*.c.generated.h` - static functions’ declarations.
+Requires clang 3.4 or later:
+
+ clang --version
+
+Build Nvim with sanitizer instrumentation:
+
+ CC=clang make CMAKE_EXTRA_FLAGS="-DCLANG_ASAN_UBSAN=ON"
+
+Create a directory to store logs:
+
+ mkdir -p "$HOME/logs"
+
+Enable the sanitizer(s) via these environment variables:
+
+ # Change to detect_leaks=1 to detect memory leaks (slower).
+ export ASAN_OPTIONS="detect_leaks=0:log_path=$HOME/logs/asan"
+ export ASAN_SYMBOLIZER_PATH=/usr/lib/llvm-5.0/bin/llvm-symbolizer
+
+ export MSAN_SYMBOLIZER_PATH=/usr/lib/llvm-5.0/bin/llvm-symbolizer
+ export TSAN_OPTIONS="external_symbolizer_path=/usr/lib/llvm-5.0/bin/llvm-symbolizer log_path=${HOME}/logs/tsan"
+
+Logs will be written to `${HOME}/logs/*san.PID`.
TUI debugging
-------------
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index 8929bc5b9b..0e7cc428d4 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -219,28 +219,38 @@ String nvim_replace_termcodes(String str, Boolean from_part, Boolean do_lt,
String nvim_command_output(String command, Error *err)
FUNC_API_SINCE(1)
{
- Array args = ARRAY_DICT_INIT;
- ADD(args, STRING_OBJ(copy_string(command)));
- ADD(args, STRING_OBJ(cstr_to_string("silent")));
- String fn = cstr_to_string("execute");
- Object rv = nvim_call_function(fn, args, err);
- api_free_string(fn);
- api_free_array(args);
+ const int save_msg_silent = msg_silent;
+ garray_T *const save_capture_ga = capture_ga;
+ garray_T capture_local;
+ ga_init(&capture_local, 1, 80);
+
+ try_start();
+ msg_silent++;
+ capture_ga = &capture_local;
+ do_cmdline_cmd(command.data);
+ capture_ga = save_capture_ga;
+ msg_silent = save_msg_silent;
+ try_end(err);
+
if (ERROR_SET(err)) {
- assert(rv.type == kObjectTypeNil);
- return (String)STRING_INIT;
+ goto theend;
}
- assert(rv.type == kObjectTypeString);
- // execute() always(?) prepends a newline; remove it.
- if (rv.data.string.size > 1) {
- assert(rv.data.string.data[0] == '\n');
- String *s = &rv.data.string;
- s->size--;
- memmove(s->data, s->data + 1, s->size);
- s->data[s->size] = '\0';
+ if (capture_local.ga_len > 1) {
+ // redir always(?) prepends a newline; remove it.
+ char *s = capture_local.ga_data;
+ assert(s[0] == '\n');
+ memmove(s, s + 1, (size_t)capture_local.ga_len);
+ s[capture_local.ga_len - 1] = '\0';
+ return (String) { // Caller will free the memory.
+ .data = s,
+ .size = (size_t)(capture_local.ga_len - 1),
+ };
}
- return rv.data.string;
+
+theend:
+ ga_clear(&capture_local);
+ return (String)STRING_INIT;
}
/// Evaluates a VimL expression (:help expression).
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 875f323a28..2e8bf18f2d 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -8116,8 +8116,7 @@ static void f_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr)
ga_append(capture_ga, NUL);
rettv->v_type = VAR_STRING;
- rettv->vval.v_string = vim_strsave(capture_ga->ga_data);
- ga_clear(capture_ga);
+ rettv->vval.v_string = capture_ga->ga_data;
capture_ga = save_capture_ga;
}