diff options
author | Peter Bindels <dascandy@gmail.com> | 2021-07-16 22:01:35 +0200 |
---|---|---|
committer | Gunnar Beutner <gunnar@beutner.name> | 2021-07-17 00:43:34 +0200 |
commit | 85c2ad94d513fece80a76f822aca31fe45e6c51d (patch) | |
tree | ad7dc5f2c477bf6c4a30caa8920370501d163646 /Userland | |
parent | 3cca9e670434cf4001012d3d41935df8f50604c5 (diff) | |
download | serenity-85c2ad94d513fece80a76f822aca31fe45e6c51d.zip |
LibC: Make scanf always copy its va_list
On x86_64 GCC implements va_list as an array. This makes the syntax
for taking a pointer to it break & crash. The workaround / solution is
to create a copy. Since va_list is a tiny struct referencing the
actual varargs, this is little overhead (especially compared to
va_args itself)
Diffstat (limited to 'Userland')
-rw-r--r-- | Userland/Libraries/LibC/scanf.cpp | 6 |
1 files changed, 5 insertions, 1 deletions
diff --git a/Userland/Libraries/LibC/scanf.cpp b/Userland/Libraries/LibC/scanf.cpp index ccdd63870c..cf46014eca 100644 --- a/Userland/Libraries/LibC/scanf.cpp +++ b/Userland/Libraries/LibC/scanf.cpp @@ -383,6 +383,9 @@ extern "C" int vsscanf(const char* input, const char* format, va_list ap) int elements_matched = 0; + va_list copy; + __builtin_va_copy(copy, ap); + while (!format_lexer.is_eof()) { format_lexer.ignore_while(isspace); if (!format_lexer.next_is('%')) { @@ -537,7 +540,7 @@ extern "C" int vsscanf(const char* input, const char* format, va_list ap) } } - auto* ap_or_null = !suppress_assignment ? (va_list*)&ap : nullptr; + auto* ap_or_null = !suppress_assignment ? (va_list*)© : nullptr; // Now try to read. switch (conversion_specifier) { @@ -616,6 +619,7 @@ extern "C" int vsscanf(const char* input, const char* format, va_list ap) } } } + va_end(copy); return elements_matched; } |