On 03/23/2015 05:38 PM, Tyler Hicks wrote:
> On 2015-03-23 18:24:43, Tyler Hicks wrote:
>> On 2015-03-06 15:48:22, Tyler Hicks wrote:
>>> From: John Johansen <john.johan...@canonical.com>
>>>
>>> While some of these allocations will go away as we convert to C++,
>>> some of these need to stay C as the are going to be moved into a
>>> library to support loading cache from init daemons etc.
>>>
>>> For the bits that will eventually be C++ this helps clean things up,
>>> in the interim.
>>>
>>> TODO: apply to libapparmor as well
>>>
>>> Signed-off-by: John Johansen <john.johan...@canonical.com>
>>> ---
>>>  parser/lib.c              | 11 ++++++++---
>>>  parser/lib.h              |  3 +++
>>>  parser/parser_interface.c | 13 ++++---------
>>>  parser/parser_lex.l       | 16 ++++------------
>>>  parser/parser_main.c      | 39 ++++++++++++---------------------------
>>>  5 files changed, 31 insertions(+), 51 deletions(-)
>>>
>>> diff --git a/parser/lib.c b/parser/lib.c
>>> index 85e39e0..fb9df49 100644
>>> --- a/parser/lib.c
>>> +++ b/parser/lib.c
>>> @@ -33,6 +33,13 @@
>>>  #include "lib.h"
>>>  #include "parser.h"
>>>  
>>> +/* automaticly free allocated variables tagged with autofree on fn exit */
>>> +void __autofree(void *p)
>>> +{
>>> +   void **_p = (void**)p;
>>> +   free(*_p);
>>> +}
>>> +
>>>  /**
>>>   * dirat_for_each: iterate over a directory calling cb for each entry
>>>   * @dir: already opened directory (MAY BE NULL)
>>> @@ -62,7 +69,7 @@
>>>  int dirat_for_each(DIR *dir, const char *name, void *data,
>>>                int (* cb)(DIR *, const char *, struct stat *, void *))
>>>  {
>>> -   struct dirent *dirent = NULL;
>>> +   autofree struct dirent *dirent = NULL;
>>>     DIR *d = NULL;
>>>     int error;
>>>  
>>> @@ -132,7 +139,6 @@ int dirat_for_each(DIR *dir, const char *name, void 
>>> *data,
>>>  
>>>     if (d != dir)
>>>             closedir(d);
>>> -   free(dirent);
>>>  
>>>     return 0;
>>>  
>>> @@ -140,7 +146,6 @@ fail:
>>>     error = errno;
>>>     if (d && d != dir)
>>>             closedir(d);
>>> -   free(dirent);
>>>     errno = error;
>>>  
>>>     return -1;
>>> diff --git a/parser/lib.h b/parser/lib.h
>>> index aac2223..73e1ffc 100644
>>> --- a/parser/lib.h
>>> +++ b/parser/lib.h
>>> @@ -3,6 +3,9 @@
>>>  
>>>  #include <dirent.h>
>>>  
>>> +#define autofree __attribute((cleanup(__autofree)))
>>> +void __autofree(void *p);
>>> +
>>>  int dirat_for_each(DIR *dir, const char *name, void *data,
>>>                int (* cb)(DIR *, const char *, struct stat *, void *));
>>>  
>>> diff --git a/parser/parser_interface.c b/parser/parser_interface.c
>>> index 0d6626d..485c30b 100644
>>> --- a/parser/parser_interface.c
>>> +++ b/parser/parser_interface.c
>>> @@ -28,6 +28,7 @@
>>>  #include <string>
>>>  #include <sstream>
>>>  
>>> +#include "lib.h"
>>>  #include "parser.h"
>>>  #include "profile.h"
>>>  #include "libapparmor_re/apparmor_re.h"
>>> @@ -374,13 +375,11 @@ void sd_serialize_profile(std::ostringstream &buf, 
>>> Profile *profile,
>>>     sd_write_struct(buf, "profile");
>>>     if (flattened) {
>>>             assert(profile->parent);
>>> -           char *name = (char *) malloc(3 + strlen(profile->name) +
>>> -                               strlen(profile->parent->name));
>>> +           autofree char *name = (char *) malloc(3 + strlen(profile->name) 
>>> + strlen(profile->parent->name));
>>>             if (!name)
>>>                     return;
>>>             sprintf(name, "%s//%s", profile->parent->name, profile->name);
>>>             sd_write_string(buf, name, NULL);
>>> -           free(name);
>>>     } else {
>>>             sd_write_string(buf, profile->name, NULL);
>>>     }
>>> @@ -483,7 +482,7 @@ int __sd_serialize_profile(int option, Profile *prof)
>>>     int fd = -1;
>>>     int error = -ENOMEM, size, wsize;
>>>     std::ostringstream work_area;
>>> -   char *filename = NULL;
>>> +   autofree char *filename = NULL;
>>>  
>>>     switch (option) {
>>>     case OPTION_ADD:
>>
>> Adding some missing context:
>>
>>         switch (option) {
>>         case OPTION_ADD:
>>                 if (asprintf(&filename, "%s/.load", subdomainbase) == -1)
>>                         goto exit;
>>                 if (kernel_load) fd = open(filename, O_WRONLY);
>>                 break;
>>         case OPTION_REPLACE:
>>                 if (asprintf(&filename, "%s/.replace", subdomainbase) == -1)
>>                         goto exit;
>>                 if (kernel_load) fd = open(filename, O_WRONLY);
>>                 break;
>>         case OPTION_REMOVE:
>>                 if (asprintf(&filename, "%s/.remove", subdomainbase) == -1)
>>                         goto exit;
>>                 if (kernel_load) fd = open(filename, O_WRONLY);
>>                 break;
>>         case OPTION_STDOUT:
>>                 filename = strdup("stdout");
>>                 fd = dup(1);
>>                 break;
>>         case OPTION_OFILE:
>>                 fd = dup(fileno(ofile));
>>                 break;
>>         default:
>>                 error = -EINVAL;
>>                 goto exit;
>>                 break;
>>         }
>>
>> If those asprintf() calls fail, the value of filename is undefined so we 
>> can't
>> be sure what the __autofree() function will receive as input. I'll follow up
>> with a patch to set filename to NULL in the asprintf() error paths.
> 
> I started to do this and it causes a bunch of churn in this series.
> Additionally, it doesn't prevent the same mistake from happening again.
> I'm now leaning towards doing something like this so that the entire
> codebase benefits:
> 
> aa_asprintf(char **strp, const char *fmt, ...)
> {
>       va_list args;
> 
>       va_start(args, fmt);
>       if(vasprintf(strp, fmt, args) == -1)
>               *strp = NULL;
>       va_end(args); 
> }
> 
> #define asprintf aa_asprintf
> 
> Any thoughts?
> 
yeah that works and keeps us from having to have the extra if for every asprintf



-- 
AppArmor mailing list
AppArmor@lists.ubuntu.com
Modify settings or unsubscribe at: 
https://lists.ubuntu.com/mailman/listinfo/apparmor

Reply via email to