xmlNormalizeURIPath(char *path) {
 char *cur, *out;

 if (path == NULL)
 return(-1);

 /* Skip all initial "/" chars.  We want to get to the beginning of the
     * first non-empty segment.
     */
    cur = path;
 while (cur[0] == '/')
 ++cur;
 if (cur[0] == '\0')
 return(0);

 /* Keep everything we've seen so far.  */
    out = cur;

 /*
     * Analyze each segment in sequence for cases (c) and (d).
     */
 while (cur[0] != '\0') {
 /*
	 * c) All occurrences of "./", where "." is a complete path segment,
	 *    are removed from the buffer string.
	 */
 if ((cur[0] == '.') && (cur[1] == '/')) {
	    cur += 2;
 /* '//' normalization should be done at this point too */
 while (cur[0] == '/')
		cur++;
 continue;
 }

 /*
	 * d) If the buffer string ends with "." as a complete path segment,
	 *    that "." is removed.
	 */
 if ((cur[0] == '.') && (cur[1] == '\0'))
 break;

 /* Otherwise keep the segment.  */
 while (cur[0] != '/') {
 if (cur[0] == '\0')
 goto done_cd;
 (out++)[0] = (cur++)[0];
 }
 /* nomalize // */
 while ((cur[0] == '/') && (cur[1] == '/'))
	    cur++;

 (out++)[0] = (cur++)[0];
 }
 done_cd:
    out[0] = '\0';

 /* Reset to the beginning of the first segment for the next sequence.  */
    cur = path;
 while (cur[0] == '/')
 ++cur;
 if (cur[0] == '\0')
 return(0);

 /*
     * Analyze each segment in sequence for cases (e) and (f).
     *
     * e) All occurrences of "<segment>/../", where <segment> is a
     *    complete path segment not equal to "..", are removed from the
     *    buffer string.  Removal of these path segments is performed
     *    iteratively, removing the leftmost matching pattern on each
     *    iteration, until no matching pattern remains.
     *
     * f) If the buffer string ends with "<segment>/..", where <segment>
     *    is a complete path segment not equal to "..", that
     *    "<segment>/.." is removed.
     *
     * To satisfy the "iterative" clause in (e), we need to collapse the
     * string every time we find something that needs to be removed.  Thus,
     * we don't need to keep two pointers into the string: we only need a
     * "current position" pointer.
     */
 while (1) {
 char *segp, *tmp;

 /* At the beginning of each iteration of this loop, "cur" points to
         * the first character of the segment we want to examine.
         */

 /* Find the end of the current segment.  */
        segp = cur;
 while ((segp[0] != '/') && (segp[0] != '\0'))
 ++segp;

 /* If this is the last segment, we're done (we need at least two
         * segments to meet the criteria for the (e) and (f) cases).
         */
 if (segp[0] == '\0')
 break;

 /* If the first segment is "..", or if the next segment _isn't_ "..",
         * keep this segment and try the next one.
         */
 ++segp;
 if (((cur[0] == '.') && (cur[1] == '.') && (segp == cur+3))
 || ((segp[0] != '.') || (segp[1] != '.')
 || ((segp[2] != '/') && (segp[2] != '\0')))) {
          cur = segp;
 continue;
 }

 /* If we get here, remove this segment and the next one and back up
         * to the previous segment (if there is one), to implement the
         * "iteratively" clause.  It's pretty much impossible to back up
         * while maintaining two pointers into the buffer, so just compact
         * the whole buffer now.
         */

 /* If this is the end of the buffer, we're done.  */
 if (segp[2] == '\0') {
          cur[0] = '\0';
 break;
 }
 /* Valgrind complained, strcpy(cur, segp + 3); */
 /* string will overlap, do not use strcpy */
        tmp = cur;
        segp += 3;
 while ((*tmp++ = *segp++) != 0)
 ;

 /* If there are no previous segments, then keep going from here.  */
        segp = cur;
 while ((segp > path) && ((--segp)[0] == '/'))
 ;
 if (segp == path)
 continue;

 /* "segp" is pointing to the end of a previous segment; find it's
         * start.  We need to back up to the previous segment and start
         * over with that to handle things like "foo/bar/../..".  If we
         * don't do this, then on the first pass we'll remove the "bar/..",
         * but be pointing at the second ".." so we won't realize we can also
         * remove the "foo/..".
         */
        cur = segp;
 while ((cur > path) && (cur[-1] != '/'))
 --cur;
 }
    out[0] = '\0';

 /*
     * g) If the resulting buffer string still begins with one or more
     *    complete path segments of "..", then the reference is
     *    considered to be in error. Implementations may handle this
     *    error by retaining these components in the resolved path (i.e.,
     *    treating them as part of the final URI), by removing them from
     *    the resolved path (i.e., discarding relative levels above the
     *    root), or by avoiding traversal of the reference.
     *
     * We discard them from the final path.
     */
 if (path[0] == '/') {
      cur = path;
 while ((cur[0] == '/') && (cur[1] == '.') && (cur[2] == '.')
 && ((cur[3] == '/') || (cur[3] == '\0')))
	cur += 3;

 if (cur != path) {
	out = path;
 while (cur[0] != '\0')
 (out++)[0] = (cur++)[0];
	out[0] = 0;
 }
 }

 return(0);
}

The product performs operations on a memory buffer, but it reads from or writes to a memory location outside the buffer's intended boundary. This may result in read or write operations on unexpected memory locations that could be linked to other variables, data structures, or internal program data.