diff options
author | Vicent Marti <tanoku@gmail.com> | 2010-10-28 02:07:18 +0300 |
---|---|---|
committer | Vicent Marti <tanoku@gmail.com> | 2010-10-28 02:07:18 +0300 |
commit | 585190183b47dc991605abcfbe3afb57220a0f29 (patch) | |
tree | f8a1f2572f667296a5b5121c64c74bb353557c93 /src/commit.c | |
parent | 2d16373cb8d8c22b3ec99a6936b82821e99e64a5 (diff) | |
download | libgit2-585190183b47dc991605abcfbe3afb57220a0f29.tar.gz |
Fix internal memory management on the library
String mememory is now managed in a much more sane manner.
Fixes include:
- git_person email and name is no longer limited to 64 characters
- git_tree_entry filename is no longer limited to 255 characters
- raw objects are properly opened & closed the minimum amount of
times required for parsing
- unit tests no longer leak
- removed 5 other misc memory leaks as reported by Valgrind
- tree writeback no longer segfaults on rare ocassions
The git_person struct is no longer public. It is now managed by the
library, and getter methods are in place to access its internal
attributes.
Signed-off-by: Vicent Marti <tanoku@gmail.com>
Diffstat (limited to 'src/commit.c')
-rw-r--r-- | src/commit.c | 232 |
1 files changed, 68 insertions, 164 deletions
diff --git a/src/commit.c b/src/commit.c index 90a30e020..a2d7221d1 100644 --- a/src/commit.c +++ b/src/commit.c @@ -23,11 +23,14 @@ * Boston, MA 02110-1301, USA. */ +#include "git/common.h" +#include "git/odb.h" +#include "git/repository.h" + #include "common.h" #include "commit.h" #include "revwalk.h" -#include "git/odb.h" -#include "git/repository.h" +#include "person.h" #define COMMIT_BASIC_PARSE 0x0 #define COMMIT_FULL_PARSE 0x1 @@ -56,8 +59,9 @@ void git_commit__free(git_commit *commit) { clear_parents(commit); - free(commit->author); - free(commit->committer); + git_person__free(commit->author); + git_person__free(commit->committer); + free(commit->message); free(commit->message_short); free(commit); @@ -73,146 +77,12 @@ const git_oid *git_commit_id(git_commit *c) return git_object_id((git_object *)c); } -int git_commit__parse(git_commit *commit) -{ - const int close_db_object = 1; - int error = 0; - - if ((error = git_object__source_open((git_object *)commit)) < 0) - return error; - - error = git_commit__parse_buffer(commit, - commit->object.source.raw.data, commit->object.source.raw.len, COMMIT_BASIC_PARSE); - - if (close_db_object) - git_object__source_close((git_object *)commit); - - return error; -} - -int git_commit__parse_full(git_commit *commit) -{ - int error; - - if (commit->full_parse) - return 0; - - if (git_object__source_open((git_object *)commit) < 0) - return GIT_ERROR; - - error = git_commit__parse_buffer(commit, - commit->object.source.raw.data, commit->object.source.raw.len, COMMIT_FULL_PARSE); - - git_object__source_close((git_object *)commit); - - commit->full_parse = 1; - return error; -} git_commit *git_commit_lookup(git_repository *repo, const git_oid *id) { return (git_commit *)git_repository_lookup(repo, id, GIT_OBJ_COMMIT); } -int git__parse_person(git_person *person, char **buffer_out, - const char *buffer_end, const char *header) -{ - const size_t header_len = strlen(header); - - int i; - char *buffer = *buffer_out; - char *line_end, *name, *email; - - line_end = memchr(buffer, '\n', buffer_end - buffer); - if (!line_end) - return GIT_EOBJCORRUPTED; - - if (buffer + (header_len + 1) > line_end) - return GIT_EOBJCORRUPTED; - - if (memcmp(buffer, header, header_len) != 0) - return GIT_EOBJCORRUPTED; - - buffer += header_len; - - - /* Parse name field */ - for (i = 0, name = person->name; - i < 64 && buffer < line_end && *buffer != '<'; - ++i) - *name++ = *buffer++; - - *(name - 1) = 0; - - while (buffer < line_end && *buffer != '<') - buffer++; - - if (++buffer >= line_end) - return GIT_EOBJCORRUPTED; - - /* Parse email field */ - for (i = 0, email = person->email; - i < 64 && buffer < line_end && *buffer != '>'; - ++i) - *email++ = *buffer++; - - *email = 0; - - while (buffer < line_end && *buffer != '>') - buffer++; - - if (++buffer >= line_end) - return GIT_EOBJCORRUPTED; - - person->time = strtol(buffer, &buffer, 10); - - if (person->time == 0) - return GIT_EOBJCORRUPTED; - - *buffer_out = (line_end + 1); - return 0; -} - -int git__write_person(git_odb_source *src, const char *header, const git_person *person) -{ - return git__source_printf(src, "%s %s <%s> %u\n", header, person->name, person->email, person->time); -} - -int git__parse_oid(git_oid *oid, char **buffer_out, - const char *buffer_end, const char *header) -{ - const size_t sha_len = GIT_OID_HEXSZ; - const size_t header_len = strlen(header); - - char *buffer = *buffer_out; - - if (buffer + (header_len + sha_len + 1) > buffer_end) - return GIT_EOBJCORRUPTED; - - if (memcmp(buffer, header, header_len) != 0) - return GIT_EOBJCORRUPTED; - - if (buffer[header_len + sha_len] != '\n') - return GIT_EOBJCORRUPTED; - - if (git_oid_mkstr(oid, buffer + header_len) < 0) - return GIT_EOBJCORRUPTED; - - *buffer_out = buffer + (header_len + sha_len + 1); - - return 0; -} - -int git__write_oid(git_odb_source *src, const char *header, const git_oid *oid) -{ - char hex_oid[41]; - - git_oid_fmt(hex_oid, oid); - hex_oid[40] = 0; - - return git__source_printf(src, "%s %s\n", header, hex_oid); -} - int git_commit__writeback(git_commit *commit, git_odb_source *src) { git_commit_parents *parent; @@ -232,12 +102,12 @@ int git_commit__writeback(git_commit *commit, git_odb_source *src) if (commit->author == NULL) return GIT_ERROR; - git__write_person(src, "author", commit->author); + git_person__write(src, "author", commit->author); if (commit->committer == NULL) return GIT_ERROR; - git__write_person(src, "committer", commit->committer); + git_person__write(src, "committer", commit->committer); if (commit->message != NULL) git__source_printf(src, "\n%s", commit->message); @@ -245,13 +115,12 @@ int git_commit__writeback(git_commit *commit, git_odb_source *src) return GIT_SUCCESS; } -int git_commit__parse_buffer(git_commit *commit, void *data, size_t len, unsigned int parse_flags) +int commit_parse_buffer(git_commit *commit, void *data, size_t len, unsigned int parse_flags) { char *buffer = (char *)data; const char *buffer_end = (char *)data + len; git_oid oid; - git_person person; if (git__parse_oid(&oid, &buffer, buffer_end, "tree ") < 0) return GIT_EOBJCORRUPTED; @@ -279,29 +148,31 @@ int git_commit__parse_buffer(git_commit *commit, void *data, size_t len, unsigne commit->parents = node; } - if (git__parse_person(&person, &buffer, buffer_end, "author ") < 0) - return GIT_EOBJCORRUPTED; if (parse_flags & COMMIT_FULL_PARSE) { if (commit->author) - free(commit->author); + git_person__free(commit->author); commit->author = git__malloc(sizeof(git_person)); - memcpy(commit->author, &person, sizeof(git_person)); - } + if (git_person__parse(commit->author, &buffer, buffer_end, "author ") < 0) + return GIT_EOBJCORRUPTED; - if (git__parse_person(&person, &buffer, buffer_end, "committer ") < 0) - return GIT_EOBJCORRUPTED; + } else { + if ((buffer = memchr(buffer, '\n', buffer_end - buffer)) == NULL) + return GIT_EOBJCORRUPTED; - commit->commit_time = person.time; + buffer++; + } - if (parse_flags & COMMIT_FULL_PARSE) { - if (commit->committer) - free(commit->committer); + /* Always parse the committer; we need the commit time */ + if (commit->committer) + git_person__free(commit->committer); - commit->committer = git__malloc(sizeof(git_person)); - memcpy(commit->committer, &person, sizeof(git_person)); - } + commit->committer = git__malloc(sizeof(git_person)); + if (git_person__parse(commit->committer, &buffer, buffer_end, "committer ") < 0) + return GIT_EOBJCORRUPTED; + + commit->commit_time = commit->committer->time; /* parse commit message */ while (buffer <= buffer_end && *buffer == '\n') @@ -329,9 +200,38 @@ int git_commit__parse_buffer(git_commit *commit, void *data, size_t len, unsigne return 0; } +int git_commit__parse(git_commit *commit) +{ + assert(commit && commit->object.source.open); + return commit_parse_buffer(commit, + commit->object.source.raw.data, commit->object.source.raw.len, COMMIT_BASIC_PARSE); +} + +int git_commit__parse_full(git_commit *commit) +{ + int error; + + if (commit->full_parse) + return 0; + + if (git_object__source_open((git_object *)commit) < 0) + return GIT_ERROR; + + error = commit_parse_buffer(commit, + commit->object.source.raw.data, commit->object.source.raw.len, COMMIT_FULL_PARSE); + + git_object__source_close((git_object *)commit); + + commit->full_parse = 1; + return error; +} + + + #define GIT_COMMIT_GETTER(_rvalue, _name) \ const _rvalue git_commit_##_name(git_commit *commit) \ {\ + assert(commit); \ if (commit->_name) \ return commit->_name; \ git_commit__parse_full(commit); \ @@ -346,6 +246,8 @@ GIT_COMMIT_GETTER(char *, message_short) time_t git_commit_time(git_commit *commit) { + assert(commit); + if (commit->commit_time) return commit->commit_time; @@ -355,26 +257,27 @@ time_t git_commit_time(git_commit *commit) void git_commit_set_tree(git_commit *commit, git_tree *tree) { + assert(commit && tree); commit->object.modified = 1; commit->tree = tree; } -void git_commit_set_author(git_commit *commit, const git_person *author) +void git_commit_set_author(git_commit *commit, const char *name, const char *email, time_t time) { + assert(commit && name && email); commit->object.modified = 1; - if (commit->author == NULL) - commit->author = git__malloc(sizeof(git_person)); - memcpy(commit->author, author, sizeof(git_person)); + git_person__free(commit->author); + commit->author = git_person__new(name, email, time); } -void git_commit_set_committer(git_commit *commit, const git_person *committer) +void git_commit_set_committer(git_commit *commit, const char *name, const char *email, time_t time) { + assert(commit && name && email); commit->object.modified = 1; - if (commit->committer == NULL) - commit->committer = git__malloc(sizeof(git_person)); - memcpy(commit->committer, committer, sizeof(git_person)); + git_person__free(commit->committer); + commit->committer = git_person__new(name, email, time); } void git_commit_set_message(git_commit *commit, const char *message) @@ -409,3 +312,4 @@ void git_commit_add_parent(git_commit *commit, git_commit *new_parent) commit->parents = node; } + |