giada icon indicating copy to clipboard operation
giada copied to clipboard

fails to compile with format-security compiler flags

Open ghost opened this issue 3 years ago • 8 comments

Environment

  • OS: NixOS 20.05pre
  • Giada version: 0.17.1

Describe the bug I ran into the following error while compiling giada:

/build/source/src/utils/log.h:87:15: error: format not a string literal and no format arguments [8;;https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#index-Wformat-security-Werror=format-security8;;]
   87 |   std::fprintf(f, format, string_to_c_str(std::forward<Args>(args))...);
      |   ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/build/source/src/utils/log.h:93:14: error: format not a string literal and no format arguments [8;;https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#index-Wformat-security-Werror=format-security8;;]
   93 |   std::printf(format, string_to_c_str(std::forward<Args>(args))...);
      |   ~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

To Reproduce Steps to reproduce the behavior:

  1. Try to compile giada 0.17.1 with -Wformat-security -Werror=format-security

Expected behavior The program compiles

Screenshots N/A

Additional context I'm the maintainer of the NixOS giada package. I ran into this error while updating to 0.17.1 (from 0.16.x).

ghost avatar Feb 07 '21 12:02 ghost

Hi @petabyteboy , thanks for reporting. This is a kind of known issue after we C++17-ified the log function. I'll try to summon @keryell to see if we can suppress that warning.

gvnnz avatar Feb 08 '21 09:02 gvnnz

It is not obvious how to fix this because as the documentation pointed says:

-Wformat-security

If -Wformat is specified, also warn about uses of format functions that represent possible security problems. At present, this warns about calls to printf and scanf functions where the format string is not a string literal and there are no format arguments, as in printf (foo); This may be a security hole if the format string came from untrusted input and contains ‘%n’. (This is currently a subset of what -Wformat-nonliteral warns about, but in future warnings may be added to -Wformat-security that are not included in -Wformat-nonliteral.)

It is a "possible security problem" but I think it is a false positive. The real fix is to avoid using unsafe C printf at the first place since it is not type safe. I looked at how was the code before: there was a vfprintf(f, format, args); instead of a std::fprintf(), which is even less secure and even more difficult to statically analyze, so this is why I guess that g++ does not even dare to barf about it...

Can we avoid using this -Wformat-security here by removing it for the file or just this line with a #pragma? Otherwise removing the printf and use C++20 std::format? :-) Or calling explicitly vfprintf as before to be even more insecure but without a warning?

keryell avatar Feb 10 '21 02:02 keryell

Otherwise removing the printf and use C++20 std::format? :-)

This would be great, unfortunately we are not ready for the C++20 upgrade yet.

Or calling explicitly vfprintf as before to be even more insecure but without a warning?

Sounds like a good temporary trade-off to me...

gvnnz avatar Feb 19 '21 09:02 gvnnz

Fedora Linux also compiles with -Werror=format-security.

If you are confident this is a false positive, you can suppress the diagnostic with a GCC pragma. I think the compilers with -Wformat-security are mostly the same ones that implement GCC diagnostic pragmas.

diff -Naur giada-0.17.1-src-original/src/utils/log.h giada-0.17.1-src/src/utils/log.h
--- giada-0.17.1-src-original/src/utils/log.h	2021-02-01 12:41:42.000000000 -0500
+++ giada-0.17.1-src/src/utils/log.h	2021-02-19 15:59:03.741888609 -0500
@@ -84,6 +84,8 @@
 
 	if (mode == LOG_MODE_FILE && stat == true) {
 		// Replace any std::string in the arguments by its C-string
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-security"
 		std::fprintf(f, format, string_to_c_str(std::forward<Args>(args))...);
 #ifdef _WIN32
 		fflush(f);
@@ -91,6 +93,7 @@
 	}
 	else
 		std::printf(format, string_to_c_str(std::forward<Args>(args))...);
+#pragma GCC diagnostic pop
 }
 } // giada::u::log

musicinmybrain avatar Feb 23 '21 22:02 musicinmybrain

I have just modernized the code around the printf, but not enough to get rid of the printf completely unfortunately. There are already cleaner alternatives like https://github.com/gabime/spdlog so I do not think more developments here are valuable. The #pragma way is also understood by Clang in the meantime... https://clang.llvm.org/docs/UsersManual.html#controlling-diagnostics-via-pragmas

keryell avatar Feb 24 '21 00:02 keryell

On a second thought, better avoid trade-offs and fix this one with the proper std::format. Postponed to 1.0.

gvnnz avatar Mar 27 '21 17:03 gvnnz

Yes. And perhaps it is possible to write a small script to update most of the current log API to something more modern and adjust manually the remainers? Or dive into https://clang.llvm.org/extra/clang-tidy/ ? Look at "Using clang-tidy for customized checkers and large scale source tree refactoring - V. Bridger" on https://llvm.org/devmtg/2020-09/program/ if you are motivated. :-)

keryell avatar Mar 27 '21 21:03 keryell

Recently we added fmt as a new dependency, so we don't really need to wait for the official std::format support to fix this.

gvnnz avatar Jun 18 '22 14:06 gvnnz

Great!

keryell avatar Jun 08 '23 22:06 keryell