On 08/29/2016 12:22 PM, william.c.roberts@xxxxxxxxx wrote: > From: William Roberts <william.c.roberts@xxxxxxxxx> > > I noticed, via gprof, that the time spent in nodups_specs() > accounts for 100% of the label_open() call. > > It seems as though the N^2 comparison using strcmp is very > slow. > > Do two major things: > 1. move the rec->validating check to the left, check the simple > thing first before runnning the expensive strcmp(). strcmp() > is used to check string equality, check lengths first. > 2. strlen() is used all over to calculate lengths, just store > it in a struct with the string so its usable elsewhere, rather > than recalculating it. > > text 21.4% speedup: > before text: 248 > after text: 195 > > binary 24.6% speedup: > before bin: 236 > after bin: 178 > > Some things to ponder: > 1. We can use C ABI safe pointer instead of len_str structure > https://bitbucket.org/billcroberts/twist > There are pros and cons to this approach, namely if someone > calls free(x) instead of twist_free(x) > It also currently has 0 support for stack based strings (simple > enough to add). I think this approach is overkill here. Agreed. > > 2. The location of the str_len struct and routines should likely > move elsewhere. Agreed. > > 3. The impact on Android is currently unmeasured, that's next. > Also, bionic uses something from label_file.h for processing > property_contexts for the Android property subsystem... so > need to ensure that all works as advertised still. > > Things to do: > 1. Cleanup the code locations, likely a util.h or a len_str.h, > a better name would be nice. > 2. Spell check this commit message Seems a bit prone to the str and len fields getting out of sync since they are both directly manipulated. > > Signed-off-by: William Roberts <william.c.roberts@xxxxxxxxx> > --- > libselinux/src/label.c | 8 ++-- > libselinux/src/label_android_property.c | 44 +++++++++---------- > libselinux/src/label_db.c | 7 +-- > libselinux/src/label_file.c | 63 ++++++++++++++------------ > libselinux/src/label_file.h | 78 +++++++++++++++++++-------------- > libselinux/src/label_internal.h | 22 +++++++++- > libselinux/src/label_media.c | 5 ++- > libselinux/src/label_support.c | 32 ++++++++------ > libselinux/src/label_x.c | 5 ++- > libselinux/src/matchpathcon.c | 2 +- > 10 files changed, 159 insertions(+), 107 deletions(-) > > diff --git a/libselinux/src/label.c b/libselinux/src/label.c > index 963bfcb..11324ea 100644 > --- a/libselinux/src/label.c > +++ b/libselinux/src/label.c > @@ -209,7 +209,7 @@ int selabel_validate(struct selabel_handle *rec, > if (!rec->validating || contexts->validated) > goto out; > > - rc = selinux_validate(&contexts->ctx_raw); > + rc = selinux_validate(&contexts->ctx_raw.str); > if (rc < 0) > goto out; > > @@ -248,7 +248,7 @@ static int selabel_fini(struct selabel_handle *rec, > return -1; > > if (translating && !lr->ctx_trans && > - selinux_raw_to_trans_context(lr->ctx_raw, &lr->ctx_trans)) > + selinux_raw_to_trans_context(lr->ctx_raw.str, &lr->ctx_trans)) > return -1; > > return 0; > @@ -369,7 +369,7 @@ int selabel_lookup_raw(struct selabel_handle *rec, char **con, > if (!lr) > return -1; > > - *con = strdup(lr->ctx_raw); > + *con = strdup(lr->ctx_raw.str); > return *con ? 0 : -1; > } > > @@ -429,7 +429,7 @@ int selabel_lookup_best_match_raw(struct selabel_handle *rec, char **con, > if (!lr) > return -1; > > - *con = strdup(lr->ctx_raw); > + *con = strdup(lr->ctx_raw.str); > return *con ? 0 : -1; > } > > diff --git a/libselinux/src/label_android_property.c b/libselinux/src/label_android_property.c > index 290b438..af0b9a8 100644 > --- a/libselinux/src/label_android_property.c > +++ b/libselinux/src/label_android_property.c > @@ -16,7 +16,7 @@ > /* A property security context specification. */ > typedef struct spec { > struct selabel_lookup_rec lr; /* holds contexts for lookup result */ > - char *property_key; /* property key string */ > + struct len_str property_key; /* property key string */ > } spec_t; > > /* Our stored configuration */ > @@ -33,13 +33,13 @@ static int cmp(const void *A, const void *B) > { > const struct spec *sp1 = A, *sp2 = B; > > - if (strncmp(sp1->property_key, "*", 1) == 0) > + if (strncmp(sp1->property_key.str, "*", 1) == 0) > return 1; > - if (strncmp(sp2->property_key, "*", 1) == 0) > + if (strncmp(sp2->property_key.str, "*", 1) == 0) > return -1; > > - size_t L1 = strlen(sp1->property_key); > - size_t L2 = strlen(sp2->property_key); > + size_t L1 = sp1->property_key.len; > + size_t L2 = sp2->property_key.len; > > return (L1 < L2) - (L1 > L2); > } > @@ -56,23 +56,23 @@ static int nodups_specs(struct saved_data *data, const char *path) > for (ii = 0; ii < data->nspec; ii++) { > curr_spec = &spec_arr[ii]; > for (jj = ii + 1; jj < data->nspec; jj++) { > - if (!strcmp(spec_arr[jj].property_key, > - curr_spec->property_key)) { > + if (len_str_eq(&spec_arr[jj].property_key, > + &curr_spec->property_key)) { > rc = -1; > errno = EINVAL; > - if (strcmp(spec_arr[jj].lr.ctx_raw, > - curr_spec->lr.ctx_raw)) { > + if (!len_str_eq(&spec_arr[jj].lr.ctx_raw, > + &curr_spec->lr.ctx_raw)) { > selinux_log > (SELINUX_ERROR, > "%s: Multiple different specifications for %s (%s and %s).\n", > - path, curr_spec->property_key, > - spec_arr[jj].lr.ctx_raw, > - curr_spec->lr.ctx_raw); > + path, curr_spec->property_key.str, > + spec_arr[jj].lr.ctx_raw.str, > + curr_spec->lr.ctx_raw.str); > } else { > selinux_log > (SELINUX_ERROR, > "%s: Multiple same specifications for %s.\n", > - path, curr_spec->property_key); > + path, curr_spec->property_key.str); > } > } > } > @@ -85,7 +85,7 @@ static int process_line(struct selabel_handle *rec, > int pass, unsigned lineno) > { > int items; > - char *prop = NULL, *context = NULL; > + struct len_str *prop = { 0 }, *context = { 0 }; > struct saved_data *data = (struct saved_data *)rec->data; > spec_t *spec_arr = data->spec_arr; > unsigned int nspec = data->nspec; > @@ -118,14 +118,14 @@ static int process_line(struct selabel_handle *rec, > free(context); > } else if (pass == 1) { > /* On the second pass, process and store the specification in spec. */ > - spec_arr[nspec].property_key = prop; > - spec_arr[nspec].lr.ctx_raw = context; > + memcpy(&spec_arr[nspec].property_key, prop, sizeof(*prop)); > + memcpy(&spec_arr[nspec].lr.ctx_raw, context, sizeof(*context)); > > if (rec->validating) { > if (selabel_validate(rec, &spec_arr[nspec].lr) < 0) { > selinux_log(SELINUX_ERROR, > "%s: line %u has invalid context %s\n", > - path, lineno, spec_arr[nspec].lr.ctx_raw); > + path, lineno, spec_arr[nspec].lr.ctx_raw.str); > errno = EINVAL; > return -1; > } > @@ -233,8 +233,8 @@ static void closef(struct selabel_handle *rec) > > for (i = 0; i < data->nspec; i++) { > spec = &data->spec_arr[i]; > - free(spec->property_key); > - free(spec->lr.ctx_raw); > + free(spec->property_key.str); > + free(spec->lr.ctx_raw.str); > free(spec->lr.ctx_trans); > } > > @@ -259,11 +259,11 @@ static struct selabel_lookup_rec *lookup(struct selabel_handle *rec, > } > > for (i = 0; i < data->nspec; i++) { > - if (strncmp(spec_arr[i].property_key, key, > - strlen(spec_arr[i].property_key)) == 0) { > + if (strncmp(spec_arr[i].property_key.str, key, > + spec_arr[i].property_key.len) == 0) { > break; > } > - if (strncmp(spec_arr[i].property_key, "*", 1) == 0) > + if (strncmp(spec_arr[i].property_key.str, "*", 1) == 0) > break; > } > > diff --git a/libselinux/src/label_db.c b/libselinux/src/label_db.c > index 1155bcc..c700aca 100644 > --- a/libselinux/src/label_db.c > +++ b/libselinux/src/label_db.c > @@ -153,7 +153,8 @@ process_line(const char *path, char *line_buf, unsigned int line_num, > > free(type); > spec->key = key; > - spec->lr.ctx_raw = context; > + spec->lr.ctx_raw.str = context; > + spec->lr.ctx_raw.len = strlen(context); > > catalog->nspec++; > > @@ -181,7 +182,7 @@ db_close(struct selabel_handle *rec) > for (i = 0; i < catalog->nspec; i++) { > spec = &catalog->specs[i]; > free(spec->key); > - free(spec->lr.ctx_raw); > + free(spec->lr.ctx_raw.str); > free(spec->lr.ctx_trans); > } > free(catalog); > @@ -333,7 +334,7 @@ out_error: > spec_t *spec = &catalog->specs[i]; > > free(spec->key); > - free(spec->lr.ctx_raw); > + free(spec->lr.ctx_raw.str); > free(spec->lr.ctx_trans); > } > free(catalog); > diff --git a/libselinux/src/label_file.c b/libselinux/src/label_file.c > index 68c566b..ade07d8 100644 > --- a/libselinux/src/label_file.c > +++ b/libselinux/src/label_file.c > @@ -71,25 +71,24 @@ static int nodups_specs(struct saved_data *data, const char *path) > for (ii = 0; ii < data->nspec; ii++) { > curr_spec = &spec_arr[ii]; > for (jj = ii + 1; jj < data->nspec; jj++) { > - if ((!strcmp(spec_arr[jj].regex_str, > - curr_spec->regex_str)) > + if (len_str_eq(&spec_arr[jj].regex_str, &curr_spec->regex_str) > && (!spec_arr[jj].mode || !curr_spec->mode > || spec_arr[jj].mode == curr_spec->mode)) { > rc = -1; > errno = EINVAL; > - if (strcmp(spec_arr[jj].lr.ctx_raw, > - curr_spec->lr.ctx_raw)) { > + if (!len_str_eq(&spec_arr[jj].lr.ctx_raw, > + &curr_spec->lr.ctx_raw)) { > COMPAT_LOG > (SELINUX_ERROR, > "%s: Multiple different specifications for %s (%s and %s).\n", > - path, curr_spec->regex_str, > - spec_arr[jj].lr.ctx_raw, > - curr_spec->lr.ctx_raw); > + path, curr_spec->regex_str.str, > + spec_arr[jj].lr.ctx_raw.str, > + curr_spec->lr.ctx_raw.str); > } else { > COMPAT_LOG > (SELINUX_ERROR, > "%s: Multiple same specifications for %s.\n", > - path, curr_spec->regex_str); > + path, curr_spec->regex_str.str); > } > } > } > @@ -475,12 +474,13 @@ static int read_binary_file(struct selabel_handle *rec) > goto out; > } > > - spec->lr.ctx_raw = str_buf; > + spec->lr.ctx_raw.str = str_buf; > + spec->lr.ctx_raw.len = entry_len -1; > > - if (strcmp(spec->lr.ctx_raw, "<<none>>") && rec->validating) { > + if (rec->validating && strcmp(spec->lr.ctx_raw.str, "<<none>>")) { > if (selabel_validate(rec, &spec->lr) < 0) { > selinux_log(SELINUX_ERROR, "%s: context %s is invalid\n", > - data->path, spec->lr.ctx_raw); > + data->path, spec->lr.ctx_raw.str); > errno = EINVAL; > free(str_buf); > goto out; > @@ -492,14 +492,16 @@ static int read_binary_file(struct selabel_handle *rec) > if (err < 0 || !entry_len) > goto out; > > - spec->regex_str = (char *) map_area->next_addr; > + spec->regex_str.str = (char *) map_area->next_addr; > err = next_entry(NULL, map_area, entry_len); > if (err < 0) > goto out; > > - if (spec->regex_str[entry_len - 1] != '\0') > + if (spec->regex_str.str[entry_len - 1] != '\0') > goto out; > > + spec->regex_str.len = entry_len - 1; > + > /* Process mode */ > if (version >= SELINUX_COMPILED_FCONTEXT_MODE) > err = next_entry(&mode, map_area, sizeof(mode)); > @@ -715,11 +717,13 @@ static void closef(struct selabel_handle *rec) > for (i = 0; i < data->nspec; i++) { > spec = &data->spec_arr[i]; > free(spec->lr.ctx_trans); > - free(spec->lr.ctx_raw); > + free(spec->lr.ctx_raw.str); > if (spec->from_mmap) > continue; > - free(spec->regex_str); > - free(spec->type_str); > + > + free(spec->regex_str.str); > + free(spec->type_str.str); > + > if (spec->regcomp) { > pcre_free(spec->regex); > pcre_free_study(spec->sd); > @@ -767,6 +771,11 @@ static struct spec *lookup_common(struct selabel_handle *rec, > const char *prev_slash, *next_slash; > unsigned int sofar = 0; > > + struct len_str none = { > + .str = (char *)"<<none>>", > + .len = 8 > + }; > + > if (!data->nspec) { > errno = ENOENT; > goto finish; > @@ -834,7 +843,7 @@ static struct spec *lookup_common(struct selabel_handle *rec, > } > } > > - if (i < 0 || strcmp(spec_arr[i].lr.ctx_raw, "<<none>>") == 0) { > + if (i < 0 || len_str_eq(&spec_arr[i].lr.ctx_raw, &none)) { > /* No matching specification. */ > errno = ENOENT; > goto finish; > @@ -926,8 +935,8 @@ static enum selabel_cmp_result incomp(struct spec *spec1, struct spec *spec2, co > selinux_log(SELINUX_INFO, > "selabel_cmp: mismatched %s on entry %d: (%s, %x, %s) vs entry %d: (%s, %x, %s)\n", > reason, > - i, spec1->regex_str, spec1->mode, spec1->lr.ctx_raw, > - j, spec2->regex_str, spec2->mode, spec2->lr.ctx_raw); > + i, spec1->regex_str.str, spec1->mode, spec1->lr.ctx_raw.str, > + j, spec2->regex_str.str, spec2->mode, spec2->lr.ctx_raw.str); > return SELABEL_INCOMPARABLE; > } > > @@ -976,7 +985,7 @@ static enum selabel_cmp_result cmp(struct selabel_handle *h1, > memcmp(spec1->regex, spec2->regex, len1)) > return incomp(spec1, spec2, "regex", i, j); > } else { > - if (strcmp(spec1->regex_str, spec2->regex_str)) > + if (strcmp(spec1->regex_str.str, spec2->regex_str.str)) > return incomp(spec1, spec2, "regex_str", i, j); > } > > @@ -995,7 +1004,7 @@ static enum selabel_cmp_result cmp(struct selabel_handle *h1, > return incomp(spec1, spec2, "stem", i, j); > } > > - if (strcmp(spec1->lr.ctx_raw, spec2->lr.ctx_raw)) > + if (!len_str_eq(&spec1->lr.ctx_raw, &spec2->lr.ctx_raw)) > return incomp(spec1, spec2, "ctx_raw", i, j); > > i++; > @@ -1020,17 +1029,17 @@ static void stats(struct selabel_handle *rec) > > for (i = 0; i < nspec; i++) { > if (spec_arr[i].matches == 0) { > - if (spec_arr[i].type_str) { > + if (spec_arr[i].type_str.str) { > COMPAT_LOG(SELINUX_WARNING, > "Warning! No matches for (%s, %s, %s)\n", > - spec_arr[i].regex_str, > - spec_arr[i].type_str, > - spec_arr[i].lr.ctx_raw); > + spec_arr[i].regex_str.str, > + spec_arr[i].type_str.str, > + spec_arr[i].lr.ctx_raw.str); > } else { > COMPAT_LOG(SELINUX_WARNING, > "Warning! No matches for (%s, %s)\n", > - spec_arr[i].regex_str, > - spec_arr[i].lr.ctx_raw); > + spec_arr[i].regex_str.str, > + spec_arr[i].lr.ctx_raw.str); > } > } > } > diff --git a/libselinux/src/label_file.h b/libselinux/src/label_file.h > index da06164..cd021f4 100644 > --- a/libselinux/src/label_file.h > +++ b/libselinux/src/label_file.h > @@ -26,10 +26,10 @@ > > /* A file security context specification. */ > struct spec { > - struct selabel_lookup_rec lr; /* holds contexts for lookup result */ > - char *regex_str; /* regular expession string for diagnostics */ > - char *type_str; /* type string for diagnostic messages */ > - pcre *regex; /* compiled regular expression */ > + struct selabel_lookup_rec lr; /* holds contexts for lookup result */ > + struct len_str regex_str; /* regular expession string for diagnostics */ > + struct len_str type_str; /* type string for diagnostic messages */ > + pcre *regex; /* compiled regular expression */ > union { > pcre_extra *sd; /* pointer to extra compiled stuff */ > pcre_extra lsd; /* used to hold the mmap'd version */ > @@ -90,16 +90,19 @@ static inline pcre_extra *get_pcre_extra(struct spec *spec) > return spec->sd; > } > > -static inline mode_t string_to_mode(char *mode) > +static inline mode_t string_to_mode(struct len_str *mode) > { > size_t len; > > if (!mode) > return 0; > - len = strlen(mode); > - if (mode[0] != '-' || len != 2) > + > + len = mode->len; > + > + if (mode->str[0] != '-' || len != 2) > return -1; > - switch (mode[1]) { > + > + switch (mode->str[1]) { > case 'b': > return S_IFBLK; > case 'c': > @@ -153,8 +156,8 @@ static inline void spec_hasMetaChars(struct spec *spec) > int len; > char *end; > > - c = spec->regex_str; > - len = strlen(spec->regex_str); > + c = spec->regex_str.str; > + len = spec->regex_str.len; > end = c + len; > > spec->hasMetaChars = 0; > @@ -175,7 +178,7 @@ static inline void spec_hasMetaChars(struct spec *spec) > case '(': > case '{': > spec->hasMetaChars = 1; > - spec->prefix_len = c - spec->regex_str; > + spec->prefix_len = c - spec->regex_str.str; > return; > case '\\': /* skip the next character */ > c++; > @@ -327,13 +330,16 @@ static inline int compile_regex(struct saved_data *data, struct spec *spec, > if (spec->regcomp) > return 0; /* already done */ > > + len = spec->regex_str.len; > + reg_buf = spec->regex_str.str; > + > /* Skip the fixed stem. */ > - reg_buf = spec->regex_str; > - if (spec->stem_id >= 0) > + if (spec->stem_id >= 0) { > reg_buf += stem_arr[spec->stem_id].len; > + len -= stem_arr[spec->stem_id].len; > + } > > /* Anchor the regular expression. */ > - len = strlen(reg_buf); > cp = anchored_regex = malloc(len + 3); > if (!anchored_regex) > return -1; > @@ -375,7 +381,15 @@ static inline int process_line(struct selabel_handle *rec, > char *line_buf, unsigned lineno) > { > int items, len, rc; > - char *regex = NULL, *type = NULL, *context = NULL; > + > + struct len_str regex = { 0 } , type = { 0 }, context = { 0 }; > + > + /* XXX Export this as a const */ > + struct len_str none = { > + .str = (char *)"<<none>>", > + .len = 8 > + }; > + > struct saved_data *data = (struct saved_data *)rec->data; > struct spec *spec_arr; > unsigned int nspec = data->nspec; > @@ -399,21 +413,21 @@ static inline int process_line(struct selabel_handle *rec, > "%s: line %u is missing fields\n", path, > lineno); > if (items == 1) > - free(regex); > + free(regex.str); > errno = EINVAL; > return -1; > } else if (items == 2) { > /* The type field is optional. */ > context = type; > - type = 0; > + memset(&type, 0, sizeof(type)); > } > > - len = get_stem_from_spec(regex); > - if (len && prefix && strncmp(prefix, regex, len)) { > + len = get_stem_from_spec(regex.str); > + if (len && prefix && strncmp(prefix, regex.str, len)) { > /* Stem of regex does not match requested prefix, discard. */ > - free(regex); > - free(type); > - free(context); > + free(regex.str); > + free(type.str); > + free(context.str); > return 0; > } > > @@ -424,13 +438,13 @@ static inline int process_line(struct selabel_handle *rec, > spec_arr = data->spec_arr; > > /* process and store the specification in spec. */ > - spec_arr[nspec].stem_id = find_stem_from_spec(data, regex); > - spec_arr[nspec].regex_str = regex; > - > - spec_arr[nspec].type_str = type; > + spec_arr[nspec].stem_id = find_stem_from_spec(data, regex.str); > + memcpy(&spec_arr[nspec].regex_str, ®ex, sizeof(regex)); > + memcpy(&spec_arr[nspec].lr.ctx_raw, &context, sizeof(context)); > spec_arr[nspec].mode = 0; > > - spec_arr[nspec].lr.ctx_raw = context; > + if (type.str) > + memcpy(&spec_arr[nspec].type_str, &type, sizeof(type)); > > /* > * bump data->nspecs to cause closef() to cover it in its free > @@ -442,19 +456,19 @@ static inline int process_line(struct selabel_handle *rec, > compile_regex(data, &spec_arr[nspec], &errbuf)) { > COMPAT_LOG(SELINUX_ERROR, > "%s: line %u has invalid regex %s: %s\n", > - path, lineno, regex, > + path, lineno, regex.str, > (errbuf ? errbuf : "out of memory")); > errno = EINVAL; > return -1; > } > > - if (type) { > - mode_t mode = string_to_mode(type); > + if (type.str) { > + mode_t mode = string_to_mode(&type); > > if (mode == (mode_t)-1) { > COMPAT_LOG(SELINUX_ERROR, > "%s: line %u has invalid file type %s\n", > - path, lineno, type); > + path, lineno, type.str); > errno = EINVAL; > return -1; > } > @@ -465,7 +479,7 @@ static inline int process_line(struct selabel_handle *rec, > * any meta characters in the RE */ > spec_hasMetaChars(&spec_arr[nspec]); > > - if (strcmp(context, "<<none>>") && rec->validating) > + if (rec->validating && !len_str_eq(&context, &none)) > compat_validate(rec, &spec_arr[nspec].lr, path, lineno); > > return 0; > diff --git a/libselinux/src/label_internal.h b/libselinux/src/label_internal.h > index aa48fff..51aa33d 100644 > --- a/libselinux/src/label_internal.h > +++ b/libselinux/src/label_internal.h > @@ -71,8 +71,28 @@ extern struct selabel_sub *selabel_subs_init(const char *path, > struct selabel_sub *list, > struct selabel_digest *digest); > > +/* > + * A simple struct for tracking string lengths > + * with strings. > + */ > +struct len_str { > + size_t len; > + char *str; > +}; > + > +static inline bool len_str_eq(struct len_str *a, struct len_str *b) > +{ > + if (a->len != b->len) > + return false; > + > + if (a->str == b->str) > + return true; > + > + return !strcmp(a->str, b->str); > +} > + > struct selabel_lookup_rec { > - char * ctx_raw; > + struct len_str ctx_raw; > char * ctx_trans; > int validated; > }; > diff --git a/libselinux/src/label_media.c b/libselinux/src/label_media.c > index 622741b..e85e973 100644 > --- a/libselinux/src/label_media.c > +++ b/libselinux/src/label_media.c > @@ -56,7 +56,8 @@ static int process_line(const char *path, char *line_buf, int pass, > > if (pass == 1) { > data->spec_arr[data->nspec].key = key; > - data->spec_arr[data->nspec].lr.ctx_raw = context; > + data->spec_arr[data->nspec].lr.ctx_raw.str = context; > + data->spec_arr[data->nspec].lr.ctx_raw.len = strlen(context); > } > > data->nspec++; > @@ -159,7 +160,7 @@ static void close(struct selabel_handle *rec) > for (i = 0; i < data->nspec; i++) { > spec = &spec_arr[i]; > free(spec->key); > - free(spec->lr.ctx_raw); > + free(spec->lr.ctx_raw.str); > free(spec->lr.ctx_trans); > } > > diff --git a/libselinux/src/label_support.c b/libselinux/src/label_support.c > index 26f9ef1..e9b842f 100644 > --- a/libselinux/src/label_support.c > +++ b/libselinux/src/label_support.c > @@ -22,16 +22,17 @@ > * errno will be set. > * > */ > -static inline int read_spec_entry(char **entry, char **ptr, int *len, const char **errbuf) > +static inline int read_spec_entry(struct len_str *entry, char **ptr, const char **errbuf) > { > - *entry = NULL; > + size_t len = 0; > char *tmp_buf = NULL; > > + memset(entry, 0, sizeof(*entry)); > + > while (isspace(**ptr) && **ptr != '\0') > (*ptr)++; > > tmp_buf = *ptr; > - *len = 0; > > while (!isspace(**ptr) && **ptr != '\0') { > if (!isascii(**ptr)) { > @@ -40,13 +41,15 @@ static inline int read_spec_entry(char **entry, char **ptr, int *len, const char > return -1; > } > (*ptr)++; > - (*len)++; > + len++; > } > > - if (*len) { > - *entry = strndup(tmp_buf, *len); > - if (!*entry) > + if (len) { > + entry->str = strndup(tmp_buf, len); > + if (!entry->str) > return -1; > + > + entry->len = len; > } > > return 0; > @@ -56,7 +59,7 @@ static inline int read_spec_entry(char **entry, char **ptr, int *len, const char > * line_buf - Buffer containing the spec entries . > * errbuf - Double pointer used for passing back specific error messages. > * num_args - The number of spec parameter entries to process. > - * ... - A 'char **spec_entry' for each parameter. > + * ... - A 'struct len_str **spec_entry' for each parameter. > * returns - The number of items processed. On error, it returns -1 with errno > * set and may set errbuf to a specific error message. > * > @@ -65,8 +68,9 @@ static inline int read_spec_entry(char **entry, char **ptr, int *len, const char > */ > int hidden read_spec_entries(char *line_buf, const char **errbuf, int num_args, ...) > { > - char **spec_entry, *buf_p; > - int len, rc, items, entry_len = 0; > + struct len_str *spec_entry; > + char *buf_p; > + int len, rc, items; > va_list ap; > > *errbuf = NULL; > @@ -93,20 +97,22 @@ int hidden read_spec_entries(char *line_buf, const char **errbuf, int num_args, > > items = 0; > while (items < num_args) { > - spec_entry = va_arg(ap, char **); > + spec_entry = va_arg(ap, struct len_str *); > > if (len - 1 == buf_p - line_buf) { > va_end(ap); > return items; > } > > - rc = read_spec_entry(spec_entry, &buf_p, &entry_len, errbuf); > + rc = read_spec_entry(spec_entry, &buf_p, errbuf); > if (rc < 0) { > va_end(ap); > return rc; > } > - if (entry_len) > + > + if (spec_entry->len) { > items++; > + } > } > va_end(ap); > return items; > diff --git a/libselinux/src/label_x.c b/libselinux/src/label_x.c > index 700def1..cdbac8c 100644 > --- a/libselinux/src/label_x.c > +++ b/libselinux/src/label_x.c > @@ -81,7 +81,8 @@ static int process_line(const char *path, char *line_buf, int pass, > return 0; > } > data->spec_arr[data->nspec].key = key; > - data->spec_arr[data->nspec].lr.ctx_raw = context; > + data->spec_arr[data->nspec].lr.ctx_raw.str = context; > + data->spec_arr[data->nspec].lr.ctx_raw.len = strlen(context); > free(type); > } > > @@ -186,7 +187,7 @@ static void close(struct selabel_handle *rec) > for (i = 0; i < data->nspec; i++) { > spec = &spec_arr[i]; > free(spec->key); > - free(spec->lr.ctx_raw); > + free(spec->lr.ctx_raw.str); > free(spec->lr.ctx_trans); > } > > diff --git a/libselinux/src/matchpathcon.c b/libselinux/src/matchpathcon.c > index 4764ab7..96c39b4 100644 > --- a/libselinux/src/matchpathcon.c > +++ b/libselinux/src/matchpathcon.c > @@ -541,7 +541,7 @@ int compat_validate(struct selabel_handle *rec, > const char *path, unsigned lineno) > { > int rc; > - char **ctx = &contexts->ctx_raw; > + char **ctx = &contexts->ctx_raw.str; > > if (myinvalidcon) > rc = myinvalidcon(path, lineno, *ctx); > _______________________________________________ Selinux mailing list Selinux@xxxxxxxxxxxxx To unsubscribe, send email to Selinux-leave@xxxxxxxxxxxxx. To get help, send an email containing "help" to Selinux-request@xxxxxxxxxxxxx.