Re: Re*: [PATCH] change contract between system_path and it's callers

2014-11-25 Thread Junio C Hamano
Alexander Kuleshov kuleshovm...@gmail.com writes:

 But if we still static const char* for git_etc_gitattributes and will
 not free it in bootstrap_attr_stack there will no memory leak, just
 tested it, so i'll remove free for it.

Leak or no leak, freeing there is wrong.  It will free the piece of
memory the next caller will obtain from the git_etc_gitattributes()
function.  In other words, the return value from that function is
owned by git_etc_gitattributes(), not by the caller.

As to leak, in the strictest sense of the word, i.e. do we
allocate on the heap and exit without freeing?, it _is_ leaking,
and your above just tested it probably means the tool I used did
not find/report it.  But as I said, it is not something worth
bothering about [*1*].

Think of it this way.

The git_etc_gitattributes() function goes like this with your patch
(and there is no fundamental difference in the original version,
which uses const char * where appropriate):

 static char *git_etc_gitattributes(void)
 {
static char *system_wide;
if (!system_wide)
system_wide = system_path(ETC_GITATTRIBUTES);
return system_wide;
 }

If you knew that the pathname for /etc/gitattributes substitute will
never be longer than 256 bytes, you may have coded the above like so
instead:

static char system_wide[256];
static char *git_etc_gitattributes(void)
{
if (!system_wide[0]) {
char *ret = system_path(ETC_GITATTRIBUTES);
if (strncpy(system_wide, ret, 256) = 256)
die(ETC_GITATTRIBUTES too long );
}   
return system_wide;
}

Even though we used the memory occupied by system_wide[] and did not
clean up before exit(), nobody would complain about leaking.

The existing code is the moral equivalent of the up to 256 bytes
illustration, but for a string whose size is not known at compile
time.  It is using and keeping the memory until program exit.
Nobody should complain about leaking.

That is, unless (1) the held memory is expected to be very large and
(2) you can prove that after the point you decide to insert free(),
nobody will ever need that information again.


[Footnote]

*1* The leaks we care about are of this form:

void silly_leaker(void)
{
printf(%s\n, system_path(ETC_GITATTRIBUTES));
}

where each invocation allocates memory, uses it and then loses
the reference to it without doing anything to clean-up.  You can
call such a function unbounded number of times and waste
unbounded amount of memory.

The implementation of git_etc_gitattributes() is not of that
kind.  An invocation of it allocates, uses and keeps.  The
second and subsequent invocation does not allocate.  When you
call it unbounded number of times, it does not waste unbounded
amount of memory.  It just keeps what it needs to answer the
next caller with.

The pattern needs to be made thread-safe, but that is a separate
topic.
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: Re*: [PATCH] change contract between system_path and it's callers

2014-11-25 Thread Alexander Kuleshov
Hello Junio,

I'm working on this patch and builtin/config.c, i have a little question:

Look, here - https://github.com/git/git/blob/master/builtin/config.c#L509
and in the next if clauses we get allocated path, but if i test it
with given config file with git config -f
(https://github.com/git/git/blob/master/builtin/config.c#L513) i have
prefix NULL and next if clause doesn't execute, so if i'll put
free(given_config_source.file) after config action i'll get error
because given_config_source.file wasn't allocated. How to be with
this?

Thank you.

2014-11-25 13:04 GMT+06:00 Alexander Kuleshov kuleshovm...@gmail.com:
 But if we still static const char* for git_etc_gitattributes and will
 not free it in bootstrap_attr_stack there will no memory leak, just
 tested it, so i'll remove free for it.

 2014-11-25 12:45 GMT+06:00 Alexander Kuleshov kuleshovm...@gmail.com:
 Hello Junio,

 I returned static to git_etc_gitattributes return value, but now i
 can't understand where to free 'system_wide'. As i understand
 correctly attr.c has following API for querying attributes:

 git_attr

 git_check_attr

 And as i see in code git_attr doesn't use git_attr_check, so now we
 have only git_check_attr and git_all_stars functions which are through
 prepare_attr_stack and bootstrap_attr_stack in it uses path which
 returned
  by system_path. So you're right if i free etc_attributes like this
 and git_etc_gitattributes will return static value we'll have access
 to freed memory if it will called again. But we have no access to
 etc_attributes outside bootstrap_attr_stack so where will be best
 place to free it?

 Thank you

 2014-11-25 2:50 GMT+06:00 Junio C Hamano gits...@pobox.com:
 Alex Kuleshov kuleshovm...@gmail.com writes:

 One thing to note is that this illustration does not consider memory
 pointed at by the system_wide variable here (from attr.c)

 static const char *git_etc_gitattributes(void)
 {
 static const char *system_wide;
 if (!system_wide)
 system_wide = system_path(ETC_GITATTRIBUTES);
 return system_wide;
 }

 at the point of process exit as a leak.

 But why? We allocated memory to system_wide with system_path, next git
 will exit somewhere with die, but system_wide didn't free... Or i'm
 wrong here too?

 It is in the same league as static const char *git_dir and friends
 that appear in the file-scope-static of environment.c.  Keeping small
 things around to be cleaned up by exit() is not a crime.



 --
 _
 0xAX



 --
 _
 0xAX



-- 
_
0xAX
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: Re*: [PATCH] change contract between system_path and it's callers

2014-11-25 Thread Alexander Kuleshov
Ah, you little ahead me, so we do not care about config.c in this way,
because it takes git_etc_gitconfig() in the same way as
git_etc_gitattributes

2014-11-25 23:55 GMT+06:00 Junio C Hamano gits...@pobox.com:
 Alexander Kuleshov kuleshovm...@gmail.com writes:

 But if we still static const char* for git_etc_gitattributes and will
 not free it in bootstrap_attr_stack there will no memory leak, just
 tested it, so i'll remove free for it.

 Leak or no leak, freeing there is wrong.  It will free the piece of
 memory the next caller will obtain from the git_etc_gitattributes()
 function.  In other words, the return value from that function is
 owned by git_etc_gitattributes(), not by the caller.

 As to leak, in the strictest sense of the word, i.e. do we
 allocate on the heap and exit without freeing?, it _is_ leaking,
 and your above just tested it probably means the tool I used did
 not find/report it.  But as I said, it is not something worth
 bothering about [*1*].

 Think of it this way.

 The git_etc_gitattributes() function goes like this with your patch
 (and there is no fundamental difference in the original version,
 which uses const char * where appropriate):

  static char *git_etc_gitattributes(void)
  {
 static char *system_wide;
 if (!system_wide)
 system_wide = system_path(ETC_GITATTRIBUTES);
 return system_wide;
  }

 If you knew that the pathname for /etc/gitattributes substitute will
 never be longer than 256 bytes, you may have coded the above like so
 instead:

 static char system_wide[256];
 static char *git_etc_gitattributes(void)
 {
 if (!system_wide[0]) {
 char *ret = system_path(ETC_GITATTRIBUTES);
 if (strncpy(system_wide, ret, 256) = 256)
 die(ETC_GITATTRIBUTES too long );
 }
 return system_wide;
 }

 Even though we used the memory occupied by system_wide[] and did not
 clean up before exit(), nobody would complain about leaking.

 The existing code is the moral equivalent of the up to 256 bytes
 illustration, but for a string whose size is not known at compile
 time.  It is using and keeping the memory until program exit.
 Nobody should complain about leaking.

 That is, unless (1) the held memory is expected to be very large and
 (2) you can prove that after the point you decide to insert free(),
 nobody will ever need that information again.


 [Footnote]

 *1* The leaks we care about are of this form:

 void silly_leaker(void)
 {
 printf(%s\n, system_path(ETC_GITATTRIBUTES));
 }

 where each invocation allocates memory, uses it and then loses
 the reference to it without doing anything to clean-up.  You can
 call such a function unbounded number of times and waste
 unbounded amount of memory.

 The implementation of git_etc_gitattributes() is not of that
 kind.  An invocation of it allocates, uses and keeps.  The
 second and subsequent invocation does not allocate.  When you
 call it unbounded number of times, it does not waste unbounded
 amount of memory.  It just keeps what it needs to answer the
 next caller with.

 The pattern needs to be made thread-safe, but that is a separate
 topic.



-- 
_
0xAX
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: Re*: [PATCH] change contract between system_path and it's callers

2014-11-25 Thread Junio C Hamano
Alexander Kuleshov kuleshovm...@gmail.com writes:

 Ah, you little ahead me, so we do not care about config.c in this way,
 because it takes git_etc_gitconfig() in the same way as
 git_etc_gitattributes

Yes, but looking at the file, you would notice that the
use_local_config codepath assigns a string obtained from
git_pathdup() to given_config_source.file, which means that somebody
later in the code path would not know if given_config_source.file is
merely pointing at a piece of memory owned by somebody else
(e.g. came from git_etc_gitconfig()) or if it owns the piece of
memory (e.g. came from git_pathdup()).  In the former case the
memory should never be freed, but not freeing in the latter would
leak the memory.

Assignment to given_config_source.file I see in that function that
borrows (i.e. the current code that does not fee is correct) are:

  - getenv(CONFIG_ENVIRONMENT)
  - NULL ;-) obviously
  - git_etc_gitconfig()
  
All the other assignment to given_config_source.file (including the
ones obtained from a call to home_config_paths()) makes us
responsible to free that piece memory, so they are technically
leaks.

But cmd_config() is a moral equivalent of main() in a typical
program, so it might not be worth worrying about allocating a single
piece of memory that is used throughout the lifetime of that
function and leaving it without freeing.


--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: Re*: [PATCH] change contract between system_path and it's callers

2014-11-24 Thread Alex Kuleshov

Junio C Hamano gits...@pobox.com @ 2014-11-25 01:33 ALMT:

 -static const char *git_etc_gitattributes(void)
 +static char *git_etc_gitattributes(void)

 Hmph, I think this should keep returning const char *, as the
 caller is not expected to free the pointer or write into the memory
 held by the returned string.  The same applies to the change of the
 type in struct git_config_source.

 The change in the semantics of system_path() made the get once and
 keep returning it this function does safer and correct, but this
 function itself did not change any behaviour from its caller's point
 of view.

Understand, will fix it.


  {
 -static const char *system_wide;
 +static char *system_wide;
  if (!system_wide)
  system_wide = system_path(ETC_GITATTRIBUTES);
  return system_wide;


 @@ -489,7 +489,9 @@ static void bootstrap_attr_stack(void)
  attr_stack = elem;

  if (git_attr_system()) {
 -elem = read_attr_from_file(git_etc_gitattributes(), 1);
 +char *etc_attributes = git_etc_gitattributes();
 +elem = read_attr_from_file(etc_attributes, 1);
 +free(etc_attributes);

 And freeing here is actively wrong, I think.  You are freeing the
 piece of memory still pointed by static char *system_wide in the
 function git_etc_gitattributes(); when it is called again, the
 caller will get a pointer into the memory you have freed here.

Why? If i understand correctly we don't use etc_attributes anymore in
this function and if we'll call this function again
git_etc_gitattributes will create new pointer and system_path alloc
memory for it or i'm wrong with it?


 diff --git a/builtin/config.c b/builtin/config.c
 index 15a7bea..266d42b 100644
 --- a/builtin/config.c
 +++ b/builtin/config.c
 @@ -575,8 +575,14 @@ int cmd_config(int argc, const char **argv, const char 
 *prefix)
  if (given_config_source.blob)
  die(editing blobs is not supported);
  git_config(git_default_config, NULL);
 -config_file = xstrdup(given_config_source.file ?
 -  given_config_source.file : 
 git_path(config));
 +
 +if (use_system_config)
 +config_file = given_config_source.file ?
 +
 given_config_source.file : git_path(config);
 +else
 +config_file = xstrdup(given_config_source.file ?
 +  
 given_config_source.file : git_path(config));
 +

 Sorry, but I do not understand this change.

 Why do you need if use-system-config, do not allocate here and
 then later everywhere if use-system-config, free it?  I would
 understand if the change were earlier we had mixture of borrowed
 and owned strings, but we make sure we always own the string by
 running xstrdup() in the caller when we used to let this function
 borrow, so that we can always free() before returning from here,
 or something.

 For example, in the original code, use_local_config codepath uses
 git_pathdup(), which is an allocated piece of memory, to initialize
 given_config_source.file.  Doesn't it need to be freed?

 Even if it is not in the use_system_config mode, if
 given_config_source.file is not an absolute path, we store a copy of
 prefix-filename result to given_config_source.file.  Doesn't it need
 to be freed?

 I think the implementation strategy you took makes the result
 unnecessarily messy and error prone.  Let's step back a bit.

 When you have code that sometimes borrows memory and sometimes owns
 memory, writing the clean-up part like this is error prone:

   char *var;

   if (A)
   var = borrowed memory;
   else if (B)
   var = borrowed memory;
   else if (C)
   var = xstrdup(borrowed memory);
   else
   var = borrowed memory;

   use var; /* a loong piece of code in reality */

   if (C)
   free(var);

 because the set-up part can and will change over time as the code
 evolves.  If written this way:

   char *var, *to_free = NULL;

   if (A)
   var = borrowed memory;
   else if (B)
   var = borrowed memory;
   else if (C)
   to_free = var = xstrdup(borrowed memory);
   else
   var = borrowed memory;

   use var; /* a loong piece of code in reality */

   free(to_free);

 the clean-up part would not have to worry how the set-up part
 decided when to borrow memory and when to own memory.  Another way
 to do so would obviously be:

   char *var;

   if (A)
   var = xstrdup(borrowed memory);
   else if (B)
   var = xstrdup(borrowed memory);
   else if (C)
   var = xstrdup(borrowed memory);
   else
   var = xstrdup(borrowed memory);

   use var; /* a loong piece of code in reality */

   

Re: Re*: [PATCH] change contract between system_path and it's callers

2014-11-24 Thread Junio C Hamano
Alex Kuleshov kuleshovm...@gmail.com writes:

 Junio C Hamano gits...@pobox.com @ 2014-11-25 01:33 ALMT:
 ...
 if (git_attr_system()) {
 -   elem = read_attr_from_file(git_etc_gitattributes(), 1);
 +   char *etc_attributes = git_etc_gitattributes();
 +   elem = read_attr_from_file(etc_attributes, 1);
 +   free(etc_attributes);

 And freeing here is actively wrong, I think.  You are freeing the
 piece of memory still pointed by static char *system_wide in the
 function git_etc_gitattributes(); when it is called again, the
 caller will get a pointer into the memory you have freed here.

 Why? If i understand correctly we don't use etc_attributes anymore in
 this function and if we'll call this function again
 git_etc_gitattributes will create new pointer and system_path alloc
 memory for it or i'm wrong with it?

The function keeps a singleton in static const char *system_wide
so that it has to call system_path() only once, and keeps the value
for second and subsequent calls.  From its callers' point of view,
they are only peeking the memory it returns.

This aspect does not change with your patch.

-static const char *git_etc_gitattributes(void)
+static char *git_etc_gitattributes(void)
 {
-   static const char *system_wide;
+   static char *system_wide;
if (!system_wide)
system_wide = system_path(ETC_GITATTRIBUTES);
return system_wide;

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: Re*: [PATCH] change contract between system_path and it's callers

2014-11-24 Thread Junio C Hamano
Alex Kuleshov kuleshovm...@gmail.com writes:

 One thing to note is that this illustration does not consider memory
 pointed at by the system_wide variable here (from attr.c)

 static const char *git_etc_gitattributes(void)
 {
 static const char *system_wide;
 if (!system_wide)
 system_wide = system_path(ETC_GITATTRIBUTES);
 return system_wide;
 }

 at the point of process exit as a leak.

 But why? We allocated memory to system_wide with system_path, next git
 will exit somewhere with die, but system_wide didn't free... Or i'm
 wrong here too?

It is in the same league as static const char *git_dir and friends
that appear in the file-scope-static of environment.c.  Keeping small
things around to be cleaned up by exit() is not a crime.
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: Re*: [PATCH] change contract between system_path and it's callers

2014-11-24 Thread Alexander Kuleshov
Hello Junio,

I returned static to git_etc_gitattributes return value, but now i
can't understand where to free 'system_wide'. As i understand
correctly attr.c has following API for querying attributes:

git_attr

git_check_attr

And as i see in code git_attr doesn't use git_attr_check, so now we
have only git_check_attr and git_all_stars functions which are through
prepare_attr_stack and bootstrap_attr_stack in it uses path which
returned
 by system_path. So you're right if i free etc_attributes like this
and git_etc_gitattributes will return static value we'll have access
to freed memory if it will called again. But we have no access to
etc_attributes outside bootstrap_attr_stack so where will be best
place to free it?

Thank you

2014-11-25 2:50 GMT+06:00 Junio C Hamano gits...@pobox.com:
 Alex Kuleshov kuleshovm...@gmail.com writes:

 One thing to note is that this illustration does not consider memory
 pointed at by the system_wide variable here (from attr.c)

 static const char *git_etc_gitattributes(void)
 {
 static const char *system_wide;
 if (!system_wide)
 system_wide = system_path(ETC_GITATTRIBUTES);
 return system_wide;
 }

 at the point of process exit as a leak.

 But why? We allocated memory to system_wide with system_path, next git
 will exit somewhere with die, but system_wide didn't free... Or i'm
 wrong here too?

 It is in the same league as static const char *git_dir and friends
 that appear in the file-scope-static of environment.c.  Keeping small
 things around to be cleaned up by exit() is not a crime.



-- 
_
0xAX
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: Re*: [PATCH] change contract between system_path and it's callers

2014-11-24 Thread Alexander Kuleshov
But if we still static const char* for git_etc_gitattributes and will
not free it in bootstrap_attr_stack there will no memory leak, just
tested it, so i'll remove free for it.

2014-11-25 12:45 GMT+06:00 Alexander Kuleshov kuleshovm...@gmail.com:
 Hello Junio,

 I returned static to git_etc_gitattributes return value, but now i
 can't understand where to free 'system_wide'. As i understand
 correctly attr.c has following API for querying attributes:

 git_attr

 git_check_attr

 And as i see in code git_attr doesn't use git_attr_check, so now we
 have only git_check_attr and git_all_stars functions which are through
 prepare_attr_stack and bootstrap_attr_stack in it uses path which
 returned
  by system_path. So you're right if i free etc_attributes like this
 and git_etc_gitattributes will return static value we'll have access
 to freed memory if it will called again. But we have no access to
 etc_attributes outside bootstrap_attr_stack so where will be best
 place to free it?

 Thank you

 2014-11-25 2:50 GMT+06:00 Junio C Hamano gits...@pobox.com:
 Alex Kuleshov kuleshovm...@gmail.com writes:

 One thing to note is that this illustration does not consider memory
 pointed at by the system_wide variable here (from attr.c)

 static const char *git_etc_gitattributes(void)
 {
 static const char *system_wide;
 if (!system_wide)
 system_wide = system_path(ETC_GITATTRIBUTES);
 return system_wide;
 }

 at the point of process exit as a leak.

 But why? We allocated memory to system_wide with system_path, next git
 will exit somewhere with die, but system_wide didn't free... Or i'm
 wrong here too?

 It is in the same league as static const char *git_dir and friends
 that appear in the file-scope-static of environment.c.  Keeping small
 things around to be cleaned up by exit() is not a crime.



 --
 _
 0xAX



-- 
_
0xAX
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html