Everywhere: Warn on function definitions without prototypes

If no header includes the prototype of a function, then it cannot be
used from outside the translation unit it was defined in. In that case,
it should be marked as `static`, in order to avoid possible ODR
problems, unnecessary exported symbols, and allow the compiler to better
optimize those.

If this warning triggers in a function defined in a header, `inline`
needs to be added, otherwise if the header is included in more than one
TU, it will fail to link with a duplicate definition error.

The reason this diff got so big is that Lagom-only code wasn't built
with this flag even in Serenity times.
This commit is contained in:
Daniel Bertalan 2024-07-14 18:29:33 +02:00
parent 7fe82a1cda
commit c62240aa80
Notes: sideshowbarker 2024-07-18 08:27:14 +09:00
24 changed files with 146 additions and 97 deletions

View file

@ -21,8 +21,8 @@ static constexpr bool TODO = false;
#define TODO_PPC64() VERIFY(TODO) /* NOLINT(cert-dcl03-c,misc-static-assert) No, this can't be static_assert, it's a runtime check */
#define TODO_PPC() VERIFY(TODO) /* NOLINT(cert-dcl03-c,misc-static-assert) No, this can't be static_assert, it's a runtime check */
#ifndef NDEBUG
extern "C" __attribute__((noreturn)) void ak_assertion_failed(char const*);
#ifndef NDEBUG
# define ASSERT(expr) \
(__builtin_expect(!(expr), 0) \
? ak_assertion_failed(#expr " at " __FILE__ ":" __stringify(__LINE__)) \

View file

@ -130,7 +130,7 @@ struct SignalHandlersInfo {
};
static Singleton<SignalHandlersInfo> s_signals;
SignalHandlersInfo* signals_info()
static SignalHandlersInfo* signals_info()
{
return s_signals.ptr();
}

View file

@ -94,7 +94,7 @@ struct SignalHandlersInfo {
};
static Singleton<SignalHandlersInfo> s_signals;
SignalHandlersInfo* signals_info()
static SignalHandlersInfo* signals_info()
{
return s_signals.ptr();
}

View file

@ -35,7 +35,7 @@ public slots:
void device_pixel_ratio_changed(qreal dpi);
private:
bool event(QEvent*) override;
virtual bool event(QEvent*) override;
void closeEvent(QCloseEvent*) override;
QScreen* m_current_screen;

View file

@ -42,7 +42,7 @@ public:
explicit TabBarButton(QIcon const& icon, QWidget* parent = nullptr);
protected:
bool event(QEvent* event);
virtual bool event(QEvent* event) override;
};
}

View file

@ -30,6 +30,8 @@
namespace Ladybird {
// FIXME: Find a place to put this declaration (and other helper functions).
bool is_using_dark_system_theme(QWidget&);
bool is_using_dark_system_theme(QWidget& widget)
{
// FIXME: Qt does not provide any method to query if the system is using a dark theme. We will have to implement

View file

@ -23,7 +23,7 @@
# include <LibCore/Platform/ProcessStatisticsMach.h>
#endif
ErrorOr<ByteString> find_certificates(StringView serenity_resource_root)
static ErrorOr<ByteString> find_certificates(StringView serenity_resource_root)
{
auto cert_path = ByteString::formatted("{}/ladybird/cacert.pem", serenity_resource_root);
if (!FileSystem::exists(cert_path))

View file

@ -22,6 +22,7 @@ endif()
add_compile_options(-Wcast-qual)
add_compile_options(-Wformat=2)
add_compile_options(-Wimplicit-fallthrough)
add_compile_options(-Wmissing-declarations)
add_compile_options(-Wsuggest-override)
add_compile_options(-Wno-invalid-offsetof)
@ -43,6 +44,8 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND NOT CMAKE_CXX_SIMULATE_ID MATCHES
# Clang's default constexpr-steps limit is 1048576(2^20), GCC doesn't have one
add_compile_options(-fconstexpr-steps=16777216)
add_compile_options(-Wmissing-prototypes)
add_compile_options(-Wno-implicit-const-int-float-conversion)
add_compile_options(-Wno-user-defined-literals)
add_compile_options(-Wno-vla-cxx-extension)

View file

@ -19,6 +19,12 @@ function(add_simple_fuzzer name)
target_sources(${name} PRIVATE "EntryShim.cpp")
target_link_libraries(${name} PUBLIC ${ARGN} AK LibCore)
endif()
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang$")
target_compile_options(${name} PRIVATE -Wno-missing-prototypes)
else()
target_compile_options(${name} PRIVATE -Wno-missing-declarations)
endif()
endfunction()
include(fuzzers.cmake)

View file

@ -24,6 +24,13 @@
#include <sys/stat.h>
#include <sys/types.h>
// These are hooks into sancov's internals, their declaration isn't available in public headers.
// See compiler-rt/lib/sanitizer_common/sanitizer_interface_internal.h
extern "C" {
void __sanitizer_cov_trace_pc_guard_init(uint32_t*, uint32_t*);
void __sanitizer_cov_trace_pc_guard(uint32_t*);
}
//
// BEGIN FUZZING CODE
//
@ -51,7 +58,7 @@ struct shmem_data {
struct shmem_data* __shmem;
uint32_t *__edges_start, *__edges_stop;
void __sanitizer_cov_reset_edgeguards()
static void __sanitizer_cov_reset_edgeguards()
{
uint64_t N = 0;
for (uint32_t* x = __edges_start; x < __edges_stop && N < MAX_EDGES; x++)

View file

@ -16,6 +16,7 @@
#include <ctype.h>
#include <stdio.h>
namespace {
struct Parameter {
Vector<ByteString> attributes;
ByteString type;
@ -823,6 +824,7 @@ void build(StringBuilder& builder, Vector<Endpoint> const& endpoints)
for (auto const& endpoint : endpoints)
build_endpoint(generator.fork(), endpoint);
}
} // end anonymous namespace
ErrorOr<int> serenity_main(Main::Arguments arguments)
{

View file

@ -15,6 +15,7 @@
#include <LibCore/File.h>
#include <LibMain/Main.h>
namespace {
struct LookupTable {
u32 first_pointer;
u32 max_code_point;
@ -175,6 +176,7 @@ namespace TextCodec {
TRY(file.write_until_depleted(generator.as_string_view().bytes()));
return {};
}
} // end anonymous namespace
ErrorOr<int> serenity_main(Main::Arguments arguments)
{

View file

@ -10,6 +10,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "IDLGenerators.h"
#include "Namespaces.h"
#include <AK/Array.h>
#include <AK/LexicalPath.h>
@ -17,10 +18,10 @@
#include <AK/QuickSort.h>
#include <LibIDL/Types.h>
Vector<StringView> s_header_search_paths;
namespace IDL {
Vector<StringView> g_header_search_paths;
// FIXME: Generate this automatically somehow.
static bool is_platform_object(Type const& type)
{
@ -284,7 +285,7 @@ static void generate_include_for(auto& generator, auto& path)
{
auto forked_generator = generator.fork();
auto path_string = path;
for (auto& search_path : s_header_search_paths) {
for (auto& search_path : g_header_search_paths) {
if (!path.starts_with(search_path))
continue;
auto relative_path = LexicalPath::relative_path(path, search_path);

View file

@ -0,0 +1,33 @@
/*
* Copyright (c) 2020-2023, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2021-2023, Linus Groh <linusg@serenityos.org>
* Copyright (c) 2021-2023, Luke Wilde <lukew@serenityos.org>
* Copyright (c) 2022, Ali Mohammad Pur <mpfard@serenityos.org>
* Copyright (c) 2023-2024, Kenneth Myhra <kennethmyhra@serenityos.org>
* Copyright (c) 2023-2024, Shannon Booth <shannon@serenityos.org>
* Copyright (c) 2023-2024, Matthew Olsson <mattco@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/StringBuilder.h>
#include <LibIDL/Types.h>
namespace IDL {
void generate_namespace_header(IDL::Interface const&, StringBuilder&);
void generate_namespace_implementation(IDL::Interface const&, StringBuilder&);
void generate_constructor_header(IDL::Interface const&, StringBuilder&);
void generate_constructor_implementation(IDL::Interface const&, StringBuilder&);
void generate_prototype_header(IDL::Interface const&, StringBuilder&);
void generate_prototype_implementation(IDL::Interface const&, StringBuilder&);
void generate_iterator_prototype_header(IDL::Interface const&, StringBuilder&);
void generate_iterator_prototype_implementation(IDL::Interface const&, StringBuilder&);
void generate_global_mixin_header(IDL::Interface const&, StringBuilder&);
void generate_global_mixin_implementation(IDL::Interface const&, StringBuilder&);
extern Vector<StringView> g_header_search_paths;
}

View file

@ -8,6 +8,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "IDLGenerators.h"
#include "Namespaces.h"
#include <AK/Debug.h>
#include <AK/LexicalPath.h>
@ -16,21 +17,6 @@
#include <LibIDL/IDLParser.h>
#include <LibIDL/Types.h>
extern Vector<StringView> s_header_search_paths;
namespace IDL {
void generate_namespace_header(IDL::Interface const&, StringBuilder&);
void generate_namespace_implementation(IDL::Interface const&, StringBuilder&);
void generate_constructor_header(IDL::Interface const&, StringBuilder&);
void generate_constructor_implementation(IDL::Interface const&, StringBuilder&);
void generate_prototype_header(IDL::Interface const&, StringBuilder&);
void generate_prototype_implementation(IDL::Interface const&, StringBuilder&);
void generate_iterator_prototype_header(IDL::Interface const&, StringBuilder&);
void generate_iterator_prototype_implementation(IDL::Interface const&, StringBuilder&);
void generate_global_mixin_header(IDL::Interface const&, StringBuilder&);
void generate_global_mixin_implementation(IDL::Interface const&, StringBuilder&);
}
ErrorOr<int> serenity_main(Main::Arguments arguments)
{
Core::ArgsParser args_parser;
@ -47,7 +33,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
.short_name = 'i',
.value_name = "path",
.accept_value = [&](StringView s) {
s_header_search_paths.append(s);
IDL::g_header_search_paths.append(s);
return true;
},
});

View file

@ -10,34 +10,7 @@
#include <LibCore/ArgsParser.h>
#include <LibMain/Main.h>
ErrorOr<void> generate_header_file(JsonObject& roles_data, Core::File& file);
ErrorOr<void> generate_implementation_file(JsonObject& roles_data, Core::File& file);
ErrorOr<int> serenity_main(Main::Arguments arguments)
{
StringView generated_header_path;
StringView generated_implementation_path;
StringView identifiers_json_path;
Core::ArgsParser args_parser;
args_parser.add_option(generated_header_path, "Path to the TransformFunctions header file to generate", "generated-header-path", 'h', "generated-header-path");
args_parser.add_option(generated_implementation_path, "Path to the TransformFunctions implementation file to generate", "generated-implementation-path", 'c', "generated-implementation-path");
args_parser.add_option(identifiers_json_path, "Path to the JSON file to read from", "json-path", 'j', "json-path");
args_parser.parse(arguments);
auto json = TRY(read_entire_file_as_json(identifiers_json_path));
VERIFY(json.is_object());
auto roles_data = json.as_object();
auto generated_header_file = TRY(Core::File::open(generated_header_path, Core::File::OpenMode::Write));
auto generated_implementation_file = TRY(Core::File::open(generated_implementation_path, Core::File::OpenMode::Write));
TRY(generate_header_file(roles_data, *generated_header_file));
TRY(generate_implementation_file(roles_data, *generated_implementation_file));
return 0;
}
namespace {
ErrorOr<void> generate_header_file(JsonObject& roles_data, Core::File& file)
{
StringBuilder builder;
@ -387,3 +360,29 @@ NameFromSource @name@::name_from_source() const
TRY(file.write_until_depleted(generator.as_string_view().bytes()));
return {};
}
} // end anonymous namespace
ErrorOr<int> serenity_main(Main::Arguments arguments)
{
StringView generated_header_path;
StringView generated_implementation_path;
StringView identifiers_json_path;
Core::ArgsParser args_parser;
args_parser.add_option(generated_header_path, "Path to the TransformFunctions header file to generate", "generated-header-path", 'h', "generated-header-path");
args_parser.add_option(generated_implementation_path, "Path to the TransformFunctions implementation file to generate", "generated-implementation-path", 'c', "generated-implementation-path");
args_parser.add_option(identifiers_json_path, "Path to the JSON file to read from", "json-path", 'j', "json-path");
args_parser.parse(arguments);
auto json = TRY(read_entire_file_as_json(identifiers_json_path));
VERIFY(json.is_object());
auto roles_data = json.as_object();
auto generated_header_file = TRY(Core::File::open(generated_header_path, Core::File::OpenMode::Write));
auto generated_implementation_file = TRY(Core::File::open(generated_implementation_path, Core::File::OpenMode::Write));
TRY(generate_header_file(roles_data, *generated_header_file));
TRY(generate_implementation_file(roles_data, *generated_implementation_file));
return 0;
}

View file

@ -10,34 +10,7 @@
#include <LibCore/ArgsParser.h>
#include <LibMain/Main.h>
ErrorOr<void> generate_header_file(JsonObject& functions_data, Core::File& file);
ErrorOr<void> generate_implementation_file(JsonObject& functions_data, Core::File& file);
ErrorOr<int> serenity_main(Main::Arguments arguments)
{
StringView generated_header_path;
StringView generated_implementation_path;
StringView identifiers_json_path;
Core::ArgsParser args_parser;
args_parser.add_option(generated_header_path, "Path to the MathFunctions header file to generate", "generated-header-path", 'h', "generated-header-path");
args_parser.add_option(generated_implementation_path, "Path to the MathFunctions implementation file to generate", "generated-implementation-path", 'c', "generated-implementation-path");
args_parser.add_option(identifiers_json_path, "Path to the JSON file to read from", "json-path", 'j', "json-path");
args_parser.parse(arguments);
auto json = TRY(read_entire_file_as_json(identifiers_json_path));
VERIFY(json.is_object());
auto math_functions_data = json.as_object();
auto generated_header_file = TRY(Core::File::open(generated_header_path, Core::File::OpenMode::Write));
auto generated_implementation_file = TRY(Core::File::open(generated_implementation_path, Core::File::OpenMode::Write));
TRY(generate_header_file(math_functions_data, *generated_header_file));
TRY(generate_implementation_file(math_functions_data, *generated_implementation_file));
return 0;
}
namespace {
ErrorOr<void> generate_header_file(JsonObject& functions_data, Core::File& file)
{
StringBuilder builder;
@ -378,3 +351,29 @@ OwnPtr<CalculationNode> Parser::parse_math_function(PropertyID property_id, Func
TRY(file.write_until_depleted(generator.as_string_view().bytes()));
return {};
}
} // end anonymous namespace
ErrorOr<int> serenity_main(Main::Arguments arguments)
{
StringView generated_header_path;
StringView generated_implementation_path;
StringView identifiers_json_path;
Core::ArgsParser args_parser;
args_parser.add_option(generated_header_path, "Path to the MathFunctions header file to generate", "generated-header-path", 'h', "generated-header-path");
args_parser.add_option(generated_implementation_path, "Path to the MathFunctions implementation file to generate", "generated-implementation-path", 'c', "generated-implementation-path");
args_parser.add_option(identifiers_json_path, "Path to the JSON file to read from", "json-path", 'j', "json-path");
args_parser.parse(arguments);
auto json = TRY(read_entire_file_as_json(identifiers_json_path));
VERIFY(json.is_object());
auto math_functions_data = json.as_object();
auto generated_header_file = TRY(Core::File::open(generated_header_path, Core::File::OpenMode::Write));
auto generated_implementation_file = TRY(Core::File::open(generated_implementation_path, Core::File::OpenMode::Write));
TRY(generate_header_file(math_functions_data, *generated_header_file));
TRY(generate_implementation_file(math_functions_data, *generated_implementation_file));
return 0;
}

View file

@ -13,7 +13,7 @@
#include <LibCore/File.h>
#include <ctype.h>
String title_casify(StringView dashy_name)
inline String title_casify(StringView dashy_name)
{
auto parts = dashy_name.split_view('-');
StringBuilder builder;
@ -28,7 +28,7 @@ String title_casify(StringView dashy_name)
return MUST(builder.to_string());
}
String camel_casify(StringView dashy_name)
inline String camel_casify(StringView dashy_name)
{
auto parts = dashy_name.split_view('-');
StringBuilder builder;
@ -49,14 +49,14 @@ String camel_casify(StringView dashy_name)
return MUST(builder.to_string());
}
String snake_casify(StringView dashy_name)
inline String snake_casify(StringView dashy_name)
{
// FIXME: We don't really need to convert dashy_name to a String first, but currently
// all the `replace` functions that take a StringView return ByteString.
return MUST(MUST(String::from_utf8(dashy_name)).replace("-"sv, "_"sv, ReplaceMode::All));
}
ErrorOr<JsonValue> read_entire_file_as_json(StringView filename)
inline ErrorOr<JsonValue> read_entire_file_as_json(StringView filename)
{
auto file = TRY(Core::File::open(filename, Core::File::OpenMode::Read));
auto json_size = TRY(file->size());

View file

@ -23,7 +23,6 @@
#include <LibJS/Runtime/ValueInlines.h>
#include <LibJS/Script.h>
#include <LibJS/SourceTextModule.h>
#include <assert.h>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
@ -544,7 +543,15 @@ static bool g_in_assert = false;
// FIXME: Use a SIGABRT handler here instead of overriding internal libc assertion handlers.
// Fixing this will likely require updating the test driver as well to pull the assertion failure
// message out of stderr rather than from the json object printed to stdout.
#ifdef ASSERT_FAIL_HAS_INT /* Set by CMake */
// FIXME: This likely doesn't even work with our custom ak_verification_failed handler
#pragma push_macro("NDEBUG")
// Apple headers do not expose the declaration of __assert_rtn when NDEBUG is set.
#undef NDEBUG
#include <assert.h>
#ifdef AK_OS_MACOS
extern "C" __attribute__((__noreturn__)) void __assert_rtn(char const* function, char const* file, int line, char const* assertion)
#elifdef ASSERT_FAIL_HAS_INT /* Set by CMake */
extern "C" __attribute__((__noreturn__)) void __assert_fail(char const* assertion, char const* file, int line, char const* function)
#else
extern "C" __attribute__((__noreturn__)) void __assert_fail(char const* assertion, char const* file, unsigned int line, char const* function)
@ -553,6 +560,7 @@ extern "C" __attribute__((__noreturn__)) void __assert_fail(char const* assertio
auto full_message = ByteString::formatted("{}:{}: {}: Assertion `{}' failed.", file, line, function, assertion);
handle_failed_assert(full_message.characters());
}
#pragma pop_macro("NDEBUG")
constexpr int exit_wrong_arguments = 2;
constexpr int exit_stdout_setup_failed = 1;

View file

@ -10,7 +10,7 @@
namespace Core {
ErrorOr<VkInstance> create_instance(uint32_t api_version)
static ErrorOr<VkInstance> create_instance(uint32_t api_version)
{
VkInstance instance;
@ -35,7 +35,7 @@ ErrorOr<VkInstance> create_instance(uint32_t api_version)
return instance;
}
ErrorOr<VkPhysicalDevice> pick_physical_device(VkInstance instance)
static ErrorOr<VkPhysicalDevice> pick_physical_device(VkInstance instance)
{
uint32_t device_count = 0;
vkEnumeratePhysicalDevices(instance, &device_count, nullptr);
@ -65,7 +65,7 @@ ErrorOr<VkPhysicalDevice> pick_physical_device(VkInstance instance)
VERIFY_NOT_REACHED();
}
ErrorOr<VkDevice> create_logical_device(VkPhysicalDevice physical_device)
static ErrorOr<VkDevice> create_logical_device(VkPhysicalDevice physical_device)
{
VkDevice device;

View file

@ -876,7 +876,7 @@ inline void fast_typed_array_set_element(TypedArrayBase& typed_array, u32 index,
*slot = value;
}
Completion throw_null_or_undefined_property_get(VM& vm, Value base_value, Optional<IdentifierTableIndex> base_identifier, IdentifierTableIndex property_identifier, Executable const& executable)
static Completion throw_null_or_undefined_property_get(VM& vm, Value base_value, Optional<IdentifierTableIndex> base_identifier, IdentifierTableIndex property_identifier, Executable const& executable)
{
VERIFY(base_value.is_nullish());
@ -885,7 +885,7 @@ Completion throw_null_or_undefined_property_get(VM& vm, Value base_value, Option
return vm.throw_completion<TypeError>(ErrorType::ToObjectNullOrUndefinedWithProperty, executable.get_identifier(property_identifier), base_value);
}
Completion throw_null_or_undefined_property_get(VM& vm, Value base_value, Optional<IdentifierTableIndex> base_identifier, Value property, Executable const& executable)
static Completion throw_null_or_undefined_property_get(VM& vm, Value base_value, Optional<IdentifierTableIndex> base_identifier, Value property, Executable const& executable)
{
VERIFY(base_value.is_nullish());

View file

@ -594,7 +594,7 @@ DOMTokenList* Element::class_list()
}
// https://dom.spec.whatwg.org/#valid-shadow-host-name
bool is_valid_shadow_host_name(FlyString const& name)
static bool is_valid_shadow_host_name(FlyString const& name)
{
// A valid shadow host name is:
// - a valid custom element name

View file

@ -839,7 +839,7 @@ CommandResult DisplayListPlayerSkia::fill_path_using_color(FillPathUsingColor co
return CommandResult::Continue;
}
SkTileMode to_skia_tile_mode(SVGLinearGradientPaintStyle::SpreadMethod spread_method)
static SkTileMode to_skia_tile_mode(SVGLinearGradientPaintStyle::SpreadMethod spread_method)
{
switch (spread_method) {
case SVGLinearGradientPaintStyle::SpreadMethod::Pad:
@ -853,7 +853,7 @@ SkTileMode to_skia_tile_mode(SVGLinearGradientPaintStyle::SpreadMethod spread_me
}
}
SkPaint paint_style_to_skia_paint(Painting::SVGGradientPaintStyle const& paint_style, Gfx::FloatRect bounding_rect)
static SkPaint paint_style_to_skia_paint(Painting::SVGGradientPaintStyle const& paint_style, Gfx::FloatRect bounding_rect)
{
SkPaint paint;

View file

@ -12,9 +12,10 @@ namespace Web::WebIDL {
extern bool g_enable_idl_tracing;
void log_trace_impl(JS::VM&, char const*);
inline void log_trace(JS::VM& vm, char const* function)
{
void log_trace_impl(JS::VM&, char const*);
if (g_enable_idl_tracing)
log_trace_impl(vm, function);
}