{"thread":{"id":"60505","subject":"[PATCH] fuzz: add new oss-fuzz fuzzer for date.c / date.h","startedAt":"2023-11-11T17:39:45Z","lastAt":"2023-11-17T17:47:51Z","messageCount":10,"participants":["Arthur Chan via GitGitGadget","Junio C Hamano","Jeff King"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"484764","messageId":"pull.1612.git.1699724379458.gitgitgadget@gmail.com","threadId":"60505","inReplyTo":null,"subject":"[PATCH] fuzz: add new oss-fuzz fuzzer for date.c / date.h","fromName":"Arthur Chan via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2023-11-11T17:39:39Z","receivedAt":"2023-11-11T17:39:45Z","isPatch":true,"sender":{"key":"arthur.chan@adalogics.com","avatar":"https://avatars.githubusercontent.com/u/33429318?v=4"},"body":"From: Arthur Chan <arthur.chan@adalogics.com>\n\nSigned-off-by: Arthur Chan <arthur.chan@adalogics.com>\n---\n    fuzz: add new oss-fuzz fuzzer for date.c / date.h\n    \n    This patch is aimed to add a new oss-fuzz fuzzer to the oss-fuzz\n    directory for fuzzing date.c / date.h in the base directory.\n    \n    The .gitignore of the oss-fuzz directory and the Makefile have been\n    modified to accommodate the new fuzzer fuzz-date.c.\n\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-1612%2Farthurscchan%2Fnew-fuzzer-date-v1\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1612/arthurscchan/new-fuzzer-date-v1\nPull-Request: https://github.com/gitgitgadget/git/pull/1612\n\n Makefile             |  1 +\n oss-fuzz/.gitignore  |  1 +\n oss-fuzz/fuzz-date.c | 75 ++++++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 77 insertions(+)\n create mode 100644 oss-fuzz/fuzz-date.c\n\ndiff --git a/Makefile b/Makefile\nindex 03adcb5a480..c9fe99a8c88 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -752,6 +752,7 @@ ETAGS_TARGET = TAGS\n FUZZ_OBJS += oss-fuzz/fuzz-commit-graph.o\n FUZZ_OBJS += oss-fuzz/fuzz-pack-headers.o\n FUZZ_OBJS += oss-fuzz/fuzz-pack-idx.o\n+FUZZ_OBJS += oss-fuzz/fuzz-date.o\n .PHONY: fuzz-objs\n fuzz-objs: $(FUZZ_OBJS)\n \ndiff --git a/oss-fuzz/.gitignore b/oss-fuzz/.gitignore\nindex 9acb74412ef..2375e77b108 100644\n--- a/oss-fuzz/.gitignore\n+++ b/oss-fuzz/.gitignore\n@@ -1,3 +1,4 @@\n fuzz-commit-graph\n fuzz-pack-headers\n fuzz-pack-idx\n+fuzz-date\ndiff --git a/oss-fuzz/fuzz-date.c b/oss-fuzz/fuzz-date.c\nnew file mode 100644\nindex 00000000000..29bcaf595e4\n--- /dev/null\n+++ b/oss-fuzz/fuzz-date.c\n@@ -0,0 +1,75 @@\n+#include \"git-compat-util.h\"\n+#include \"date.h\"\n+\n+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);\n+\n+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)\n+{\n+\tint type;\n+\tint time;\n+\tint num;\n+\tchar *str;\n+\ttimestamp_t ts;\n+\tenum date_mode_type dmtype;\n+\tstruct date_mode *dm;\n+\n+\tif (size <= 8)\n+\t{\n+\t\treturn 0;\n+\t}\n+\n+\ttype = (*((int *)data)) % 8;\n+\tdata += 4;\n+\tsize -= 4;\n+\n+\ttime = abs(*((int *)data));\n+\tdata += 4;\n+\tsize -= 4;\n+\n+\tstr = (char *)malloc(size+1);\n+\tif (!str)\n+\t{\n+\t\treturn 0;\n+\t}\n+\tmemcpy(str, data, size);\n+\tstr[size] = '\\0';\n+\n+\tts = approxidate_careful(str, &num);\n+\tfree(str);\n+\n+\tswitch(type)\n+\t{\n+\t\tcase 0: default:\n+\t\t\tdmtype = DATE_NORMAL;\n+\t\t\tbreak;\n+\t\tcase 1:\n+\t\t\tdmtype = DATE_HUMAN;\n+\t\t\tbreak;\n+\t\tcase 2:\n+\t\t\tdmtype = DATE_SHORT;\n+\t\t\tbreak;\n+\t\tcase 3:\n+\t\t\tdmtype = DATE_ISO8601;\n+\t\t\tbreak;\n+\t\tcase 4:\n+\t\t\tdmtype = DATE_ISO8601_STRICT;\n+\t\t\tbreak;\n+\t\tcase 5:\n+\t\t\tdmtype = DATE_RFC2822;\n+\t\t\tbreak;\n+\t\tcase 6:\n+\t\t\tdmtype = DATE_RAW;\n+\t\t\tbreak;\n+\t\tcase 7:\n+\t\t\tdmtype = DATE_UNIX;\n+\t\t\tbreak;\n+\t}\n+\n+\tdm = date_mode_from_type(dmtype);\n+\tdm->local = 1;\n+\tshow_date(ts, time, dm);\n+\n+\tdate_mode_release(dm);\n+\n+\treturn 0;\n+}\n\nbase-commit: dadef801b365989099a9929e995589e455c51fed\n-- \ngitgitgadget\n"},{"id":"484767","messageId":"xmqqfs1bo6l4.fsf@gitster.g","threadId":"60505","inReplyTo":"pull.1612.git.1699724379458.gitgitgadget@gmail.com","subject":"Re: [PATCH] fuzz: add new oss-fuzz fuzzer for date.c / date.h","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-11-12T05:59:03Z","receivedAt":"2023-11-12T05:59:11Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Arthur Chan via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n\n> diff --git a/Makefile b/Makefile\n> index 03adcb5a480..c9fe99a8c88 100644\n> --- a/Makefile\n> +++ b/Makefile\n> @@ -752,6 +752,7 @@ ETAGS_TARGET = TAGS\n>  FUZZ_OBJS += oss-fuzz/fuzz-commit-graph.o\n>  FUZZ_OBJS += oss-fuzz/fuzz-pack-headers.o\n>  FUZZ_OBJS += oss-fuzz/fuzz-pack-idx.o\n> +FUZZ_OBJS += oss-fuzz/fuzz-date.o\n\nThe same comment applies to .gitignore but I think the existing\nentries are sorted and fuzz-date should be added between\nfuzz-commit-graph and fuzz-pack-headers.\n\n> diff --git a/oss-fuzz/fuzz-date.c b/oss-fuzz/fuzz-date.c\n> new file mode 100644\n> index 00000000000..29bcaf595e4\n> --- /dev/null\n> +++ b/oss-fuzz/fuzz-date.c\n> @@ -0,0 +1,75 @@\n> +#include \"git-compat-util.h\"\n> +#include \"date.h\"\n> +\n> +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);\n> +\n> +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)\n> +{\n> +\tint type;\n> +\tint time;\n> +\tint num;\n> +\tchar *str;\n> +\ttimestamp_t ts;\n> +\tenum date_mode_type dmtype;\n> +\tstruct date_mode *dm;\n> +\n> +\tif (size <= 8)\n> +\t{\n> +\t\treturn 0;\n> +\t}\n\nHow much do we care about sticking to our coding style for source\nfiles in this directory?  If we do (and I do not see a strong reason\nnot to), let's lose the {unneeded braces} around a single statement\nblock.\n\n> +\ttype = (*((int *)data)) % 8;\n> +\tdata += 4;\n> +\tsize -= 4;\n\nI'd prefer to avoid these hardcoded and unexplained constants.  I\nthink \"8\" relates to the number of case arms below?  I am not sure\nif \"4\" is justifiable without \"we assume everybody's int is four\nbytes long\", but if that is what is going on, perhaps use uint32_t\nor something?\n\nAlso, is data[] guaranteed to be aligned well to allow us to do the\nabove?  As we only need to spread to DATE_UNIX-1 types (because we\nexclude DATE_STRFTIME), it is sufficient to look at the lower nibble\nof a single byte.  The upper nibble could be used to fuzz the .local\nbit if you wanted to, e.g. so I wonder\n\n\tlocal_bit = !!(*data & 0x10);\n\tdmtype = (enum date_mode_type)(*data % DATE_UNIX);\n\tif (dmtype == DATE_STRFTIME)\n\t\treturn 0;\n\tdata++;\n\tsize--;\n\n> +\ttime = abs(*((int *)data));\n> +\tdata += 4;\n> +\tsize -= 4;\n\nDitto.  Rename \"time\" because the second parameter to show_date() is\n*not* \"time\" but \"tz\".  The valid range of \"tz\" comfortably fits in\n16-bit signed int, but note that there are valid negative values in\nthe range.\n\nAre we assuming that the \"tz\" is attacker controlled?  Why are you\nlimiting its value to non-negative, yet you are not rejecting absurd\ntimezone offsets?  Good values lie in a range much narrower than\nbetween -2400 and 2400.  Subjecting \"tz\" to fuzzer is perfectly\nfine, but then limiting its value to non-negative contradicts with\nit, so I am not sure what your intention is.\n\nAs I used the first byte to fuzz dmtype and .local, let's use the\nnext three bytes to allow feeding overly wild timezone values to the\nmachinery and see what breaks, perhaps like so:\n\n\ttz = *data++; /* int tz; */\n\ttz = (tz << 8) | *data++;\n\ttz = (tz << 8) | *data++;\n\tsize -= 3;\n\nNow the upfront length check needs to reject any input shorter than\n4 bytes, so do so with a comment accordingly, perhaps like\n\n\tif (size < 4)\n\t\t/*\n                 * we use the first byte to fuzz dmtype and local,\n                 * then the next three bytes to fuzz tz\toffset,\n                 * and the remainder is fed as end-user input to\n\t\t * approxidate().\n\t\t */\n\t\treturn 0;\n\nbefore everything I wrote so far.\n\n> +\tstr = (char *)malloc(size+1);\n\n\t(char *)malloc(size + 1);\n\n> +\tif (!str)\n> +\t{\n> +\t\treturn 0;\n> +\t}\n\nDitto on {unnecessary braces}.\n\n> +\tmemcpy(str, data, size);\n> +\tstr[size] = '\\0';\n> +\n> +\tts = approxidate_careful(str, &num);\n> +\tfree(str);\n> +\n> +\tswitch(type)\n> +\t{\n> +\t\tcase 0: default:\n> +\t\t\tdmtype = DATE_NORMAL;\n> +\t\t\tbreak;\n\nStyle.  In our codebase, \"switch\" and \"case\" align at the same\ncolumn, and case arms are written one per line, i.e.,\n\n\tswitch (type) {\n\tcase 0:\n\tdefault:\n\t\t...\n\nThe way dmtype is handled in a switch() below tells me that you do\nnot consider it is a potential attack vector (e.g., an attacker\ncannot force us to use dmtype==DATE_STRFTIME without the format and\ncause us to die).  Am I reading your intention correctly?\n\nIf so, I'd just do the \"use the lower nibble of the first byte\" as I\nshown earlier, and this large switch statement will go away.\n\n> +\t\tcase 1:\n> +\t\t\tdmtype = DATE_HUMAN;\n> +\t\t\tbreak;\n> +\t\tcase 2:\n> +\t\t\tdmtype = DATE_SHORT;\n> +\t\t\tbreak;\n> +\t\tcase 3:\n> +\t\t\tdmtype = DATE_ISO8601;\n> +\t\t\tbreak;\n> +\t\tcase 4:\n> +\t\t\tdmtype = DATE_ISO8601_STRICT;\n> +\t\t\tbreak;\n> +\t\tcase 5:\n> +\t\t\tdmtype = DATE_RFC2822;\n> +\t\t\tbreak;\n> +\t\tcase 6:\n> +\t\t\tdmtype = DATE_RAW;\n> +\t\t\tbreak;\n> +\t\tcase 7:\n> +\t\t\tdmtype = DATE_UNIX;\n> +\t\t\tbreak;\n> +\t}\n> +\n> +\tdm = date_mode_from_type(dmtype);\n> +\tdm->local = 1;\n\nDon't we want to allow the incoming data to fuzz the local bit, too?\n\n> +\tshow_date(ts, time, dm);\n> +\n> +\tdate_mode_release(dm);\n> +\n> +\treturn 0;\n> +}\n>\n> base-commit: dadef801b365989099a9929e995589e455c51fed\n"},{"id":"484771","messageId":"xmqq7cmnno1n.fsf@gitster.g","threadId":"60505","inReplyTo":"xmqqfs1bo6l4.fsf@gitster.g","subject":"Re: [PATCH] fuzz: add new oss-fuzz fuzzer for date.c / date.h","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-11-12T12:39:32Z","receivedAt":"2023-11-12T12:39:38Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> As I used the first byte to fuzz dmtype and .local, let's use the\n> next three bytes to allow feeding overly wild timezone values to the\n> machinery and see what breaks, perhaps like so:\n>\n> \ttz = *data++; /* int tz; */\n> \ttz = (tz << 8) | *data++;\n> \ttz = (tz << 8) | *data++;\n> \tsize -= 3;\n\nJust this part.  As data points at unsigned char, the above would\nnot give us any negative number.  We'd need to sign-extend the\n24-bit resulting value if we are going to adopt the above approach.\n"},{"id":"484802","messageId":"pull.1612.v2.git.1699892568344.gitgitgadget@gmail.com","threadId":"60505","inReplyTo":"pull.1612.git.1699724379458.gitgitgadget@gmail.com","subject":"[PATCH v2] fuzz: add new oss-fuzz fuzzer for date.c / date.h","fromName":"Arthur Chan via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2023-11-13T16:22:48Z","receivedAt":"2023-11-13T16:22:56Z","isPatch":true,"sender":{"key":"arthur.chan@adalogics.com","avatar":"https://avatars.githubusercontent.com/u/33429318?v=4"},"body":"From: Arthur Chan <arthur.chan@adalogics.com>\n\nSigned-off-by: Arthur Chan <arthur.chan@adalogics.com>\n---\n    fuzz: add new oss-fuzz fuzzer for date.c / date.h\n    \n    This patch is aimed to add a new oss-fuzz fuzzer to the oss-fuzz\n    directory for fuzzing date.c / date.h in the base directory.\n    \n    The .gitignore of the oss-fuzz directory and the Makefile have been\n    modified to accommodate the new fuzzer fuzz-date.c.\n    \n    Fixed the objects order in .gitignore and Makefiles and fixed some of\n    the logic and formatting for the fuzz-date.c fuzzer in v2.\n\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-1612%2Farthurscchan%2Fnew-fuzzer-date-v2\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1612/arthurscchan/new-fuzzer-date-v2\nPull-Request: https://github.com/gitgitgadget/git/pull/1612\n\nRange-diff vs v1:\n\n 1:  d43724c19d0 ! 1:  2928e2b858d fuzz: add new oss-fuzz fuzzer for date.c / date.h\n     @@ Commit message\n          Signed-off-by: Arthur Chan <arthur.chan@adalogics.com>\n      \n       ## Makefile ##\n     -@@ Makefile: ETAGS_TARGET = TAGS\n     +@@ Makefile: SCRIPTS = $(SCRIPT_SH_GEN) \\\n     + ETAGS_TARGET = TAGS\n     + \n       FUZZ_OBJS += oss-fuzz/fuzz-commit-graph.o\n     ++FUZZ_OBJS += oss-fuzz/fuzz-date.o\n       FUZZ_OBJS += oss-fuzz/fuzz-pack-headers.o\n       FUZZ_OBJS += oss-fuzz/fuzz-pack-idx.o\n     -+FUZZ_OBJS += oss-fuzz/fuzz-date.o\n       .PHONY: fuzz-objs\n     - fuzz-objs: $(FUZZ_OBJS)\n     - \n      \n       ## oss-fuzz/.gitignore ##\n      @@\n       fuzz-commit-graph\n     ++fuzz-date\n       fuzz-pack-headers\n       fuzz-pack-idx\n     -+fuzz-date\n      \n       ## oss-fuzz/fuzz-date.c (new) ##\n      @@\n     @@ oss-fuzz/fuzz-date.c (new)\n      +\n      +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)\n      +{\n     -+\tint type;\n     -+\tint time;\n     ++\tint local;\n      +\tint num;\n     ++\tuint16_t tz;\n      +\tchar *str;\n      +\ttimestamp_t ts;\n      +\tenum date_mode_type dmtype;\n      +\tstruct date_mode *dm;\n      +\n     -+\tif (size <= 8)\n     -+\t{\n     ++\tif (size <= 4)\n     ++\t\t/*\n     ++\t\t * we use the first byte to fuzz dmtype and local,\n     ++\t\t * then the next three bytes to fuzz tz\toffset,\n     ++\t\t * and the remainder (at least one byte) is fed\n     ++\t\t * as end-user input to approxidate_careful().\n     ++\t\t */\n      +\t\treturn 0;\n     -+\t}\n      +\n     -+\ttype = (*((int *)data)) % 8;\n     -+\tdata += 4;\n     -+\tsize -= 4;\n     ++\tlocal = !!(*data & 0x10);\n     ++\tdmtype = (enum date_mode_type)(*data % DATE_UNIX);\n     ++\tif (dmtype == DATE_STRFTIME)\n     ++\t\t/*\n     ++\t\t * Currently DATE_STRFTIME is not supported.\n     ++\t\t */\n     ++\t\treturn 0;\n     ++\tdata++;\n     ++\tsize--;\n      +\n     -+\ttime = abs(*((int *)data));\n     -+\tdata += 4;\n     -+\tsize -= 4;\n     ++\ttz = *data++;\n     ++\ttz = (tz << 8) | *data++;\n     ++\ttz = (tz << 8) | *data++;\n     ++\tsize -= 3;\n      +\n     -+\tstr = (char *)malloc(size+1);\n     ++\tstr = (char *)malloc(size + 1);\n      +\tif (!str)\n     -+\t{\n      +\t\treturn 0;\n     -+\t}\n      +\tmemcpy(str, data, size);\n      +\tstr[size] = '\\0';\n      +\n      +\tts = approxidate_careful(str, &num);\n      +\tfree(str);\n      +\n     -+\tswitch(type)\n     -+\t{\n     -+\t\tcase 0: default:\n     -+\t\t\tdmtype = DATE_NORMAL;\n     -+\t\t\tbreak;\n     -+\t\tcase 1:\n     -+\t\t\tdmtype = DATE_HUMAN;\n     -+\t\t\tbreak;\n     -+\t\tcase 2:\n     -+\t\t\tdmtype = DATE_SHORT;\n     -+\t\t\tbreak;\n     -+\t\tcase 3:\n     -+\t\t\tdmtype = DATE_ISO8601;\n     -+\t\t\tbreak;\n     -+\t\tcase 4:\n     -+\t\t\tdmtype = DATE_ISO8601_STRICT;\n     -+\t\t\tbreak;\n     -+\t\tcase 5:\n     -+\t\t\tdmtype = DATE_RFC2822;\n     -+\t\t\tbreak;\n     -+\t\tcase 6:\n     -+\t\t\tdmtype = DATE_RAW;\n     -+\t\t\tbreak;\n     -+\t\tcase 7:\n     -+\t\t\tdmtype = DATE_UNIX;\n     -+\t\t\tbreak;\n     -+\t}\n     -+\n      +\tdm = date_mode_from_type(dmtype);\n     -+\tdm->local = 1;\n     -+\tshow_date(ts, time, dm);\n     ++\tdm->local = local;\n     ++\tshow_date(ts, (int16_t)tz, dm);\n      +\n      +\tdate_mode_release(dm);\n      +\n\n\n Makefile             |  1 +\n oss-fuzz/.gitignore  |  1 +\n oss-fuzz/fuzz-date.c | 56 ++++++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 58 insertions(+)\n create mode 100644 oss-fuzz/fuzz-date.c\n\ndiff --git a/Makefile b/Makefile\nindex 03adcb5a480..4b875ef6ce1 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -750,6 +750,7 @@ SCRIPTS = $(SCRIPT_SH_GEN) \\\n ETAGS_TARGET = TAGS\n \n FUZZ_OBJS += oss-fuzz/fuzz-commit-graph.o\n+FUZZ_OBJS += oss-fuzz/fuzz-date.o\n FUZZ_OBJS += oss-fuzz/fuzz-pack-headers.o\n FUZZ_OBJS += oss-fuzz/fuzz-pack-idx.o\n .PHONY: fuzz-objs\ndiff --git a/oss-fuzz/.gitignore b/oss-fuzz/.gitignore\nindex 9acb74412ef..5b954088254 100644\n--- a/oss-fuzz/.gitignore\n+++ b/oss-fuzz/.gitignore\n@@ -1,3 +1,4 @@\n fuzz-commit-graph\n+fuzz-date\n fuzz-pack-headers\n fuzz-pack-idx\ndiff --git a/oss-fuzz/fuzz-date.c b/oss-fuzz/fuzz-date.c\nnew file mode 100644\nindex 00000000000..a5c887bf11c\n--- /dev/null\n+++ b/oss-fuzz/fuzz-date.c\n@@ -0,0 +1,56 @@\n+#include \"git-compat-util.h\"\n+#include \"date.h\"\n+\n+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);\n+\n+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)\n+{\n+\tint local;\n+\tint num;\n+\tuint16_t tz;\n+\tchar *str;\n+\ttimestamp_t ts;\n+\tenum date_mode_type dmtype;\n+\tstruct date_mode *dm;\n+\n+\tif (size <= 4)\n+\t\t/*\n+\t\t * we use the first byte to fuzz dmtype and local,\n+\t\t * then the next three bytes to fuzz tz\toffset,\n+\t\t * and the remainder (at least one byte) is fed\n+\t\t * as end-user input to approxidate_careful().\n+\t\t */\n+\t\treturn 0;\n+\n+\tlocal = !!(*data & 0x10);\n+\tdmtype = (enum date_mode_type)(*data % DATE_UNIX);\n+\tif (dmtype == DATE_STRFTIME)\n+\t\t/*\n+\t\t * Currently DATE_STRFTIME is not supported.\n+\t\t */\n+\t\treturn 0;\n+\tdata++;\n+\tsize--;\n+\n+\ttz = *data++;\n+\ttz = (tz << 8) | *data++;\n+\ttz = (tz << 8) | *data++;\n+\tsize -= 3;\n+\n+\tstr = (char *)malloc(size + 1);\n+\tif (!str)\n+\t\treturn 0;\n+\tmemcpy(str, data, size);\n+\tstr[size] = '\\0';\n+\n+\tts = approxidate_careful(str, &num);\n+\tfree(str);\n+\n+\tdm = date_mode_from_type(dmtype);\n+\tdm->local = local;\n+\tshow_date(ts, (int16_t)tz, dm);\n+\n+\tdate_mode_release(dm);\n+\n+\treturn 0;\n+}\n\nbase-commit: dadef801b365989099a9929e995589e455c51fed\n-- \ngitgitgadget\n"},{"id":"484809","messageId":"20231113183509.GA3838361@coredump.intra.peff.net","threadId":"60505","inReplyTo":"pull.1612.v2.git.1699892568344.gitgitgadget@gmail.com","subject":"Re: [PATCH v2] fuzz: add new oss-fuzz fuzzer for date.c / date.h","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2023-11-13T18:35:09Z","receivedAt":"2023-11-13T18:35:15Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Nov 13, 2023 at 04:22:48PM +0000, Arthur Chan via GitGitGadget wrote:\n\n> +\tstr = (char *)malloc(size + 1);\n> +\tif (!str)\n> +\t\treturn 0;\n> +\tmemcpy(str, data, size);\n> +\tstr[size] = '\\0';\n\nIs it important that we avoid calling die() if the malloc fails here?\n\nThe usual way to write this in our code base is just:\n\n  str = xmemdupz(data, size);\n\nIt's not entirely a style thing; we sometimes audit the code base\nlooking for computations on malloc sizes (for integer overflows) as well\nas sites that should be using xmalloc and are not. Obviously we can\nexclude oss-fuzz/ from such audits, but if there's no reason not to\nprefer our usual style, it's one less thing to worry about.\n\n-Peff\n"},{"id":"484825","messageId":"xmqq4jhp5j4q.fsf@gitster.g","threadId":"60505","inReplyTo":"pull.1612.v2.git.1699892568344.gitgitgadget@gmail.com","subject":"Re: [PATCH v2] fuzz: add new oss-fuzz fuzzer for date.c / date.h","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-11-13T23:27:33Z","receivedAt":"2023-11-13T23:27:40Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Arthur Chan via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n\n> +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);\n\nIt is somewhat annoying that everybody has to repeat this twice\nhere, but it is not your fault X-<.\n\n> +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)\n> +{\n> +\tint local;\n> +\tint num;\n> +\tuint16_t tz;\n\ntz offset can be negative, so uint16_t is not appropriate.  See\ndate.c:gm_time_t() that is eventually called from show_date().\n\n> +\tchar *str;\n> +\ttimestamp_t ts;\n> +\tenum date_mode_type dmtype;\n> +\tstruct date_mode *dm;\n> +\n> +\tif (size <= 4)\n> +\t\t/*\n> +\t\t * we use the first byte to fuzz dmtype and local,\n> +\t\t * then the next three bytes to fuzz tz\toffset,\n> +\t\t * and the remainder (at least one byte) is fed\n> +\t\t * as end-user input to approxidate_careful().\n> +\t\t */\n> +\t\treturn 0;\n> +\n> +\tlocal = !!(*data & 0x10);\n> +\tdmtype = (enum date_mode_type)(*data % DATE_UNIX);\n> +\tif (dmtype == DATE_STRFTIME)\n> +\t\t/*\n> +\t\t * Currently DATE_STRFTIME is not supported.\n> +\t\t */\n> +\t\treturn 0;\n\nThere is an off-by-one error above, as modulo DATE_UNIX will never\nyield DATE_UNIX.  Presumably we could do something silly like\n\n\ttmp = *data % DATE_UNIX;\n\tif (DATE_STRFTIME <= tmp)\n\t\ttmp++;\n\tdmtime = (enum date_mode_type)tmp;\n\nto pick values from [0..DATE_UNIX) and then shift everything above\nDATE_STRFTIME by one to create a hole there and fill DATE_UNIX at\nthe same time, without wasting a sample by returning.\n\n> +\tdata++;\n> +\tsize--;\n> +\n> +\ttz = *data++;\n> +\ttz = (tz << 8) | *data++;\n> +\ttz = (tz << 8) | *data++;\n> +\tsize -= 3;\n\nIf your tz is 16-bit wide, then we do not have to eat three bytes\nhere, do we?\n\nYou never answered my question on your intention.  Is \"tz\"\nconsidered attacker controlled (and needs to be fuzzed including\ninvalid values)?\n\n> +\tstr = (char *)malloc(size + 1);\n> +\tif (!str)\n> +\t\treturn 0;\n> +\tmemcpy(str, data, size);\n> +\tstr[size] = '\\0';\n> +\n> +\tts = approxidate_careful(str, &num);\n> +\tfree(str);\n> +\n> +\tdm = date_mode_from_type(dmtype);\n> +\tdm->local = local;\n> +\tshow_date(ts, (int16_t)tz, dm);\n> +\n> +\tdate_mode_release(dm);\n> +\n> +\treturn 0;\n> +}\n>\n> base-commit: dadef801b365989099a9929e995589e455c51fed\n\nThanks.\n"},{"id":"484826","messageId":"xmqqzfzh44jw.fsf@gitster.g","threadId":"60505","inReplyTo":"20231113183509.GA3838361@coredump.intra.peff.net","subject":"Re: [PATCH v2] fuzz: add new oss-fuzz fuzzer for date.c / date.h","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-11-13T23:27:47Z","receivedAt":"2023-11-13T23:27:51Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> On Mon, Nov 13, 2023 at 04:22:48PM +0000, Arthur Chan via GitGitGadget wrote:\n>\n>> +\tstr = (char *)malloc(size + 1);\n>> +\tif (!str)\n>> +\t\treturn 0;\n>> +\tmemcpy(str, data, size);\n>> +\tstr[size] = '\\0';\n>\n> Is it important that we avoid calling die() if the malloc fails here?\n>\n> The usual way to write this in our code base is just:\n>\n>   str = xmemdupz(data, size);\n>\n> It's not entirely a style thing; we sometimes audit the code base\n> looking for computations on malloc sizes (for integer overflows) as well\n> as sites that should be using xmalloc and are not. Obviously we can\n> exclude oss-fuzz/ from such audits, but if there's no reason not to\n> prefer our usual style, it's one less thing to worry about.\n\nGood point.  Thanks.\n"},{"id":"484858","messageId":"pull.1612.v3.git.1699959186146.gitgitgadget@gmail.com","threadId":"60505","inReplyTo":"pull.1612.v2.git.1699892568344.gitgitgadget@gmail.com","subject":"[PATCH v3] fuzz: add new oss-fuzz fuzzer for date.c / date.h","fromName":"Arthur Chan via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2023-11-14T10:53:05Z","receivedAt":"2023-11-14T10:53:13Z","isPatch":true,"sender":{"key":"arthur.chan@adalogics.com","avatar":"https://avatars.githubusercontent.com/u/33429318?v=4"},"body":"From: Arthur Chan <arthur.chan@adalogics.com>\n\nSigned-off-by: Arthur Chan <arthur.chan@adalogics.com>\n---\n    fuzz: add new oss-fuzz fuzzer for date.c / date.h\n    \n    This patch is aimed to add a new oss-fuzz fuzzer to the oss-fuzz\n    directory for fuzzing date.c / date.h in the base directory.\n    \n    The .gitignore of the oss-fuzz directory and the Makefile have been\n    modified to accommodate the new fuzzer fuzz-date.c.\n    \n    Fixed the objects order in .gitignore and Makefiles and fixed some of\n    the logic and formatting for the fuzz-date.c fuzzer in v2.\n    \n    Fixed the creation and memory allocation of the fuzzing str in v3. Also\n    fixed the tz type and sign-extended the data before passing to the tz\n    variable.\n    \n    Comment: Yes, indeed. It is quite annoying to have that twice. Yes, the\n    tz should be considered as attacker controllable and thus negative\n    values should be considered. But it is tricky to fuzz it because the\n    date.c::gm_time_t() will call die() if the value is invalid and that\n    exit the fuzzer directly. OSS-Fuzz may consider it as an issue (or bug)\n    because the fuzzer exit \"unexpectedly\". I agree that if we consider the\n    tz as \"attacker controllable, we should include negative values, but\n    since it will cause the fuzzer exit, I am not sure if it is the right\n    approach from the fuzzing perspective. Also, it is something that date.c\n    already take care of with the conditional checking, thus it may also be\n    worth to do some checking and exclude some invalid values before calling\n    date.c::show_date() but this may result in copying some conditional\n    checking code from date.c.\n\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-1612%2Farthurscchan%2Fnew-fuzzer-date-v3\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1612/arthurscchan/new-fuzzer-date-v3\nPull-Request: https://github.com/gitgitgadget/git/pull/1612\n\nRange-diff vs v2:\n\n 1:  2928e2b858d ! 1:  046bca32889 fuzz: add new oss-fuzz fuzzer for date.c / date.h\n     @@ oss-fuzz/fuzz-date.c (new)\n      +{\n      +\tint local;\n      +\tint num;\n     -+\tuint16_t tz;\n     ++\tint tz;\n      +\tchar *str;\n     ++\tint8_t *tmp_data;\n      +\ttimestamp_t ts;\n      +\tenum date_mode_type dmtype;\n      +\tstruct date_mode *dm;\n     @@ oss-fuzz/fuzz-date.c (new)\n      +\t\treturn 0;\n      +\n      +\tlocal = !!(*data & 0x10);\n     -+\tdmtype = (enum date_mode_type)(*data % DATE_UNIX);\n     -+\tif (dmtype == DATE_STRFTIME)\n     -+\t\t/*\n     -+\t\t * Currently DATE_STRFTIME is not supported.\n     -+\t\t */\n     -+\t\treturn 0;\n     ++\tnum = *data % DATE_UNIX;\n     ++\tif (num >= DATE_STRFTIME)\n     ++\t\tnum++;\n     ++\tdmtype = (enum date_mode_type)num;\n      +\tdata++;\n      +\tsize--;\n      +\n     -+\ttz = *data++;\n     -+\ttz = (tz << 8) | *data++;\n     -+\ttz = (tz << 8) | *data++;\n     ++\ttmp_data = (int8_t*)data;\n     ++\ttz = *tmp_data++;\n     ++\ttz = (tz << 8) | *tmp_data++;\n     ++\ttz = (tz << 8) | *tmp_data++;\n     ++\tdata += 3;\n      +\tsize -= 3;\n      +\n     -+\tstr = (char *)malloc(size + 1);\n     -+\tif (!str)\n     -+\t\treturn 0;\n     -+\tmemcpy(str, data, size);\n     -+\tstr[size] = '\\0';\n     ++\tstr = xmemdupz(data, size);\n      +\n      +\tts = approxidate_careful(str, &num);\n      +\tfree(str);\n      +\n      +\tdm = date_mode_from_type(dmtype);\n      +\tdm->local = local;\n     -+\tshow_date(ts, (int16_t)tz, dm);\n     ++\tshow_date(ts, tz, dm);\n      +\n      +\tdate_mode_release(dm);\n      +\n\n\n Makefile             |  1 +\n oss-fuzz/.gitignore  |  1 +\n oss-fuzz/fuzz-date.c | 53 ++++++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 55 insertions(+)\n create mode 100644 oss-fuzz/fuzz-date.c\n\ndiff --git a/Makefile b/Makefile\nindex 03adcb5a480..4b875ef6ce1 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -750,6 +750,7 @@ SCRIPTS = $(SCRIPT_SH_GEN) \\\n ETAGS_TARGET = TAGS\n \n FUZZ_OBJS += oss-fuzz/fuzz-commit-graph.o\n+FUZZ_OBJS += oss-fuzz/fuzz-date.o\n FUZZ_OBJS += oss-fuzz/fuzz-pack-headers.o\n FUZZ_OBJS += oss-fuzz/fuzz-pack-idx.o\n .PHONY: fuzz-objs\ndiff --git a/oss-fuzz/.gitignore b/oss-fuzz/.gitignore\nindex 9acb74412ef..5b954088254 100644\n--- a/oss-fuzz/.gitignore\n+++ b/oss-fuzz/.gitignore\n@@ -1,3 +1,4 @@\n fuzz-commit-graph\n+fuzz-date\n fuzz-pack-headers\n fuzz-pack-idx\ndiff --git a/oss-fuzz/fuzz-date.c b/oss-fuzz/fuzz-date.c\nnew file mode 100644\nindex 00000000000..52bea5553a1\n--- /dev/null\n+++ b/oss-fuzz/fuzz-date.c\n@@ -0,0 +1,53 @@\n+#include \"git-compat-util.h\"\n+#include \"date.h\"\n+\n+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);\n+\n+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)\n+{\n+\tint local;\n+\tint num;\n+\tint tz;\n+\tchar *str;\n+\tint8_t *tmp_data;\n+\ttimestamp_t ts;\n+\tenum date_mode_type dmtype;\n+\tstruct date_mode *dm;\n+\n+\tif (size <= 4)\n+\t\t/*\n+\t\t * we use the first byte to fuzz dmtype and local,\n+\t\t * then the next three bytes to fuzz tz\toffset,\n+\t\t * and the remainder (at least one byte) is fed\n+\t\t * as end-user input to approxidate_careful().\n+\t\t */\n+\t\treturn 0;\n+\n+\tlocal = !!(*data & 0x10);\n+\tnum = *data % DATE_UNIX;\n+\tif (num >= DATE_STRFTIME)\n+\t\tnum++;\n+\tdmtype = (enum date_mode_type)num;\n+\tdata++;\n+\tsize--;\n+\n+\ttmp_data = (int8_t*)data;\n+\ttz = *tmp_data++;\n+\ttz = (tz << 8) | *tmp_data++;\n+\ttz = (tz << 8) | *tmp_data++;\n+\tdata += 3;\n+\tsize -= 3;\n+\n+\tstr = xmemdupz(data, size);\n+\n+\tts = approxidate_careful(str, &num);\n+\tfree(str);\n+\n+\tdm = date_mode_from_type(dmtype);\n+\tdm->local = local;\n+\tshow_date(ts, tz, dm);\n+\n+\tdate_mode_release(dm);\n+\n+\treturn 0;\n+}\n\nbase-commit: dadef801b365989099a9929e995589e455c51fed\n-- \ngitgitgadget\n"},{"id":"484866","messageId":"xmqqv8a4xo6g.fsf@gitster.g","threadId":"60505","inReplyTo":"pull.1612.v3.git.1699959186146.gitgitgadget@gmail.com","subject":"Re: [PATCH v3] fuzz: add new oss-fuzz fuzzer for date.c / date.h","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-11-14T17:03:19Z","receivedAt":"2023-11-14T17:03:24Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Arthur Chan via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n\n>      ++\ttmp_data = (int8_t*)data;\n>      ++\ttz = *tmp_data++;\n>      ++\ttz = (tz << 8) | *tmp_data++;\n>      ++\ttz = (tz << 8) | *tmp_data++;\n\nThis has a funny skew towards negative number.  Any time MSB of the\none of the three bytes is set, tz becomes negative.  Worse, a byte\ntaken from *tmp_data that has its MSB on will _wipe_ what was read\nin tz so far, because its higher order bits above 8th bit are sign\nextended.  If the incoming data is evenly distributed, 7/8 of the\ntime, you'd end up with a negative number in tz, no?\n\nI think you can and should pick bytes with uint8_t pointer to avoid\nsign extending individual bytes and sign extend the resulting number\nat the end.  Or if it is too cumbersome to do so, using \"int16_t tz\"\nand filling it with two bytes from *data will sign extend itself\nwhen we pass it to show_date() as a parameter of type \"int\", which\nmay be the easiest to code, I suspect.\n\nThanks.\n\n"},{"id":"484994","messageId":"pull.1612.v4.git.1700243267653.gitgitgadget@gmail.com","threadId":"60505","inReplyTo":"pull.1612.v3.git.1699959186146.gitgitgadget@gmail.com","subject":"[PATCH v4] fuzz: add new oss-fuzz fuzzer for date.c / date.h","fromName":"Arthur Chan via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2023-11-17T17:47:47Z","receivedAt":"2023-11-17T17:47:51Z","isPatch":true,"sender":{"key":"arthur.chan@adalogics.com","avatar":"https://avatars.githubusercontent.com/u/33429318?v=4"},"body":"From: Arthur Chan <arthur.chan@adalogics.com>\n\nSigned-off-by: Arthur Chan <arthur.chan@adalogics.com>\n---\n    fuzz: add new oss-fuzz fuzzer for date.c / date.h\n    \n    This patch is aimed to add a new oss-fuzz fuzzer to the oss-fuzz\n    directory for fuzzing date.c / date.h in the base directory.\n    \n    The .gitignore of the oss-fuzz directory and the Makefile have been\n    modified to accommodate the new fuzzer fuzz-date.c.\n    \n    Fixed the objects order in .gitignore and Makefiles and fixed some of\n    the logic and formatting for the fuzz-date.c fuzzer in v2.\n    \n    Fixed the creation and memory allocation of the fuzzing str in v3. Also\n    fixed the tz type and sign-extended the data before passing to the tz\n    variable.\n    \n    Fixed the tz variable allocations and some of the bytes used for fuzzing\n    variables in v4.\n    \n    Comment: Yes, indeed. It is quite annoying to have that twice. Yes, the\n    tz should be considered as attacker controllable and thus negative\n    values should be considered. But it is tricky to fuzz it because the\n    date.c::gm_time_t() will call die() if the value is invalid and that\n    exit the fuzzer directly. OSS-Fuzz may consider it as an issue (or bug)\n    because the fuzzer exit \"unexpectedly\". I agree that if we consider the\n    tz as \"attacker controllable, we should include negative values, but\n    since it will cause the fuzzer exit, I am not sure if it is the right\n    approach from the fuzzing perspective. Also, it is something that date.c\n    already take care of with the conditional checking, thus it may also be\n    worth to do some checking and exclude some invalid values before calling\n    date.c::show_date() but this may result in copying some conditional\n    checking code from date.c.\n    \n    Additional comment for v4: Thanks for the suggestion. Yes, that maybe\n    the easier approach. Since the new logic is only using 2 bytes for the\n    int16_t tz, thus the local and dmtype variable could use separate bytes\n    to increase \"randomness\".\n\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-1612%2Farthurscchan%2Fnew-fuzzer-date-v4\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1612/arthurscchan/new-fuzzer-date-v4\nPull-Request: https://github.com/gitgitgadget/git/pull/1612\n\nRange-diff vs v3:\n\n 1:  046bca32889 ! 1:  33a72d4c197 fuzz: add new oss-fuzz fuzzer for date.c / date.h\n     @@ oss-fuzz/fuzz-date.c (new)\n      +{\n      +\tint local;\n      +\tint num;\n     -+\tint tz;\n      +\tchar *str;\n     -+\tint8_t *tmp_data;\n     ++\tint16_t tz;\n      +\ttimestamp_t ts;\n      +\tenum date_mode_type dmtype;\n      +\tstruct date_mode *dm;\n      +\n      +\tif (size <= 4)\n      +\t\t/*\n     -+\t\t * we use the first byte to fuzz dmtype and local,\n     -+\t\t * then the next three bytes to fuzz tz\toffset,\n     -+\t\t * and the remainder (at least one byte) is fed\n     -+\t\t * as end-user input to approxidate_careful().\n     ++\t\t * we use the first byte to fuzz dmtype and the\n     ++\t\t * second byte to fuzz local, then the next two\n     ++\t\t * bytes to fuzz tz offset. The remainder\n     ++\t\t * (at least one byte) is fed as input to\n     ++\t\t * approxidate_careful().\n      +\t\t */\n      +\t\treturn 0;\n      +\n     -+\tlocal = !!(*data & 0x10);\n     -+\tnum = *data % DATE_UNIX;\n     ++\tlocal = !!(*data++ & 0x10);\n     ++\tnum = *data++ % DATE_UNIX;\n      +\tif (num >= DATE_STRFTIME)\n      +\t\tnum++;\n      +\tdmtype = (enum date_mode_type)num;\n     -+\tdata++;\n     -+\tsize--;\n     ++\tsize -= 2;\n      +\n     -+\ttmp_data = (int8_t*)data;\n     -+\ttz = *tmp_data++;\n     -+\ttz = (tz << 8) | *tmp_data++;\n     -+\ttz = (tz << 8) | *tmp_data++;\n     -+\tdata += 3;\n     -+\tsize -= 3;\n     ++\ttz = *data++;\n     ++\ttz = (tz << 8) | *data++;\n     ++\tsize -= 2;\n      +\n      +\tstr = xmemdupz(data, size);\n      +\n     @@ oss-fuzz/fuzz-date.c (new)\n      +\n      +\tdm = date_mode_from_type(dmtype);\n      +\tdm->local = local;\n     -+\tshow_date(ts, tz, dm);\n     ++\tshow_date(ts, (int)tz, dm);\n      +\n      +\tdate_mode_release(dm);\n      +\n\n\n Makefile             |  1 +\n oss-fuzz/.gitignore  |  1 +\n oss-fuzz/fuzz-date.c | 49 ++++++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 51 insertions(+)\n create mode 100644 oss-fuzz/fuzz-date.c\n\ndiff --git a/Makefile b/Makefile\nindex 03adcb5a480..4b875ef6ce1 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -750,6 +750,7 @@ SCRIPTS = $(SCRIPT_SH_GEN) \\\n ETAGS_TARGET = TAGS\n \n FUZZ_OBJS += oss-fuzz/fuzz-commit-graph.o\n+FUZZ_OBJS += oss-fuzz/fuzz-date.o\n FUZZ_OBJS += oss-fuzz/fuzz-pack-headers.o\n FUZZ_OBJS += oss-fuzz/fuzz-pack-idx.o\n .PHONY: fuzz-objs\ndiff --git a/oss-fuzz/.gitignore b/oss-fuzz/.gitignore\nindex 9acb74412ef..5b954088254 100644\n--- a/oss-fuzz/.gitignore\n+++ b/oss-fuzz/.gitignore\n@@ -1,3 +1,4 @@\n fuzz-commit-graph\n+fuzz-date\n fuzz-pack-headers\n fuzz-pack-idx\ndiff --git a/oss-fuzz/fuzz-date.c b/oss-fuzz/fuzz-date.c\nnew file mode 100644\nindex 00000000000..036378b946f\n--- /dev/null\n+++ b/oss-fuzz/fuzz-date.c\n@@ -0,0 +1,49 @@\n+#include \"git-compat-util.h\"\n+#include \"date.h\"\n+\n+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);\n+\n+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)\n+{\n+\tint local;\n+\tint num;\n+\tchar *str;\n+\tint16_t tz;\n+\ttimestamp_t ts;\n+\tenum date_mode_type dmtype;\n+\tstruct date_mode *dm;\n+\n+\tif (size <= 4)\n+\t\t/*\n+\t\t * we use the first byte to fuzz dmtype and the\n+\t\t * second byte to fuzz local, then the next two\n+\t\t * bytes to fuzz tz offset. The remainder\n+\t\t * (at least one byte) is fed as input to\n+\t\t * approxidate_careful().\n+\t\t */\n+\t\treturn 0;\n+\n+\tlocal = !!(*data++ & 0x10);\n+\tnum = *data++ % DATE_UNIX;\n+\tif (num >= DATE_STRFTIME)\n+\t\tnum++;\n+\tdmtype = (enum date_mode_type)num;\n+\tsize -= 2;\n+\n+\ttz = *data++;\n+\ttz = (tz << 8) | *data++;\n+\tsize -= 2;\n+\n+\tstr = xmemdupz(data, size);\n+\n+\tts = approxidate_careful(str, &num);\n+\tfree(str);\n+\n+\tdm = date_mode_from_type(dmtype);\n+\tdm->local = local;\n+\tshow_date(ts, (int)tz, dm);\n+\n+\tdate_mode_release(dm);\n+\n+\treturn 0;\n+}\n\nbase-commit: dadef801b365989099a9929e995589e455c51fed\n-- \ngitgitgadget\n"}]}