Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 26 additions & 20 deletions arith.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* Yash: yet another shell */
/* arith.c: arithmetic expansion */
/* (C) 2007-2025 magicant */
/* (C) 2007-2026 magicant */

/* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -287,10 +287,10 @@ bool do_assignment(const word_T *word, const value_T *value)
if (vstr == NULL)
return false;

wchar_t name[word->length + 1];
wmemcpy(name, word->contents, word->length);
name[word->length] = L'\0';
return set_variable(name, vstr, SCOPE_GLOBAL, false);
wchar_t *name = xwcsndup(word->contents, word->length);
bool ok = set_variable(name, vstr, SCOPE_GLOBAL, false);
free(name);
return ok;
}

/* Converts `value' to a newly-malloced wide string.
Expand All @@ -306,16 +306,21 @@ wchar_t *value_to_string(const value_T *value)
return malloc_wprintf(L"%.*g", DBL_DIG, value->v_double);
case VT_VAR:
{
wchar_t name[value->v_var.length + 1];
wmemcpy(name, value->v_var.contents, value->v_var.length);
name[value->v_var.length] = L'\0';
wchar_t *name = xwcsndup(
value->v_var.contents, value->v_var.length);
const wchar_t *var = getvar(name);
if (var != NULL)
return xwcsdup(var);
if (shopt_unset)
return malloc_wprintf(L"%ld", 0L);
xerror(0, Ngt("arithmetic: parameter `%ls' is not set"), name);
return NULL;
wchar_t *result;
if (var != NULL) {
result = xwcsdup(var);
} else if (shopt_unset) {
result = malloc_wprintf(L"%ld", 0L);
} else {
xerror(0, Ngt("arithmetic: parameter `%ls' is not set"),
name);
result = NULL;
}
free(name);
return result;
}
}
UNREACHABLE();
Expand Down Expand Up @@ -1097,14 +1102,13 @@ void parse_primary(evalinfo_T *info, value_T *result)
void parse_as_number(evalinfo_T *info, value_T *result)
{
word_T *word = &info->atoken.word;
wchar_t wordstr[word->length + 1];
wcsncpy(wordstr, word->contents, word->length);
wordstr[word->length] = L'\0';
wchar_t *wordstr = xwcsndup(word->contents, word->length);

long longresult;
if (xwcstol(wordstr, 0, &longresult)) {
result->type = VT_LONG;
result->v_long = longresult;
free(wordstr);
return;
}
if (!posixly_correct) {
Expand All @@ -1118,10 +1122,12 @@ void parse_as_number(evalinfo_T *info, value_T *result)
if (ok) {
result->type = VT_DOUBLE;
result->v_double = doubleresult;
free(wordstr);
return;
}
}
xerror(0, Ngt("arithmetic: `%ls' is not a valid number"), wordstr);
free(wordstr);
info->error = true;
result->type = VT_INVALID;
}
Expand All @@ -1137,17 +1143,17 @@ void coerce_number(evalinfo_T *info, value_T *value)
const wchar_t *varvalue;
{
word_T *name = &value->v_var;
wchar_t namestr[name->length + 1];
wmemcpy(namestr, name->contents, name->length);
namestr[name->length] = L'\0';
wchar_t *namestr = xwcsndup(name->contents, name->length);
varvalue = getvar(namestr);

if (varvalue == NULL && !shopt_unset) {
xerror(0, Ngt("arithmetic: parameter `%ls' is not set"), namestr);
free(namestr);
info->error = true;
value->type = VT_INVALID;
return;
}
free(namestr);
}
if (varvalue == NULL || varvalue[0] == L'\0') {
value->type = VT_LONG;
Expand Down
2 changes: 1 addition & 1 deletion configure
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ confighdefs=''
# define options for debugging
if ${debug}
then
cflags="${CFLAGS--pedantic -MMD -Wall -Wextra -Og -fno-inline -ggdb}"
cflags="${CFLAGS--pedantic -MMD -Wall -Wextra -Wvla -Og -fno-inline -ggdb}"
else
defconfigh "NDEBUG"
fi
Expand Down
8 changes: 5 additions & 3 deletions exec.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* Yash: yet another shell */
/* exec.c: command execution */
/* (C) 2007-2025 magicant */
/* (C) 2007-2026 magicant */

/* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -1118,7 +1118,7 @@ wchar_t **invoke_simple_command(
void exec_external_program(
const char *path, int argc, char *argv0, void **argv, char **envs)
{
char *mbsargv[argc + 1];
char **mbsargv = xmalloce(argc, 1, sizeof *mbsargv);
mbsargv[0] = argv0;
for (int i = 1; i < argc; i++) {
mbsargv[i] = malloc_wcstombs(argv[i]);
Expand Down Expand Up @@ -1148,6 +1148,7 @@ void exec_external_program(

for (int i = 1; i < argc; i++)
free(mbsargv[i]);
free(mbsargv);
}

/* Calls `execve' until it doesn't return EINTR. */
Expand All @@ -1167,7 +1168,7 @@ void exec_fall_back_on_sh(
{
assert(argv[argc] == NULL);

char *args[argc + 3];
char **args = xmalloce(argc, 3, sizeof *args);
size_t index = 0;
args[index++] = "sh";
args[index++] = (char *) "-";
Expand Down Expand Up @@ -1195,6 +1196,7 @@ void exec_fall_back_on_sh(
xexecve(shpath, args, envp);
else
errno = ENOENT;
free(args);
xerror(errno, Ngt("cannot invoke a new shell to execute script `%s'"),
argv[0]);
}
Expand Down
13 changes: 5 additions & 8 deletions lineedit/complete.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* Yash: yet another shell */
/* complete.c: command line completion */
/* (C) 2007-2025 magicant */
/* (C) 2007-2026 magicant */

/* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -1157,10 +1157,9 @@ size_t get_common_prefix_length(void)
common_prefix_length = cpl;

if (le_state_is_compdebug) {
wchar_t value[common_prefix_length + 1];
wmemcpy(value, cand->origvalue, common_prefix_length);
value[common_prefix_length] = L'\0';
wchar_t *value = xwcsndup(cand->origvalue, common_prefix_length);
le_compdebug("candidate common prefix: \"%ls\"", value);
free(value);
}

return common_prefix_length;
Expand Down Expand Up @@ -1217,11 +1216,9 @@ void update_main_buffer(bool subst, bool finish)
assert(srclen <= cpl);
cand = le_candidates.contents[0];

size_t valuelen = cpl - srclen;
wchar_t value[valuelen + 1];
wcsncpy(value, cand->origvalue + srclen, valuelen);
value[valuelen] = L'\0';
wchar_t *value = xwcsndup(cand->origvalue + srclen, cpl - srclen);
quote(&quoted, value, quotetype);
free(value);
} else {
// Quote the selected candidate.
cand = le_candidates.contents[le_selected_candidate_index];
Expand Down
9 changes: 5 additions & 4 deletions lineedit/editing.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* Yash: yet another shell */
/* editing.c: main editing module */
/* (C) 2007-2025 magicant */
/* (C) 2007-2026 magicant */

/* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -3247,13 +3247,14 @@ void cmd_emacs_delete_horizontal_space(wchar_t c __attribute__((unused)))
* If the count is specified, blanks are replaced with `count' spaces. */
void cmd_emacs_just_one_space(wchar_t c __attribute__((unused)))
{
#define MAX_SPACE_COUNT 1000 /* The count is limited to avoid overflow. */
int count = get_count(1);
if (count < 0)
count = 0;
else if (count > 1000)
count = 1000;
else if (count > MAX_SPACE_COUNT)
count = MAX_SPACE_COUNT;

wchar_t s[count + 1];
wchar_t s[MAX_SPACE_COUNT + 1];
wmemset(s, L' ', count);
s[count] = L'\0';

Expand Down
19 changes: 7 additions & 12 deletions parser.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* Yash: yet another shell */
/* parser.c: syntax parser */
/* (C) 2007-2025 magicant */
/* (C) 2007-2026 magicant */

/* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -883,10 +883,9 @@ void print_errmsg_token(parsestate_T *ps, const char *message)
assert(ps->index <= ps->next_index);
assert(ps->next_index <= ps->src.length);
size_t length = ps->next_index - ps->index;
wchar_t token[length + 1];
wcsncpy(token, &ps->src.contents[ps->index], length);
token[length] = L'\0';
wchar_t *token = xwcsndup(&ps->src.contents[ps->index], length);
serror(ps, message, token);
free(token);
}

const char *get_errmsg_unexpected_tokentype(tokentype_T tokentype)
Expand Down Expand Up @@ -4087,13 +4086,8 @@ void print_embedded_command(struct print *pr, embedcmd_T ec, unsigned indent)
return;
}

size_t save_count = pr->pending_heredocs.length;
size_t extended_count = save_count;
if (extended_count == 0)
extended_count = 1; // A variable-length array must not be empty.
void *save_heredocs[extended_count];
memcpy(save_heredocs, pr->pending_heredocs.contents, sizeof save_heredocs);
pl_truncate(&pr->pending_heredocs, 0);
plist_T save_heredocs = pr->pending_heredocs;
pl_init(&pr->pending_heredocs);

print_and_or_lists(pr, ec.value.preparsed, indent, true);

Expand All @@ -4107,7 +4101,8 @@ void print_embedded_command(struct print *pr, embedcmd_T ec, unsigned indent)
}

assert(pr->pending_heredocs.length == 0);
pl_ncat(&pr->pending_heredocs, save_heredocs, save_count);
pl_destroy(&pr->pending_heredocs);
pr->pending_heredocs = save_heredocs;
}

void print_indent(struct print *pr, unsigned indent)
Expand Down
44 changes: 27 additions & 17 deletions path.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* Yash: yet another shell */
/* path.c: filename-related utilities */
/* (C) 2007-2025 magicant */
/* (C) 2007-2026 magicant */

/* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -160,13 +160,17 @@ bool check_access(const char *path, mode_t mode, int amode)

int gcount = getgroups(0, &gid); /* the second argument is a dummy */
if (gcount > 0) {
gid_t groups[gcount];
gid_t *groups = xmallocn(gcount, sizeof *groups);
gcount = getgroups(gcount, groups);
if (gcount > 0) {
for (int i = 0; i < gcount; i++)
if (gid == groups[i])
for (int i = 0; i < gcount; i++) {
if (gid == groups[i]) {
free(groups);
return st.st_mode & S_IRWXG;
}
}
}
free(groups);
}

return st.st_mode & S_IRWXO;
Expand Down Expand Up @@ -283,22 +287,25 @@ char *which(
return NULL;

size_t namelen = strlen(name);
xstrbuf_T path;
sb_init(&path);
for (const char *dir; (dir = *dirs) != NULL; dirs++) {
size_t dirlen = strlen(dir);
char path[dirlen + namelen + 3];
sb_clear(&path);
if (dirlen > 0) {
/* concatenate `dir' and `name' to produce a pathname `path' */
strcpy(path, dir);
if (path[dirlen - 1] != '/')
path[dirlen++] = '/';
strcpy(path + dirlen, name);
sb_ncat_force(&path, dir, dirlen);
if (path.contents[dirlen - 1] != '/')
sb_ccat(&path, '/');
sb_ncat_force(&path, name, namelen);
} else {
/* if `dir' is empty, it's considered to be the current directory */
strcpy(path, name);
sb_ncat_force(&path, name, namelen);
}
if (cond(path))
return xstrdup(path);
if (cond(path.contents))
return sb_tostr(&path);
}
sb_destroy(&path);
return NULL;
}

Expand Down Expand Up @@ -717,16 +724,18 @@ plist_T wglob_parse_pattern(const wchar_t *pattern, enum wglobflags_T flags)
plist_T components;
pl_init(&components);

xwcsbuf_T component;
wb_init(&component);

for (;;) {
const wchar_t *slash = wcschr(pattern, L'/');
size_t componentlength =
(slash != NULL) ? (size_t) (slash - pattern) : wcslen(pattern);
wchar_t component[componentlength + 1];
wcsncpy(component, pattern, componentlength);
component[componentlength] = L'\0';
wb_clear(&component);
wb_ncat(&component, pattern, componentlength);

struct wglob_pattern *c =
wglob_parse_component(component, flags, slash != NULL);
struct wglob_pattern *c = wglob_parse_component(
component.contents, flags, slash != NULL);
if (c == NULL) {
pl_clear(&components, wglob_free_pattern_vp);
break;
Expand All @@ -738,6 +747,7 @@ plist_T wglob_parse_pattern(const wchar_t *pattern, enum wglobflags_T flags)
pattern = &slash[1];
}

wb_destroy(&component);
return components;
}

Expand Down
9 changes: 4 additions & 5 deletions variable.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* Yash: yet another shell */
/* variable.c: deals with shell variables and parameters */
/* (C) 2007-2025 magicant */
/* (C) 2007-2026 magicant */

/* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -2161,10 +2161,7 @@ void array_remove_elements(
const wchar_t *name, variable_T *array, size_t count,
void *const *indexwcss)
{
size_t extended_count = count;
if (extended_count == 0)
extended_count = 1; // A variable-length array must not be empty.
long indices[extended_count];
long *indices = xmallocn(count, sizeof *indices);

assert((array->v_type & VF_MASK) == VF_ARRAY);

Expand All @@ -2173,6 +2170,7 @@ void array_remove_elements(
const wchar_t *indexwcs = indexwcss[i];
if (!xwcstol(indexwcs, 10, &indices[i])) {
xerror(errno, Ngt("`%ls' is not a valid integer"), indexwcs);
free(indices);
return;
}

Expand Down Expand Up @@ -2210,6 +2208,7 @@ void array_remove_elements(
}
array->v_valc = newcount;
array->v_vals[newcount] = NULL;
free(indices);

if (newcount < oldcount) {
variable_set(name, array);
Expand Down
Loading
Loading