<pre style='margin:0'>
Joshua Root (jmroot) pushed a commit to branch master
in repository macports-base.
</pre>
<p><a href="https://github.com/macports/macports-base/commit/4eb0095fb006ff5fb9d1a6a471c2a022f73a1aa1">https://github.com/macports/macports-base/commit/4eb0095fb006ff5fb9d1a6a471c2a022f73a1aa1</a></p>
<pre style="white-space: pre; background: #F8F8F8">The following commit(s) were added to refs/heads/master by this push:
<span style='display:block; white-space:pre;color:#404040;'> new 4eb0095 Fix a crash due to an out-of-bounds array access
</span>4eb0095 is described below
<span style='display:block; white-space:pre;color:#808000;'>commit 4eb0095fb006ff5fb9d1a6a471c2a022f73a1aa1
</span>Author: Saagar Jha <saagar@saagarjha.com>
AuthorDate: Thu Feb 14 00:01:02 2019 -0800
<span style='display:block; white-space:pre;color:#404040;'> Fix a crash due to an out-of-bounds array access
</span><span style='display:block; white-space:pre;color:#404040;'>
</span><span style='display:block; white-space:pre;color:#404040;'> entry_search had a "type confusion" bug where it would perform array
</span><span style='display:block; white-space:pre;color:#404040;'> accesses that bypassed bounds checks if given arguments that looked like
</span><span style='display:block; white-space:pre;color:#404040;'> strategies. I've rewritten most of the argument parsing loop in a way
</span><span style='display:block; white-space:pre;color:#404040;'> that should eliminate this issue, while being shorter and more
</span><span style='display:block; white-space:pre;color:#404040;'> straightforward (with less duplicated code), only requiring one pass
</span><span style='display:block; white-space:pre;color:#404040;'> through the arguments. The downside is that we allocate a bit more
</span><span style='display:block; white-space:pre;color:#404040;'> memory and have a couple of gotos to handle errors.
</span>---
src/cregistry/entry.c | 4 +-
src/cregistry/entry.h | 4 +-
src/registry2.0/entry.c | 170 +++++++++++++++++-----------------------
src/registry2.0/tests/entry.tcl | 3 +
4 files changed, 80 insertions(+), 101 deletions(-)
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/cregistry/entry.c b/src/cregistry/entry.c
</span><span style='display:block; white-space:pre;color:#808080;'>index 74898c2..073e5ef 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/src/cregistry/entry.c
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/cregistry/entry.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -397,8 +397,8 @@ static int reg_all_entries(reg_registry* reg, char* query, int query_len,
</span> * @param [out] errPtr on error, a description of the error that occurred
* @return the number of entries if success; false if failure
*/
<span style='display:block; white-space:pre;background:#ffe0e0;'>-int reg_entry_search(reg_registry* reg, char** keys, char** vals, int key_count,
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- int *strategies, reg_entry*** entries, reg_error* errPtr) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int reg_entry_search(reg_registry* reg, const char** keys, const char** vals,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int key_count, int *strategies, reg_entry*** entries, reg_error* errPtr) {
</span> int i;
char* kwd = " WHERE ";
char* query;
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/cregistry/entry.h b/src/cregistry/entry.h
</span><span style='display:block; white-space:pre;color:#808080;'>index 756a774..0c37aba 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/src/cregistry/entry.h
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/cregistry/entry.h
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -52,8 +52,8 @@ int reg_entry_delete(reg_entry* entry, reg_error* errPtr);
</span>
void reg_entry_free(reg_entry* entry);
<span style='display:block; white-space:pre;background:#ffe0e0;'>-int reg_entry_search(reg_registry* reg, char** keys, char** vals, int key_count,
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- int* strategies, reg_entry*** entries, reg_error* errPtr);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int reg_entry_search(reg_registry* reg, const char** keys, const char** vals,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int key_count, int* strategies, reg_entry*** entries, reg_error* errPtr);
</span>
int reg_entry_imaged(reg_registry* reg, const char* name, const char* version,
const char* revision, const char* variants, reg_entry*** entries,
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/registry2.0/entry.c b/src/registry2.0/entry.c
</span><span style='display:block; white-space:pre;color:#808080;'>index abb6298..987b065 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/src/registry2.0/entry.c
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/registry2.0/entry.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -248,116 +248,92 @@ static strategy_type strategies[] = {
</span> * Can be given an option of -exact, -glob, -regexp or -null to specify the
* matching strategy; defaults to exact.
*/
<span style='display:block; white-space:pre;background:#ffe0e0;'>-static int entry_search(Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- int i, j;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- reg_registry* reg = registry_for(interp, reg_attached);
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- if (reg == NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int entry_search(Tcl_Interp* interp, int objc, Tcl_Obj* CONST *objv) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ reg_registry *reg = registry_for(interp, reg_attached);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!reg) {
</span> return TCL_ERROR;
<span style='display:block; white-space:pre;background:#ffe0e0;'>- } else {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- char** keys;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- char** vals;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- int* strats;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- int key_count = 0;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- reg_entry** entries;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- reg_error error;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- int entry_count;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- for (i = 2; i < objc;) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- int index, strat_index, val_length;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- if (Tcl_GetIndexFromObj(interp, objv[i], entry_props, "search key",
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- 0, &index) != TCL_OK) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- return TCL_ERROR;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- }
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- /* we ate the key value */
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- i++;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- /* check whether there's a strategy */
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- if (Tcl_GetString(objv[i])[0] == '-'
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- && Tcl_GetIndexFromObjStruct(interp, objv[i], strategies,
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- sizeof(strategy_type), "option", 0, &strat_index)
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- != TCL_ERROR) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- /* this key has a strategy specified, eat the strategy parameter */
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- i++;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- if (strategies[strat_index].strategy != reg_strategy_null) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- /* this key must also have a value */
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- if (Tcl_GetStringFromObj(objv[i], &val_length) == NULL) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- Tcl_WrongNumArgs(interp, 2, objv,
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- "search ?key ?options? value ...?");
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- return TCL_ERROR;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- }
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- i++;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- }
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- } else {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- /* this key must also have a value */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ const char **keys = malloc(objc * sizeof(char *));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ const char **vals = malloc(objc * sizeof(char *));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int *strats = malloc(objc * sizeof(int));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!keys || !vals || !strats) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ goto cleanup_error;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int key_count = 0;
</span>
<span style='display:block; white-space:pre;background:#ffe0e0;'>- if (Tcl_GetStringFromObj(objv[i], &val_length) == NULL) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- Tcl_WrongNumArgs(interp, 2, objv,
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- "search ?key ?options? value ...?");
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- return TCL_ERROR;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Skip the "registry::entry" "search" bit */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ objv += 2;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ objc -= 2;
</span>
<span style='display:block; white-space:pre;background:#ffe0e0;'>- i++;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ for (int i = 0; i < objc; ++key_count /* i in incremented in the loop */) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int key_index, strategy_index;
</span>
<span style='display:block; white-space:pre;background:#ffe0e0;'>- key_count++;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Grab the key */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (Tcl_GetIndexFromObj(interp, objv[i], entry_props, "search key",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 0, &key_index) != TCL_OK) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ goto cleanup_error;
</span> }
<span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- keys = malloc(key_count * sizeof(char*));
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- vals = malloc(key_count * sizeof(char*));
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- strats = malloc(key_count * sizeof(int));
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- if (!keys || !vals || !strats) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- return TCL_ERROR;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ keys[key_count] = entry_props[key_index];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (objc <= ++i) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ goto wrong_num_args; /* We're missing a strategy or value */
</span> }
<span style='display:block; white-space:pre;background:#ffe0e0;'>- for (i = 2, j = 0; i < objc && j < key_count; j++) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- int strat_index;
</span>
<span style='display:block; white-space:pre;background:#ffe0e0;'>- keys[j] = Tcl_GetString(objv[i++]);
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- /* try to get the strategy */
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- if (Tcl_GetString(objv[i])[0] == '-'
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- && Tcl_GetIndexFromObjStruct(interp, objv[i], strategies,
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- sizeof(strategy_type), "option", 0, &strat_index)
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- != TCL_ERROR) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- /* this key has a strategy specified */
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- i++;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- strats[j] = strategies[strat_index].strategy;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- } else {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- /* use default strategy */
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- strats[j] = reg_strategy_exact;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Set the default strategy, in case we don't find one */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ strats[key_count] = reg_strategy_exact;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Try to grab the strategy */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (Tcl_GetIndexFromObjStruct(interp, objv[i], strategies,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ sizeof(strategy_type), "option", 0, &strategy_index) !=
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ TCL_ERROR) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ strats[key_count] = strategies[strategy_index].strategy;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (objc <= ++i && strats[key_count] != reg_strategy_null) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ goto wrong_num_args;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else if (strats[key_count] == reg_strategy_null) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* This doesn't take a value, so start from the top */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ continue;
</span> }
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span>
<span style='display:block; white-space:pre;background:#ffe0e0;'>- if (strats[j] != reg_strategy_null) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- vals[j] = Tcl_GetString(objv[i++]);
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- } else {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- vals[j] = NULL;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Grab the value */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!(vals[key_count] = Tcl_GetString(objv[i++]))) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ goto wrong_num_args; /* We're missing a value */
</span> }
<span style='display:block; white-space:pre;background:#ffe0e0;'>- entry_count = reg_entry_search(reg, keys, vals, key_count,
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- strats, &entries, &error);
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- free(keys);
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- free(vals);
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- free(strats);
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- if (entry_count >= 0) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- int retval;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- Tcl_Obj* resultObj;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- Tcl_Obj** objs;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- if (list_entry_to_obj(interp, &objs, entries, entry_count, &error)){
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- resultObj = Tcl_NewListObj(entry_count, objs);
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- Tcl_SetObjResult(interp, resultObj);
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- free(objs);
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- retval = TCL_OK;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- } else {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- retval = registry_failed(interp, &error);
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- }
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- free(entries);
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- return retval;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ reg_entry **entries;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ reg_error error;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int entry_count;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ entry_count = reg_entry_search(reg, keys, vals, key_count, strats, &entries,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ &error);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ free(keys);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ free(vals);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ free(strats);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (entry_count >= 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int retval;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_Obj* resultObj;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_Obj** objs;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (list_entry_to_obj(interp, &objs, entries, entry_count, &error)){
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ resultObj = Tcl_NewListObj(entry_count, objs);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_SetObjResult(interp, resultObj);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ free(objs);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ retval = TCL_OK;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ retval = registry_failed(interp, &error);
</span> }
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ free(entries);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return retval;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else {
</span> return registry_failed(interp, &error);
}
<span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+wrong_num_args:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Tcl_WrongNumArgs(interp, 2, objv,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ "search ?key ?options? value ...?");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+cleanup_error:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ free(keys);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ free(vals);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ free(strats);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return TCL_ERROR;
</span> }
/*
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/registry2.0/tests/entry.tcl b/src/registry2.0/tests/entry.tcl
</span><span style='display:block; white-space:pre;color:#808080;'>index b4505bd..9c487f0 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/src/registry2.0/tests/entry.tcl
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/registry2.0/tests/entry.tcl
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -74,6 +74,9 @@ proc main {pextlibname} {
</span> test_set {[registry::entry search name -glob vi*]} {$vim1 $vim2 $vim3}
test_set {[registry::entry search name -regexp {zlib|pcre}]} \
{$zlib $pcre}
<span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # test that passing in confusing arguments doesn't crash
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ test {[catch {registry::entry search name vim1 --}] == 1}
</span> }
# try mapping files and checking their owners
</pre><pre style='margin:0'>
</pre>