aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libiberty/ChangeLog69
-rw-r--r--libiberty/argv.c33
-rwxr-xr-xlibiberty/configure4
-rw-r--r--libiberty/configure.ac4
-rw-r--r--libiberty/cp-demangle.c33
-rw-r--r--libiberty/lrealpath.c199
-rw-r--r--libiberty/make-temp-file.c1
-rw-r--r--libiberty/obstacks.texi4
-rw-r--r--libiberty/pex-win32.c93
-rw-r--r--libiberty/strstr.c15
-rw-r--r--libiberty/testsuite/demangle-expected30
11 files changed, 363 insertions, 122 deletions
diff --git a/libiberty/ChangeLog b/libiberty/ChangeLog
index 0e2289d..3424fef 100644
--- a/libiberty/ChangeLog
+++ b/libiberty/ChangeLog
@@ -1,3 +1,72 @@
+2023-06-15 Marek Polacek <polacek@redhat.com>
+
+ * configure.ac: Also set shared when enable_host_pie.
+ * configure: Regenerate.
+
+2023-06-13 Nathan Sidwell <nathan@acm.org>
+
+ * cp-demangle.c (d_print_conversion): Remove incorrect
+ template instantiation handling.
+ * testsuite/demangle-expected: Add testcases.
+
+2023-06-07 Costas Argyris <costas.argyris@gmail.com>
+
+ * argv.c (writeargv): Constant propagate "0" for "status",
+ simplifying the code slightly.
+
+2023-06-06 Costas Argyris <costas.argyris@gmail.com>
+
+ * argv.c (writeargv): Simplify & remove gotos.
+
+2023-06-05 Costas Argyris <costas.argyris@gmail.com>
+
+ * pex-win32.c: fix typos.
+
+2023-06-05 Costas Argyris <costas.argyris@gmail.com>
+
+ * pex-win32.c (win32_spawn): Check command line length
+ and generate a response file if necessary.
+ (spawn_script): Adjust parameters.
+ (pex_win32_exec_child): Ditto.
+
+2023-06-03 Patrick Palka <ppalka@redhat.com>
+
+ PR c++/70790
+ * cp-demangle.c (cplus_demangle_operators): Add the noexcept
+ operator.
+ (d_print_comp_inner) <case DEMANGLE_COMPONENT_UNARY>: Always
+ print parens around the operand of noexcept too.
+ * testsuite/demangle-expected: Test noexcept operator
+ demangling.
+
+2023-04-02 Jakub Jelinek <jakub@redhat.com>
+
+ PR other/109306
+ * strstr.c: Revert the 2020-11-13 changes.
+ (strstr): Return s1 if len is 0.
+
+2023-03-30 Gerald Pfeifer <gerald@pfeifer.com>
+
+ * obstacks.texi (Preparing for Obstacks): Remove a (broken)
+ reference to the Glibc manual.
+
+2023-03-03 Costas Argyris <costas.argyris@gmail.com>
+
+ * pex-win32.c (win32_spawn): Fix memory leak of cmdline
+ buffer and refactor to have cleanup code appear once
+ for all exit cases.
+
+2023-02-11 niXman <i.nixman@autistici.org>
+
+ * lrealpath.c (lrealpath): try to resolve symlink and
+ use UNC paths where applicable.
+
+2023-01-07 LIU Hao <lh_mouse@126.com>
+
+ PR middle-end/108300
+ * make-temp-file.c: Define `WIN32_LEAN_AND_MEAN` before <windows.h>.
+ * pex-win32.c: Likewise.
+
2022-11-23 Marek Polacek <polacek@redhat.com>
Revert:
diff --git a/libiberty/argv.c b/libiberty/argv.c
index a95a10e..c2823d3 100644
--- a/libiberty/argv.c
+++ b/libiberty/argv.c
@@ -289,8 +289,8 @@ char **buildargv (const char *input)
@deftypefn Extension int writeargv (char * const *@var{argv}, FILE *@var{file})
Write each member of ARGV, handling all necessary quoting, to the file
-named by FILE, separated by whitespace. Return 0 on success, non-zero
-if an error occurred while writing to FILE.
+associated with FILE, separated by whitespace. Return 0 on success,
+non-zero if an error occurred while writing to FILE.
@end deftypefn
@@ -299,8 +299,6 @@ if an error occurred while writing to FILE.
int
writeargv (char * const *argv, FILE *f)
{
- int status = 0;
-
if (f == NULL)
return 1;
@@ -314,37 +312,26 @@ writeargv (char * const *argv, FILE *f)
if (ISSPACE(c) || c == '\\' || c == '\'' || c == '"')
if (EOF == fputc ('\\', f))
- {
- status = 1;
- goto done;
- }
+ return 1;
if (EOF == fputc (c, f))
- {
- status = 1;
- goto done;
- }
+ return 1;
+
arg++;
}
/* Write out a pair of quotes for an empty argument. */
if (arg == *argv)
- if (EOF == fputs ("\"\"", f))
- {
- status = 1;
- goto done;
- }
+ if (EOF == fputs ("\"\"", f))
+ return 1;
if (EOF == fputc ('\n', f))
- {
- status = 1;
- goto done;
- }
+ return 1;
+
argv++;
}
- done:
- return status;
+ return 0;
}
/*
diff --git a/libiberty/configure b/libiberty/configure
index 1ccfac9..dd89627 100755
--- a/libiberty/configure
+++ b/libiberty/configure
@@ -5396,8 +5396,8 @@ case "${enable_shared}" in
*) shared=yes ;;
esac
-# ...unless --enable-host-shared was passed from top-level config:
-if [ "${enable_host_shared}" = "yes" ]; then
+# ...unless --enable-host-{shared,pie} was passed from top-level config:
+if [ "${enable_host_shared}" = "yes" ] || [ "${enable_host_pie}" = "yes" ]; then
shared=yes
fi
diff --git a/libiberty/configure.ac b/libiberty/configure.ac
index 6c1ff9c..0748c59 100644
--- a/libiberty/configure.ac
+++ b/libiberty/configure.ac
@@ -245,8 +245,8 @@ case "${enable_shared}" in
*) shared=yes ;;
esac
-# ...unless --enable-host-shared was passed from top-level config:
-if [[ "${enable_host_shared}" = "yes" ]]; then
+# ...unless --enable-host-{shared,pie} was passed from top-level config:
+if [[ "${enable_host_shared}" = "yes" ]] || [[ "${enable_host_pie}" = "yes" ]]; then
shared=yes
fi
diff --git a/libiberty/cp-demangle.c b/libiberty/cp-demangle.c
index f2b36bc..3bd303a 100644
--- a/libiberty/cp-demangle.c
+++ b/libiberty/cp-demangle.c
@@ -1947,6 +1947,7 @@ const struct demangle_operator_info cplus_demangle_operators[] =
{ "ng", NL ("-"), 1 },
{ "nt", NL ("!"), 1 },
{ "nw", NL ("new"), 3 },
+ { "nx", NL ("noexcept"), 1 },
{ "oR", NL ("|="), 2 },
{ "oo", NL ("||"), 2 },
{ "or", NL ("|"), 2 },
@@ -5836,8 +5837,8 @@ d_print_comp_inner (struct d_print_info *dpi, int options,
if (code && !strcmp (code, "gs"))
/* Avoid parens after '::'. */
d_print_comp (dpi, options, operand);
- else if (code && !strcmp (code, "st"))
- /* Always print parens for sizeof (type). */
+ else if (code && (!strcmp (code, "st") || !strcmp (code, "nx")))
+ /* Always print parens for sizeof (type) and noexcept(expr). */
{
d_append_char (dpi, '(');
d_print_comp (dpi, options, operand);
@@ -6659,32 +6660,10 @@ d_print_conversion (struct d_print_info *dpi, int options,
dpt.template_decl = dpi->current_template;
}
- if (d_left (dc)->type != DEMANGLE_COMPONENT_TEMPLATE)
- {
- d_print_comp (dpi, options, d_left (dc));
- if (dpi->current_template != NULL)
- dpi->templates = dpt.next;
- }
- else
- {
- d_print_comp (dpi, options, d_left (d_left (dc)));
-
- /* For a templated cast operator, we need to remove the template
- parameters from scope after printing the operator name,
- so we need to handle the template printing here. */
- if (dpi->current_template != NULL)
- dpi->templates = dpt.next;
+ d_print_comp (dpi, options, d_left (dc));
- if (d_last_char (dpi) == '<')
- d_append_char (dpi, ' ');
- d_append_char (dpi, '<');
- d_print_comp (dpi, options, d_right (d_left (dc)));
- /* Avoid generating two consecutive '>' characters, to avoid
- the C++ syntactic ambiguity. */
- if (d_last_char (dpi) == '>')
- d_append_char (dpi, ' ');
- d_append_char (dpi, '>');
- }
+ if (dpi->current_template != NULL)
+ dpi->templates = dpt.next;
}
/* Initialize the information structure we use to pass around
diff --git a/libiberty/lrealpath.c b/libiberty/lrealpath.c
index c662f8f..2578288 100644
--- a/libiberty/lrealpath.c
+++ b/libiberty/lrealpath.c
@@ -68,8 +68,135 @@ extern char *canonicalize_file_name (const char *);
/* cygwin has realpath, so it won't get here. */
# if defined (_WIN32)
# define WIN32_LEAN_AND_MEAN
-# include <windows.h> /* for GetFullPathName */
-# endif
+# include <windows.h> /* for GetFullPathName/GetFinalPathNameByHandle/
+ CreateFile/CloseHandle */
+# define WIN32_REPLACE_SLASHES(_ptr, _len) \
+ for (unsigned i = 0; i != (_len); ++i) \
+ if ((_ptr)[i] == '\\') (_ptr)[i] = '/';
+
+# define WIN32_UNC_PREFIX "//?/UNC/"
+# define WIN32_UNC_PREFIX_LEN (sizeof(WIN32_UNC_PREFIX)-1)
+# define WIN32_IS_UNC_PREFIX(ptr) \
+ (0 == memcmp(ptr, WIN32_UNC_PREFIX, WIN32_UNC_PREFIX_LEN))
+
+# define WIN32_NON_UNC_PREFIX "//?/"
+# define WIN32_NON_UNC_PREFIX_LEN (sizeof(WIN32_NON_UNC_PREFIX)-1)
+# define WIN32_IS_NON_UNC_PREFIX(ptr) \
+ (0 == memcmp(ptr, WIN32_NON_UNC_PREFIX, WIN32_NON_UNC_PREFIX_LEN))
+
+/* Get full path name without symlinks resolution.
+ It also converts all forward slashes to back slashes.
+*/
+char* get_full_path_name(const char *filename) {
+ DWORD len;
+ char *buf, *ptr, *res;
+
+ /* determining the required buffer size.
+ from the man: `If the lpBuffer buffer is too small to contain
+ the path, the return value is the size, in TCHARs, of the buffer
+ that is required to hold the path _and_the_terminating_null_character_`
+ */
+ len = GetFullPathName(filename, 0, NULL, NULL);
+
+ if ( len == 0 )
+ return strdup(filename);
+
+ buf = (char *)malloc(len);
+
+ /* no point to check the result again */
+ len = GetFullPathName(filename, len, buf, NULL);
+ buf[len] = 0;
+
+ /* replace slashes */
+ WIN32_REPLACE_SLASHES(buf, len);
+
+ /* calculate offset based on prefix type */
+ len = WIN32_IS_UNC_PREFIX(buf)
+ ? (WIN32_UNC_PREFIX_LEN - 2)
+ : WIN32_IS_NON_UNC_PREFIX(buf)
+ ? WIN32_NON_UNC_PREFIX_LEN
+ : 0
+ ;
+
+ ptr = buf + len;
+ if ( WIN32_IS_UNC_PREFIX(buf) ) {
+ ptr[0] = '/';
+ ptr[1] = '/';
+ }
+
+ res = strdup(ptr);
+
+ free(buf);
+
+ return res;
+}
+
+# if _WIN32_WINNT >= 0x0600
+
+/* Get full path name WITH symlinks resolution.
+ It also converts all forward slashes to back slashes.
+*/
+char* get_final_path_name(HANDLE fh) {
+ DWORD len;
+ char *buf, *ptr, *res;
+
+ /* determining the required buffer size.
+ from the man: `If the function fails because lpszFilePath is too
+ small to hold the string plus the terminating null character,
+ the return value is the required buffer size, in TCHARs. This
+ value _includes_the_size_of_the_terminating_null_character_`.
+ but in my testcase I have path with 26 chars, the function
+ returns 26 also, ie without the trailing zero-char...
+ */
+ len = GetFinalPathNameByHandle(
+ fh
+ ,NULL
+ ,0
+ ,FILE_NAME_NORMALIZED | VOLUME_NAME_DOS
+ );
+
+ if ( len == 0 )
+ return NULL;
+
+ len += 1; /* for zero-char */
+ buf = (char *)malloc(len);
+
+ /* no point to check the result again */
+ len = GetFinalPathNameByHandle(
+ fh
+ ,buf
+ ,len
+ ,FILE_NAME_NORMALIZED | VOLUME_NAME_DOS
+ );
+ buf[len] = 0;
+
+ /* replace slashes */
+ WIN32_REPLACE_SLASHES(buf, len);
+
+ /* calculate offset based on prefix type */
+ len = WIN32_IS_UNC_PREFIX(buf)
+ ? (WIN32_UNC_PREFIX_LEN - 2)
+ : WIN32_IS_NON_UNC_PREFIX(buf)
+ ? WIN32_NON_UNC_PREFIX_LEN
+ : 0
+ ;
+
+ ptr = buf + len;
+ if ( WIN32_IS_UNC_PREFIX(buf) ) {
+ ptr[0] = '/';
+ ptr[1] = '/';
+ }
+
+ res = strdup(ptr);
+
+ free(buf);
+
+ return res;
+}
+
+# endif // _WIN32_WINNT >= 0x0600
+
+# endif // _WIN32
#endif
char *
@@ -128,30 +255,52 @@ lrealpath (const char *filename)
}
#endif
- /* The MS Windows method. If we don't have realpath, we assume we
- don't have symlinks and just canonicalize to a Windows absolute
- path. GetFullPath converts ../ and ./ in relative paths to
- absolute paths, filling in current drive if one is not given
- or using the current directory of a specified drive (eg, "E:foo").
- It also converts all forward slashes to back slashes. */
+ /* The MS Windows method */
#if defined (_WIN32)
{
- char buf[MAX_PATH];
- char* basename;
- DWORD len = GetFullPathName (filename, MAX_PATH, buf, &basename);
- if (len == 0 || len > MAX_PATH - 1)
- return strdup (filename);
- else
- {
- /* The file system is case-preserving but case-insensitive,
- Canonicalize to lowercase, using the codepage associated
- with the process locale. */
- CharLowerBuff (buf, len);
- return strdup (buf);
- }
- }
-#endif
+ char *res;
+
+ /* For Windows Vista and greater */
+#if _WIN32_WINNT >= 0x0600
+
+ /* For some reason the function receives just empty `filename`, but not NULL.
+ What should we do in that case?
+ According to `strdup()` implementation
+ (https://elixir.bootlin.com/glibc/latest/source/string/strdup.c)
+ it will alloc 1 byte even for empty but non NULL string.
+ OK, will use `strdup()` for that case.
+ */
+ if ( 0 == strlen(filename) )
+ return strdup(filename);
+
+ HANDLE fh = CreateFile(
+ filename
+ ,FILE_READ_ATTRIBUTES
+ ,FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE
+ ,NULL
+ ,OPEN_EXISTING
+ ,FILE_FLAG_BACKUP_SEMANTICS
+ ,NULL
+ );
+
+ if ( fh == INVALID_HANDLE_VALUE ) {
+ res = get_full_path_name(filename);
+ } else {
+ res = get_final_path_name(fh);
+ CloseHandle(fh);
- /* This system is a lost cause, just duplicate the filename. */
- return strdup (filename);
+ if ( !res )
+ res = get_full_path_name(filename);
+ }
+
+#else
+
+ /* For Windows XP */
+ res = get_full_path_name(filename);
+
+#endif // _WIN32_WINNT >= 0x0600
+
+ return res;
+ }
+#endif // _WIN32
}
diff --git a/libiberty/make-temp-file.c b/libiberty/make-temp-file.c
index fae743f..1d2f21d 100644
--- a/libiberty/make-temp-file.c
+++ b/libiberty/make-temp-file.c
@@ -37,6 +37,7 @@ Boston, MA 02110-1301, USA. */
#include <sys/file.h> /* May get R_OK, etc. on some systems. */
#endif
#if defined(_WIN32) && !defined(__CYGWIN__)
+#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
#if HAVE_SYS_STAT_H
diff --git a/libiberty/obstacks.texi b/libiberty/obstacks.texi
index b2d2403..37d26c9 100644
--- a/libiberty/obstacks.texi
+++ b/libiberty/obstacks.texi
@@ -172,8 +172,8 @@ The value of this variable is a pointer to a function that
@code{obstack} uses when @code{obstack_chunk_alloc} fails to allocate
memory. The default action is to print a message and abort.
You should supply a function that either calls @code{exit}
-(@pxref{Program Termination, , , libc, The GNU C Library Reference Manual}) or @code{longjmp} (@pxref{Non-Local
-Exits, , , libc, The GNU C Library Reference Manual}) and doesn't return.
+(@pxref{Program Termination, , , libc, The GNU C Library Reference Manual})
+or @code{longjmp} and doesn't return.
@smallexample
void my_obstack_alloc_failed (void)
diff --git a/libiberty/pex-win32.c b/libiberty/pex-win32.c
index 5f6b420..f7fe306 100644
--- a/libiberty/pex-win32.c
+++ b/libiberty/pex-win32.c
@@ -20,6 +20,7 @@ Boston, MA 02110-1301, USA. */
#include "pex-common.h"
+#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#ifdef HAVE_STDLIB_H
@@ -350,7 +351,7 @@ argv_to_cmdline (char *const *argv)
prevent wasting 2 chars per argument of the CreateProcess 32k char
limit. We need only escape embedded double-quotes and immediately
preceeding backslash characters. A sequence of backslach characters
- that is not follwed by a double quote character will not be
+ that is not followed by a double quote character will not be
escaped. */
needs_quotes = 0;
for (j = 0; argv[i][j]; j++)
@@ -365,7 +366,7 @@ argv_to_cmdline (char *const *argv)
/* Escape preceeding backslashes. */
for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
cmdline_len++;
- /* Escape the qote character. */
+ /* Escape the quote character. */
cmdline_len++;
}
}
@@ -568,7 +569,8 @@ env_compare (const void *a_ptr, const void *b_ptr)
* target is not actually an executable, such as if it is a shell script. */
static pid_t
-win32_spawn (const char *executable,
+win32_spawn (struct pex_obj *obj,
+ const char *executable,
BOOL search,
char *const *argv,
char *const *env, /* array of strings of the form: VAR=VALUE */
@@ -576,14 +578,12 @@ win32_spawn (const char *executable,
LPSTARTUPINFO si,
LPPROCESS_INFORMATION pi)
{
- char *full_executable;
- char *cmdline;
+ char *full_executable = NULL;
+ char *cmdline = NULL;
+ pid_t pid = (pid_t) -1;
char **env_copy;
char *env_block = NULL;
- full_executable = NULL;
- cmdline = NULL;
-
if (env)
{
int env_size;
@@ -621,13 +621,42 @@ win32_spawn (const char *executable,
full_executable = find_executable (executable, search);
if (!full_executable)
- goto error;
+ goto exit;
cmdline = argv_to_cmdline (argv);
if (!cmdline)
- goto error;
-
- /* Create the child process. */
- if (!CreateProcess (full_executable, cmdline,
+ goto exit;
+ /* If cmdline is too large, CreateProcess will fail with a bad
+ 'No such file or directory' error. Try passing it through a
+ temporary response file instead. */
+ if (strlen (cmdline) > 32767)
+ {
+ char *response_file = make_temp_file ("");
+ /* Register the file for deletion by pex_free. */
+ ++obj->remove_count;
+ obj->remove = XRESIZEVEC (char *, obj->remove, obj->remove_count);
+ obj->remove[obj->remove_count - 1] = response_file;
+ int fd = pex_win32_open_write (obj, response_file, 0, 0);
+ if (fd == -1)
+ goto exit;
+ FILE *f = pex_win32_fdopenw (obj, fd, 0);
+ /* Don't write argv[0] (program name) to the response file. */
+ if (writeargv (&argv[1], f))
+ {
+ fclose (f);
+ goto exit;
+ }
+ fclose (f); /* Also closes fd and the underlying OS handle. */
+ char *response_arg = concat ("@", response_file, NULL);
+ char *response_argv[3] = {argv[0], response_arg, NULL};
+ free (cmdline);
+ cmdline = argv_to_cmdline (response_argv);
+ free (response_arg);
+ if (!cmdline)
+ goto exit;
+ }
+
+ /* Create the child process. */
+ if (CreateProcess (full_executable, cmdline,
/*lpProcessAttributes=*/NULL,
/*lpThreadAttributes=*/NULL,
/*bInheritHandles=*/TRUE,
@@ -637,33 +666,25 @@ win32_spawn (const char *executable,
si,
pi))
{
- free (env_block);
-
- free (full_executable);
-
- return (pid_t) -1;
+ CloseHandle (pi->hThread);
+ pid = (pid_t) pi->hProcess;
}
+ exit:
/* Clean up. */
- CloseHandle (pi->hThread);
- free (full_executable);
- free (env_block);
-
- return (pid_t) pi->hProcess;
-
- error:
free (env_block);
free (cmdline);
free (full_executable);
-
- return (pid_t) -1;
+
+ return pid;
}
/* Spawn a script. This simulates the Unix script execution mechanism.
This function is called as a fallback if win32_spawn fails. */
static pid_t
-spawn_script (const char *executable, char *const *argv,
+spawn_script (struct pex_obj *obj,
+ const char *executable, char *const *argv,
char* const *env,
DWORD dwCreationFlags,
LPSTARTUPINFO si,
@@ -713,20 +734,20 @@ spawn_script (const char *executable, char *const *argv,
executable = strrchr (executable1, '\\') + 1;
if (!executable)
executable = executable1;
- pid = win32_spawn (executable, TRUE, argv, env,
+ pid = win32_spawn (obj, executable, TRUE, argv, env,
dwCreationFlags, si, pi);
#else
if (strchr (executable1, '\\') == NULL)
- pid = win32_spawn (executable1, TRUE, argv, env,
+ pid = win32_spawn (obj, executable1, TRUE, argv, env,
dwCreationFlags, si, pi);
else if (executable1[0] != '\\')
- pid = win32_spawn (executable1, FALSE, argv, env,
+ pid = win32_spawn (obj, executable1, FALSE, argv, env,
dwCreationFlags, si, pi);
else
{
const char *newex = mingw_rootify (executable1);
*avhere = newex;
- pid = win32_spawn (newex, FALSE, argv, env,
+ pid = win32_spawn (obj, newex, FALSE, argv, env,
dwCreationFlags, si, pi);
if (executable1 != newex)
free ((char *) newex);
@@ -736,7 +757,7 @@ spawn_script (const char *executable, char *const *argv,
if (newex != executable1)
{
*avhere = newex;
- pid = win32_spawn (newex, FALSE, argv, env,
+ pid = win32_spawn (obj, newex, FALSE, argv, env,
dwCreationFlags, si, pi);
free ((char *) newex);
}
@@ -755,7 +776,7 @@ spawn_script (const char *executable, char *const *argv,
/* Execute a child. */
static pid_t
-pex_win32_exec_child (struct pex_obj *obj ATTRIBUTE_UNUSED, int flags,
+pex_win32_exec_child (struct pex_obj *obj, int flags,
const char *executable, char * const * argv,
char* const* env,
int in, int out, int errdes,
@@ -851,10 +872,10 @@ pex_win32_exec_child (struct pex_obj *obj ATTRIBUTE_UNUSED, int flags,
si.hStdError = stderr_handle;
/* Create the child process. */
- pid = win32_spawn (executable, (flags & PEX_SEARCH) != 0,
+ pid = win32_spawn (obj, executable, (flags & PEX_SEARCH) != 0,
argv, env, dwCreationFlags, &si, &pi);
if (pid == (pid_t) -1)
- pid = spawn_script (executable, argv, env, dwCreationFlags,
+ pid = spawn_script (obj, executable, argv, env, dwCreationFlags,
&si, &pi);
if (pid == (pid_t) -1)
{
diff --git a/libiberty/strstr.c b/libiberty/strstr.c
index c6f6849..49209e8 100644
--- a/libiberty/strstr.c
+++ b/libiberty/strstr.c
@@ -18,18 +18,23 @@ length, the function returns @var{string}.
#include <stddef.h>
-extern int memcmp (const void *, const void *, size_t);
+extern char *strchr (const char *, int);
+extern int strncmp (const void *, const void *, size_t);
extern size_t strlen (const char *);
char *
strstr (const char *s1, const char *s2)
{
+ const char *p = s1;
const size_t len = strlen (s2);
- while (*s1)
+
+ if (!len)
+ return s1;
+
+ for (; (p = strchr (p, *s2)) != 0; p++)
{
- if (!memcmp (s1, s2, len))
- return (char *)s1;
- ++s1;
+ if (strncmp (p, s2, len) == 0)
+ return (char *)p;
}
return (0);
}
diff --git a/libiberty/testsuite/demangle-expected b/libiberty/testsuite/demangle-expected
index d9bc7ed..0acd2d6 100644
--- a/libiberty/testsuite/demangle-expected
+++ b/libiberty/testsuite/demangle-expected
@@ -1659,3 +1659,33 @@ auto f()::{lambda<typename $T0>(X<$T0>*, X<int>*)#1}::operator()<char>(X<char>*,
_ZZN1XIiE1FEvENKUliE_clEi
X<int>::F()::{lambda(int)#1}::operator()(int) const
+
+_Z1fIiEv1AIXnxtlT_EEE
+void f<int>(A<noexcept(int{})>)
+
+_ZNO1Ycv1XEv
+Y::operator X() &&
+
+_ZNO1Ycv1XIT_EIvEEv
+Y::operator X<void><void>() &&
+
+_ZNO1Y3bobEv
+Y::bob() &&
+
+_ZNR1Y3bobEv
+Y::bob() &
+
+_ZNKR1YcvRK1XIT_EIvEEv
+Y::operator X<void> const&<void>() const &
+
+_ZZN1XIiEcviEvE1y
+X<int>::operator int()::y
+
+_ZZN1XIiEcv1ZIiEEvE1y
+X<int>::operator Z<int>()::y
+
+_ZZN1Xcv1ZIT_EIiEEvE1y
+X::operator Z<int><int>()::y
+
+_ZZN1XIfEcv1ZIT_EIiEEvE1y
+X<float>::operator Z<int><int>()::y