diff options
-rw-r--r-- | .github/workflows/main.yml | 4 | ||||
-rw-r--r-- | INSTALL | 4 | ||||
-rw-r--r-- | builtin/clone.c | 9 | ||||
-rwxr-xr-x | ci/install-dependencies.sh | 24 | ||||
-rwxr-xr-x | ci/lib.sh | 7 | ||||
-rw-r--r-- | compat/nedmalloc/nedmalloc.c | 1 | ||||
-rw-r--r-- | compat/win32/syslog.c | 2 | ||||
-rw-r--r-- | http-push.c | 8 | ||||
-rw-r--r-- | http.c | 105 | ||||
-rw-r--r-- | http.h | 8 | ||||
-rw-r--r-- | range-diff.c | 29 | ||||
-rw-r--r-- | remote-curl.c | 32 |
12 files changed, 149 insertions, 84 deletions
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a3fbbe6398..07f3ab3f8f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -282,7 +282,7 @@ jobs: pool: ubuntu-latest - jobname: linux-gcc cc: gcc - pool: ubuntu-latest + pool: ubuntu-20.04 - jobname: osx-clang cc: clang pool: macos-latest @@ -340,7 +340,7 @@ jobs: if: needs.ci-config.outputs.enabled == 'yes' env: jobname: StaticAnalysis - runs-on: ubuntu-18.04 + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v1 - run: ci/install-dependencies.sh @@ -145,6 +145,10 @@ Issues of note: patches into an IMAP mailbox, you do not have to have them (use NO_CURL). + Git requires version "7.19.5" or later of "libcurl" to build + without NO_CURL. This version requirement may be bumped in + the future. + - "expat" library; git-http-push uses it for remote lock management over DAV. Similar to "curl" above, this is optional (with NO_EXPAT). diff --git a/builtin/clone.c b/builtin/clone.c index c042b2e256..9ab17cab19 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -251,6 +251,15 @@ static char *guess_dir_name(const char *repo, int is_bundle, int is_bare) } /* + * It should not be possible to overflow `ptrdiff_t` by passing in an + * insanely long URL, but GCC does not know that and will complain + * without this check. + */ + if (end - start < 0) + die(_("No directory name could be guessed.\n" + "Please specify a directory on the command line")); + + /* * Strip trailing port number if we've got only a * hostname (that is, there is no dir separator but a * colon). This check is required such that we do not diff --git a/ci/install-dependencies.sh b/ci/install-dependencies.sh index 0b1184e04a..2d54427175 100755 --- a/ci/install-dependencies.sh +++ b/ci/install-dependencies.sh @@ -5,7 +5,7 @@ . ${0%/*}/lib.sh -P4WHENCE=http://filehost.perforce.com/perforce/r$LINUX_P4_VERSION +P4WHENCE=https://cdist2.perforce.com/perforce/r21.2 LFSWHENCE=https://github.com/github/git-lfs/releases/download/v$LINUX_GIT_LFS_VERSION UBUNTU_COMMON_PKGS="make libssl-dev libcurl4-openssl-dev libexpat-dev tcl tk gettext zlib1g-dev perl-modules liberror-perl libauthen-sasl-perl @@ -16,7 +16,7 @@ linux-clang|linux-gcc) sudo apt-add-repository -y "ppa:ubuntu-toolchain-r/test" sudo apt-get -q update sudo apt-get -q -y install language-pack-is libsvn-perl apache2 \ - $UBUNTU_COMMON_PKGS + $UBUNTU_COMMON_PKGS $PYTHON_PACKAGE case "$jobname" in linux-gcc) sudo apt-get -q -y install gcc-8 @@ -44,13 +44,15 @@ osx-clang|osx-gcc) test -z "$BREW_INSTALL_PACKAGES" || brew install $BREW_INSTALL_PACKAGES brew link --force gettext - brew install --cask --no-quarantine perforce || { - # Update the definitions and try again - cask_repo="$(brew --repository)"/Library/Taps/homebrew/homebrew-cask && - git -C "$cask_repo" pull --no-stat --ff-only && - brew install --cask --no-quarantine perforce - } || - brew install homebrew/cask/perforce + mkdir -p $HOME/bin + ( + cd $HOME/bin + wget -q "$P4WHENCE/bin.macosx1015x86_64/helix-core-server.tgz" && + tar -xf helix-core-server.tgz && + sudo xattr -d com.apple.quarantine p4 p4d 2>/dev/null || true + ) + PATH="$PATH:${HOME}/bin" + export PATH case "$jobname" in osx-gcc) brew install gcc@9 @@ -81,9 +83,9 @@ esac if type p4d >/dev/null && type p4 >/dev/null then echo "$(tput setaf 6)Perforce Server Version$(tput sgr0)" - p4d -V | grep Rev. + p4d -V echo "$(tput setaf 6)Perforce Client Version$(tput sgr0)" - p4 -V | grep Rev. + p4 -V fi if type git-lfs >/dev/null then @@ -184,13 +184,13 @@ export SKIP_DASHED_BUILT_INS=YesPlease case "$jobname" in linux-clang|linux-gcc) + PYTHON_PACKAGE=python2 if [ "$jobname" = linux-gcc ] then export CC=gcc-8 - MAKEFLAGS="$MAKEFLAGS PYTHON_PATH=/usr/bin/python3" - else - MAKEFLAGS="$MAKEFLAGS PYTHON_PATH=/usr/bin/python2" + PYTHON_PACKAGE=python3 fi + MAKEFLAGS="$MAKEFLAGS PYTHON_PATH=/usr/bin/$PYTHON_PACKAGE" export GIT_TEST_HTTPD=true @@ -199,7 +199,6 @@ linux-clang|linux-gcc) # were recorded in the Homebrew database upon creating the OS X # image. # Keep that in mind when you encounter a broken OS X build! - export LINUX_P4_VERSION="16.2" export LINUX_GIT_LFS_VERSION="1.5.2" P4_PATH="$HOME/custom/p4" diff --git a/compat/nedmalloc/nedmalloc.c b/compat/nedmalloc/nedmalloc.c index 1cc31c3502..141c30f07f 100644 --- a/compat/nedmalloc/nedmalloc.c +++ b/compat/nedmalloc/nedmalloc.c @@ -323,7 +323,6 @@ static NOINLINE void RemoveCacheEntries(nedpool *p, threadcache *tc, unsigned in } static void DestroyCaches(nedpool *p) THROWSPEC { - if(p->caches) { threadcache *tc; int n; diff --git a/compat/win32/syslog.c b/compat/win32/syslog.c index 161978d720..1f8d8934cc 100644 --- a/compat/win32/syslog.c +++ b/compat/win32/syslog.c @@ -43,6 +43,7 @@ void syslog(int priority, const char *fmt, ...) va_end(ap); while ((pos = strstr(str, "%1")) != NULL) { + size_t offset = pos - str; char *oldstr = str; str = realloc(str, st_add(++str_len, 1)); if (!str) { @@ -50,6 +51,7 @@ void syslog(int priority, const char *fmt, ...) warning_errno("realloc failed"); return; } + pos = str + offset; memmove(pos + 2, pos + 1, strlen(pos)); pos[1] = ' '; } diff --git a/http-push.c b/http-push.c index 6a4a43e07f..756779bb19 100644 --- a/http-push.c +++ b/http-push.c @@ -198,14 +198,14 @@ static void curl_setup_http(CURL *curl, const char *url, const char *custom_req, struct buffer *buffer, curl_write_callback write_fn) { - curl_easy_setopt(curl, CURLOPT_PUT, 1); + curl_easy_setopt(curl, CURLOPT_UPLOAD, 1); curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_INFILE, buffer); curl_easy_setopt(curl, CURLOPT_INFILESIZE, buffer->buf.len); curl_easy_setopt(curl, CURLOPT_READFUNCTION, fread_buffer); -#ifndef NO_CURL_IOCTL - curl_easy_setopt(curl, CURLOPT_IOCTLFUNCTION, ioctl_buffer); - curl_easy_setopt(curl, CURLOPT_IOCTLDATA, buffer); +#ifndef NO_CURL_SEEK + curl_easy_setopt(curl, CURLOPT_SEEKFUNCTION, seek_buffer); + curl_easy_setopt(curl, CURLOPT_SEEKDATA, buffer); #endif curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_fn); curl_easy_setopt(curl, CURLOPT_NOBODY, 0); @@ -186,22 +186,20 @@ size_t fread_buffer(char *ptr, size_t eltsize, size_t nmemb, void *buffer_) return size / eltsize; } -#ifndef NO_CURL_IOCTL -curlioerr ioctl_buffer(CURL *handle, int cmd, void *clientp) +#ifndef NO_CURL_SEEK +int seek_buffer(void *clientp, curl_off_t offset, int origin) { struct buffer *buffer = clientp; - switch (cmd) { - case CURLIOCMD_NOP: - return CURLIOE_OK; - - case CURLIOCMD_RESTARTREAD: - buffer->posn = 0; - return CURLIOE_OK; - - default: - return CURLIOE_UNKNOWNCMD; + if (origin != SEEK_SET) + BUG("seek_buffer only handles SEEK_SET"); + if (offset < 0 || offset >= buffer->buf.len) { + error("curl seek would be outside of buffer"); + return CURL_SEEKFUNC_FAIL; } + + buffer->posn = offset; + return CURL_SEEKFUNC_OK; } #endif @@ -810,20 +808,37 @@ void setup_curl_trace(CURL *handle) } #ifdef CURLPROTO_HTTP -static long get_curl_allowed_protocols(int from_user) +static void proto_list_append(struct strbuf *list, const char *proto) +{ + if (!list) + return; + if (list->len) + strbuf_addch(list, ','); + strbuf_addstr(list, proto); +} + +static long get_curl_allowed_protocols(int from_user, struct strbuf *list) { - long allowed_protocols = 0; + long bits = 0; - if (is_transport_allowed("http", from_user)) - allowed_protocols |= CURLPROTO_HTTP; - if (is_transport_allowed("https", from_user)) - allowed_protocols |= CURLPROTO_HTTPS; - if (is_transport_allowed("ftp", from_user)) - allowed_protocols |= CURLPROTO_FTP; - if (is_transport_allowed("ftps", from_user)) - allowed_protocols |= CURLPROTO_FTPS; + if (is_transport_allowed("http", from_user)) { + bits |= CURLPROTO_HTTP; + proto_list_append(list, "http"); + } + if (is_transport_allowed("https", from_user)) { + bits |= CURLPROTO_HTTPS; + proto_list_append(list, "https"); + } + if (is_transport_allowed("ftp", from_user)) { + bits |= CURLPROTO_FTP; + proto_list_append(list, "ftp"); + } + if (is_transport_allowed("ftps", from_user)) { + bits |= CURLPROTO_FTPS; + proto_list_append(list, "ftps"); + } - return allowed_protocols; + return bits; } #endif @@ -981,10 +996,24 @@ static CURL *get_curl_handle(void) curl_easy_setopt(result, CURLOPT_POST301, 1); #endif #ifdef CURLPROTO_HTTP +#if LIBCURL_VERSION_NUM >= 0x075500 + { + struct strbuf buf = STRBUF_INIT; + + get_curl_allowed_protocols(0, &buf); + curl_easy_setopt(result, CURLOPT_REDIR_PROTOCOLS_STR, buf.buf); + strbuf_reset(&buf); + + get_curl_allowed_protocols(-1, &buf); + curl_easy_setopt(result, CURLOPT_PROTOCOLS_STR, buf.buf); + strbuf_release(&buf); + } +#else curl_easy_setopt(result, CURLOPT_REDIR_PROTOCOLS, - get_curl_allowed_protocols(0)); + get_curl_allowed_protocols(0, NULL)); curl_easy_setopt(result, CURLOPT_PROTOCOLS, - get_curl_allowed_protocols(-1)); + get_curl_allowed_protocols(-1, NULL)); +#endif #else warning(_("Protocol restrictions not supported with cURL < 7.19.4")); #endif @@ -1523,6 +1552,32 @@ void run_active_slot(struct active_request_slot *slot) finish_active_slot(slot); } #endif + + /* + * The value of slot->finished we set before the loop was used + * to set our "finished" variable when our request completed. + * + * 1. The slot may not have been reused for another requst + * yet, in which case it still has &finished. + * + * 2. The slot may already be in-use to serve another request, + * which can further be divided into two cases: + * + * (a) If call run_active_slot() hasn't been called for that + * other request, slot->finished would have been cleared + * by get_active_slot() and has NULL. + * + * (b) If the request did call run_active_slot(), then the + * call would have updated slot->finished at the beginning + * of this function, and with the clearing of the member + * below, we would find that slot->finished is now NULL. + * + * In all cases, slot->finished has no useful information to + * anybody at this point. Some compilers warn us for + * attempting to smuggle a pointer that is about to become + * invalid, i.e. &finished. We clear it here to assure them. + */ + slot->finished = NULL; } static void release_active_slot(struct active_request_slot *slot) @@ -41,8 +41,8 @@ #define CURLE_HTTP_RETURNED_ERROR CURLE_HTTP_NOT_FOUND #endif -#if LIBCURL_VERSION_NUM < 0x070c03 -#define NO_CURL_IOCTL +#if LIBCURL_VERSION_NUM < 0x071200 +#define NO_CURL_SEEK #endif /* @@ -82,8 +82,8 @@ struct buffer { size_t fread_buffer(char *ptr, size_t eltsize, size_t nmemb, void *strbuf); size_t fwrite_buffer(char *ptr, size_t eltsize, size_t nmemb, void *strbuf); size_t fwrite_null(char *ptr, size_t eltsize, size_t nmemb, void *strbuf); -#ifndef NO_CURL_IOCTL -curlioerr ioctl_buffer(CURL *handle, int cmd, void *clientp); +#ifndef NO_CURL_SEEK +int seek_buffer(void *clientp, curl_off_t offset, int origin); #endif /* Slot lifecycle functions */ diff --git a/range-diff.c b/range-diff.c index b9950f10c8..9e2b788cdf 100644 --- a/range-diff.c +++ b/range-diff.c @@ -25,17 +25,6 @@ struct patch_util { struct object_id oid; }; -static size_t find_end_of_line(char *buffer, unsigned long size) -{ - char *eol = memchr(buffer, '\n', size); - - if (!eol) - return size; - - *eol = '\0'; - return eol + 1 - buffer; -} - /* * Reads the patches into a string list, with the `util` field being populated * as struct object_id (will need to be free()d). @@ -48,7 +37,7 @@ static int read_patches(const char *range, struct string_list *list, struct patch_util *util = NULL; int in_header = 1; char *line, *current_filename = NULL; - int offset, len; + ssize_t len; size_t size; strvec_pushl(&cp.args, "log", "--no-color", "-p", "--no-merges", @@ -83,11 +72,18 @@ static int read_patches(const char *range, struct string_list *list, line = contents.buf; size = contents.len; - for (offset = 0; size > 0; offset += len, size -= len, line += len) { + for (; size > 0; size -= len, line += len) { const char *p; + char *eol; + + eol = memchr(line, '\n', size); + if (eol) { + *eol = '\0'; + len = eol + 1 - line; + } else { + len = size; + } - len = find_end_of_line(line, size); - line[len - 1] = '\0'; if (skip_prefix(line, "commit ", &p)) { if (util) { string_list_append(list, buf.buf)->util = util; @@ -129,7 +125,8 @@ static int read_patches(const char *range, struct string_list *list, strbuf_addch(&buf, '\n'); if (!util->diff_offset) util->diff_offset = buf.len; - line[len - 1] = '\n'; + if (eol) + *eol = '\n'; orig_len = len; len = parse_git_diff_header(&root, &linenr, 0, line, len, size, &patch); diff --git a/remote-curl.c b/remote-curl.c index 0290b04891..f50531624a 100644 --- a/remote-curl.c +++ b/remote-curl.c @@ -707,26 +707,24 @@ static size_t rpc_out(void *ptr, size_t eltsize, return avail; } -#ifndef NO_CURL_IOCTL -static curlioerr rpc_ioctl(CURL *handle, int cmd, void *clientp) +#ifndef NO_CURL_SEEK +static int rpc_seek(void *clientp, curl_off_t offset, int origin) { struct rpc_state *rpc = clientp; - switch (cmd) { - case CURLIOCMD_NOP: - return CURLIOE_OK; + if (origin != SEEK_SET) + BUG("rpc_seek only handles SEEK_SET, not %d", origin); - case CURLIOCMD_RESTARTREAD: - if (rpc->initial_buffer) { - rpc->pos = 0; - return CURLIOE_OK; + if (rpc->initial_buffer) { + if (offset < 0 || offset > rpc->len) { + error("curl seek would be outside of rpc buffer"); + return CURL_SEEKFUNC_FAIL; } - error(_("unable to rewind rpc post data - try increasing http.postBuffer")); - return CURLIOE_FAILRESTART; - - default: - return CURLIOE_UNKNOWNCMD; + rpc->pos = offset; + return CURL_SEEKFUNC_OK; } + error(_("unable to rewind rpc post data - try increasing http.postBuffer")); + return CURL_SEEKFUNC_FAIL; } #endif @@ -947,9 +945,9 @@ retry: rpc->initial_buffer = 1; curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, rpc_out); curl_easy_setopt(slot->curl, CURLOPT_INFILE, rpc); -#ifndef NO_CURL_IOCTL - curl_easy_setopt(slot->curl, CURLOPT_IOCTLFUNCTION, rpc_ioctl); - curl_easy_setopt(slot->curl, CURLOPT_IOCTLDATA, rpc); +#ifndef NO_CURL_SEEK + curl_easy_setopt(slot->curl, CURLOPT_SEEKFUNCTION, rpc_seek); + curl_easy_setopt(slot->curl, CURLOPT_SEEKDATA, rpc); #endif if (options.verbosity > 1) { fprintf(stderr, "POST %s (chunked)\n", rpc->service_name); |