type_from_string_gently: make sure length matches
PATCH 1/1 type_from_string_gently: make sure length matches
When commit fe8e3b7 refactored type_from_string to allow input that was not NUL-terminated, it switched to using strncmp instead of strcmp. But this means we check only the first "len" bytes of the strings, and ignore any remaining bytes in the object_type_string. We should make sure that it is also "len" bytes, or else we would accept "comm" as "commit", and so forth.
---
Since the strings we are matching are literals, we could also record their sizes in the object_type_strings array and check the length first before even calling strncmp. I doubt this is a performance hot-spot, though.
You could also potentially just use strlen(object_type_strings[i]), but I'm not sure if compilers will optimize out the strlen in this case, since it is in a loop.
object.c | 3 ++- t/t1007-hash-object.sh | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-)
object.c +2 -1
@@ -41,7 +41,8 @@ int type_from_string_gently(const char *str, ssize_t len, int gentle) len =strlen (str);for (i =1 ; i <ARRAY_SIZE (object_type_strings); i++) -if (!strncmp (str, object_type_strings[i], len)) +if (!strncmp (str, object_type_strings[i], len) && + object_type_strings[i][len] =='\0' )return i;if (gentle)
t/t1007-hash-object.sh +8 -0
@@ -201,4 +201,12 @@ test_expect_success 'corrupt tag' ' test_must_fail git hash-object -t tag --stdin </dev/null ' +test_expect_success 'hash-object complains about bogus type name' ' + test_must_fail git hash-object -t bogus --stdin </dev/null +' + +test_expect_success 'hash-object complains about truncated type name' ' + test_must_fail git hash-object -t bl --stdin </dev/null +' + test_done
Signature · 1 line
2.4.0.rc2.384.g7297a4a
Quoted 15 lines · Jeff King
When commit fe8e3b7 refactored
type_from_stringto allow input that was not NUL-terminated, it switched to using strncmp instead of strcmp. But this means we check only the first "len" bytes of the strings, and ignore any remaining bytes in theobject_type_string. We should make sure that it is also "len" bytes, or else we would accept "comm" as "commit", and so forth.Signed-off-by Jeff King <[email protected]>---
Since the strings we are matching are literals, we could also record their sizes in theobject_type_stringsarray and check the length first before even calling strncmp. I doubt this is a performance hot-spot, though.
Quoted 3 lines
You could also potentially just use
strlen(object_type_strings[i]), but I'm not sure if compilers will optimize out the strlen in this case, since it is in a loop.
That thought crossed my mind while reading your patch. It could even make it go faster if we made object_type_strings into an array of counted strings (i.e. "struct { const char *str; int len; }") and then took advantage of the fact that we have lengths of both.
object.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-)
object.c +14 -10
@@ -18,19 +18,22 @@ struct object *get_indexed_object(unsigned int idx)return obj_hash[idx]; } -static const char *object_type_strings[] = { -NULL ,/* OBJ_NONE = 0 */ -"commit" ,/* OBJ_COMMIT = 1 */ -"tree" ,/* OBJ_TREE = 2 */ -"blob" ,/* OBJ_BLOB = 3 */ -"tag" ,/* OBJ_TAG = 4 */ +static struct { +const char *str; +int len; +} object_type_name[] = { + {NULL ,0 },/* OBJ_NONE = 0 */ + {"commit" ,6 },/* OBJ_COMMIT = 1 */ + {"tree" ,4 },/* OBJ_TREE = 2 */ + {"blob" ,4 },/* OBJ_BLOB = 3 */ + {"tag" ,3 },/* OBJ_TAG = 4 */ };const char *typename (unsigned int type) { -if (type >=ARRAY_SIZE (object_type_strings)) +if (type >=ARRAY_SIZE (object_type_name))return NULL ; -return object_type_strings[type]; +return object_type_name[type].str; }int type_from_string_gently (const char *str,ssize_t len,int gentle)
@@ -40,8 +43,9 @@ int type_from_string_gently(const char *str, ssize_t len, int gentle)if (len <0 ) len =strlen (str); -for (i =1 ; i <ARRAY_SIZE (object_type_strings); i++) -if (!strncmp (str, object_type_strings[i], len)) +for (i =1 ; i <ARRAY_SIZE (object_type_name); i++) +if (object_type_name[i].len == len && + !strncmp (str, object_type_name[i].str, len))return i;if (gentle)
Quoted 5 lines · Junio C Hamano
Quoted 5 lines
Since the strings we are matching are literals, we could also record their sizes in the
object_type_stringsarray and check the length first before even calling strncmp. I doubt this is a performance hot-spot, though.
Quoted 8 lines
Quoted 3 lines
You could also potentially just use
strlen(object_type_strings[i]), but I'm not sure if compilers will optimize out the strlen in this case, since it is in a loop.That thought crossed my mind while reading your patch. It could even make it go faster if we made
object_type_stringsinto an array of counted strings (i.e. "struct { const char *str; int len; }") and then took advantage of the fact that we have lengths of both.
Right, that was what I meant.
I'd be surprised if it appreciably speeds things up, but I guess it is not too complicated to do.
object.c struct object *get_indexed_object(unsigned int idx) · line 30
Quoted 10 lines
object.c +9
-0+static struct { +const char *str; +int len; +} object_type_name[] = { + {NULL ,0 },/* OBJ_NONE = 0 */ + {"commit" ,6 },/* OBJ_COMMIT = 1 */ + {"tree" ,4 },/* OBJ_TREE = 2 */ + {"blob" ,4 },/* OBJ_BLOB = 3 */ + {"tag" ,3 },/* OBJ_TAG = 4 */ };
I had envisioned a macro like:
#define SIZED_STRING(x) { (x), (sizeof(x) - 1) }though perhaps that is overkill for such a short list (that we don't even expect to change).
-Peff
Quoted 16 lines · Jeff King
I'd be surprised if it appreciably speeds things up, but I guess it is not too complicated to do.
object.c struct object *get_indexed_object(unsigned int idx) · line 30
Quoted 10 lines
object.c +9
-0+static struct { +const char *str; +int len; +} object_type_name[] = { + {NULL ,0 },/* OBJ_NONE = 0 */ + {"commit" ,6 },/* OBJ_COMMIT = 1 */ + {"tree" ,4 },/* OBJ_TREE = 2 */ + {"blob" ,4 },/* OBJ_BLOB = 3 */ + {"tag" ,3 },/* OBJ_TAG = 4 */ };I had envisioned a macro like:
Quoted 4 lines
#define SIZED_STRING(x) { (x), (sizeof(x) - 1) }though perhaps that is overkill for such a short list (that we don't even expect to change).
Sounds good (either way ;-)