Showing posts with label clang_flags. Show all posts
Showing posts with label clang_flags. Show all posts

Dec 15, 2025

[C++] [CppCon 2025] Implement the C++ Standard Library minute

Reference:

Implement the C++ Standard Library: Design, Optimisations, Testing while Implementing Libc++
[C++] Object Lifetimes reading minute

1)

1) tail padding.
2) if type is empty, it does not acquire address.

e.g.
struct Foo {
  int a; // 4
  char c; // 1 
  bool b; // 1
  // +2
};

enum class ErrCode : int {
 E1, E2, E3,
};

template<typename Val, Err>
struct Expected {
  union U {
  	[[no_unique_address]] Val val_;
	[[no_unique_address]] Err err_;
  };
  [[no_unique_address]] U value_;
  bool has_value_; 
};
Without `no_unique_address`, no tail padding,
sizeof(Expected<Foo, ErrCode>) == 12

With `no_unique_address`, 
bool has_value_;
can sneak into
U if U is of type Foo, `has_value_` would occupy Foo's tail padding,
thus:
sizeof(Expected<Foo, ErrCode>) == 8


2)

template<typename Val, Err>
struct Expected {
  union U {
  	[[no_unique_address]] Val val_;
	[[no_unique_address]] Err err_;
  };
  [[no_unique_address]] U value_;
  bool has_value_; 
  
  Expected(const Expected& other) :
  	has_value{other.has_value} {
	 if (has_value_) {
	 	std::construct_at(std::addressof(value_.val_), other.value_.val_);
	 } else {
	 	std::construct_at(std::addressof(value_.err_), other.value_.err_);
	 }
	}
};

Expected e1 = {Foo{}, true};
Expected e2 = e1;
assert(e2.has_value_); // Failed.
Why failed? Due to std::construct_at construct the value_ union's val_ and
zero out the padding, which has_value_ resides in due to `no_unique_address`.

Take away:

Don't mix no_unique_address with manual lifetime management
(union, construct_at, placement-new, std::bit_cast, std::start_lifetime_as, std::start_lifetime_as_array).


3)

Reference:
Segmented Iterators and Hierarchical Algorithms - Matthew H. Austern
https://lafstern.org/matt/segmented.pdf
Which is faster?
std::deque<int> d = ...

// 1
for (int& i : d) {
    i = std::clamp(i, 200, 500);
}

// 2 Faster due to using Segmented Iterators
std::ranges::for_each(d, [](int& i) {
    i = std::clamp(i, 200, 500);
});

Segmented Iterators:

template <class T> struct seg_array_iter
{
    // Local Iterator: position within the current segment (e.g., a vector<T>::iterator)
    vector<T>::iterator cur;
    
    // Segment Iterator: position among the segments (e.g., a vector<vector<T>*>::iterator)
    vector<vector<T>*>::iterator node;

    T& operator*() const { return *cur; }

    seg_array_iter& operator++() {
        // Standard increment: move to the next element in the current segment
        if (++cur == (**node).end()) {
            // End of segment reached: move to the next segment
            ++node;
            // Set the local iterator (cur) to the beginning of the new segment
            // or 0 (a null pointer equivalent for iterators) if it's the end.
            cur = *node ? (**node).begin() : 0;
        }
        return *this;
    }
    // ... other iterator operations like operator==, operator!=, etc.
};

template <class Iter, class T>
inline void fill (Iter first, Iter last, const T& x)
{
    typedef segmented_iterator_traits<Iter> Traits;
    
    // Dispatch call: The compiler chooses the segmented or nonsegmented helper 
    // based on the type of Traits::is_segmented_iterator (true_type or false_type).
    fill(first, last, x,
         typename Traits::is_segmented_iterator()); 
}

template <class SegIter, class T>
void fill (SegIter first, SegIter last, const T& x, true_type)
{
    typedef segmented_iterator_traits<SegIter> traits;

    // Decompose the full segmented iterators into segment and local iterators
    typename traits::segment_iterator sfirst = traits::segment (first);
    typename traits::segment_iterator slast = traits::segment (last);

    if (sfirst == slast) {
        // Case 1: Start and end are in the same segment. Use one local fill.
        fill(traits::local (first), traits::local (last), x);
    } else {
        // Case 2: Fill the *rest* of the starting segment
        fill(traits::local (first), traits::end(sfirst), x);

        // Case 3: Loop through all *middle* segments, filling them completely
        for (++sfirst; sfirst != slast; ++sfirst)
            fill(traits::begin(sfirst), traits::end(sfirst), x);

        // Case 4: Fill the *start* of the ending segment (sfirst now equals slast)
        fill(traits::begin(sfirst), traits::local (last), x);
    }
} 

Take away:

  • Use the most precise API for what you're trying to achieve.
    • insert_range instead of insert in a loop. (O(n) vs. N * log(M) )
    • use sorted_unique if the inputs are already sorted.
  • Use library facilities (e.g. views::zip) to benefit from concept-based optimizations.


4)

compiler flag
-Xclang -verify used for static_asserts
e.g.
clang++ -Xclang -verify -fsyntax-only test_integer_only.cpp

#include <type_traits>

template <typename T>
void strict_int_check() {
    static_assert(std::is_integral<T>::value, "Type must be an integer!");
}

void test() {
    // This line is valid, so no comment needed.
    strict_int_check<int>();

    // We WANT this line to fail. 
    // Without -verify, this breaks the build.
    // With -verify, Clang checks if the error matches the regex in {{...}}.
    strict_int_check<double>(); // expected-error {{Type must be an integer!}}
}

Apr 29, 2025

[clang] --system-header-prefix flag

Controlling Diagnostics in System Headers

Assign --system-header-prefix flag to indicate what are system headers, thus the warnings

emit from those headers are ignored.

Its main purpose is to instruct the compiler to treat header files located in directories matching a specified prefix as "system headers."

Key Functionality

When a header file is designated as a system header, compilers like Clang typically suppress warnings that originate from within that header. This behavior is desirable because:

  • Third-Party Libraries: Developers often use external libraries with their own header files. These headers might generate warnings with the project's specific compiler settings, but the project developer cannot or should not modify these library headers.
  • Standard Library and OS Headers: Headers from the C++ Standard Library, C Standard Library, or the operating system itself are inherently system-level. Warnings from these are generally not actionable by the application developer.
  • Reduced Noise: Suppressing these warnings allows developers to focus on issues within their own codebase.





#pragma clang enable-system-header-diagnostics

Sep 9, 2021

[C++] Safer Usage Of C++ note

Reference:
Safer Usage Of C++

CLang user manual:

https://clang.llvm.org/docs/UsersManual.html

https://clang.llvm.org/docs/ClangCommandLineReference.html


Enable flags:

-fno-exceptions
-ftrapv
-fwrapv
fsanitize=signed-integer-overflow
-Wdangling-gsl

-fno-delete-null-pointer-checks (named as such for historical reasons) that defines null pointer dereferences. With this flag, dereferences of null are never optimized away.


MiraclePtr:

https://youtu.be/ohlxw5kDn-k

https://docs.google.com/presentation/d/1QvfZXx5HdUl0IdkBcrx-NM0ua-PVcTi2jNx0Sf-n8Fo/edit#slide=id.gab22a695b8_0_1


scpptool 

is a command line tool to help enforce a memory and data race safe subset of C++. 

https://github.com/duneroadrunner/scpptool


"SaferCPlusPlus" is essentially a collection of safe data types intended to facilitate memory and data race safe C++ programming.

https://github.com/duneroadrunner/SaferCPlusPlus

https://github.com/duneroadrunner/SaferCPlusPlus-AutoTranslation2


StarScan

Heap scanning use-after-free prevention

https://source.chromium.org/chromium/chromium/src/+/master:base/allocator/partition_allocator/starscan/README.md


MiraclePtr aka raw_ptr aka BackupRefPtr

https://chromium.googlesource.com/chromium/src/+/ddc017f9569973a731a574be4199d8400616f5a5/base/memory/raw_ptr.md


Pointer Safety Ideas

https://docs.google.com/document/d/1qsPh8Bcrma7S-5fobbCkBkXWaAijXOnorEqvIIGKzc0/edit#


P1705R1

Enumerating Core Undefined Behavior

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1705r1.html


Automatic Reference Counting

https://en.wikipedia.org/wiki/Automatic_Reference_Counting


Blink GC API reference

https://chromium.googlesource.com/chromium/src/+/refs/heads/main/third_party/blink/renderer/platform/heap/BlinkGCAPIReference.md

https://docs.google.com/presentation/d/1XPu03ymz8W295mCftEC9KshH9Icxfq81YwIJQzQrvxo/edit#slide=id.p


2 basic types of memory safety

spatial:

The program will behave in a defined and safe way if it accesses memory outside valid bounds.

Examples include array bounds, struct and union field access, and iterator access.


temporal:

The program will behave in a defined and safe way if it accesses memory when that memory is not valid at the time of the access.

Examples include use after free (UAF), double-free, use before initialization, and use after move (UAM).


[[clang::lifetimebound]] 

https://clang.llvm.org/docs/AttributeReference.html#lifetimebound


ABSL

Use absl::variant Instead Of enums for state machines


May 7, 2019

[C++] -Wredundant-move && -Wpessimizing-move

2 flags for compiling(both clang++ / g++ support these flags) as well as vimrc usage :-)

-Wpessimizing-move
-Wredundant-move

Those 2 flags become quite useful in C++17 since the standard makes RVO mandatory.

Oct 11, 2018

[C++][Cppcon 2017] Louis Brandy: Curiously Recurring C++ Bugs at Facebook

CppCon 2017: Louis Brandy “Curiously Recurring C++ Bugs at Facebook”

Some wisdom extracted from writing production code..


ASan:
https://github.com/google/sanitizers


Bug 1:
std::vector::operator[]

1. No boundary check is performed (FAST)
2. Returns a reference

code:
--
return v[102];  // out of boundary.
--

mitigation:
  • Static analysis. Complicated, Hard, Expensive.
  • Improved abstractions (range-based operations)
  • Dynamic analysis

Bug 2:
std::map::operator[] 

If you are a fan of Scott Meyers and have read his book:
Effective STL (Too bad there's no update with modern C++ since now he's retired.) Bug 1 & 2 are mentioned in this book.

1. It's slow.
2. Why it's slow? It checks if the key exist, if not, insert the key with
default value type constructor constructed value instance.

But, even though it's slow, it makes the code elegant , somehow~:
--
map<char, int> occ;

for (auto c : str) {
    occ[c]++;
}
--

const correctness:
As a senior C++ engineer knows const can act as guardian against accidentally modify the internal state.


Bug 3:
folly::get_default

Same idea as Python's  dict().get(Key, DefaultValue)

Bugs comes from returning string as r-value and caller references it.
(emm~ yup, this talk is for junior C++ engineer :-) although not bad and pinpoint the issue instead of gibberish )

mitigation:
-fsanitize-address-use-after-scope


Bug 4:
volatile

When coming to atomic operation, find something under
header <atomic>

The famous paper about volatile + atomic could be:
C++ and the Perils of Double-Checked Locking -Scott Meyers and Andrei Alexandrescu


Bug 5:
std::shared_ptr  thread safe?

Yes for internal ref counting.
(Another saying is that shared_ptr is as thead-safe as a normal pointer~ duh~ Not precise and sometimes incorrect.)

However, the type instance it points to is definitely not thread-safe.
(Well, depends on the type).

i.e shared_ptr's control block itself is thread-safe.
Wanna speed? Use unique_ptr.

Reference:
Always consider function thread safeness drags performance in single thread code

Reference:
$ git bisect  // debugging~
http://vsdmars.blogspot.com/2016/01/git-concepts-and-commands.html#more

mitigation:
  • Thread sanitizer
  • Address Sanitizer often does, too
  • Use library:
    atomic<shared_ptr>


Bug 6:
This compiles:
#include <string>
void f()
{
    std::string(foo);  // Same as std::string foo;
}

Why?
Effective STL Item 6: Be alert for C++'s most vexing parse.

The insidious bug could be:
void obj::update() noexcept {
    unique_lock<mutex>(m_mutex);  // This one is truly insidious... Not locking at all.
    do_something();
}

Fix, simple name the unique_lock<mutex> g{m_mutext};
and use {} instead () _always_!

This kind of bug happens on types which have default constructor.

mitigation:
  • -Wshadow  // Why? Because it warns us if there's a re-declaration shadows outter scope variable.
    It's noisy, not a good mitigation, though.
  • Use {} instead of ()

Sep 20, 2018

[clang] CUDA Support in Clang 7.0

http://releases.llvm.org/7.0.0/tools/clang/docs/ReleaseNotes.html

Clang now supports generating object files with relocatable device code.
This feature needs to be enabled with 
-fcuda-rdc
and may result in performance penalties compared to whole program compilation. 

Sep 29, 2017

[C++][cppcon 2017] libfuzzer

clang++ -std=c++11 string_view_uaf.cc -stdlib=libc++ -fsanitize=address && ./a.out

clang -g -O1 -fsanitize=address,fuzzer fuzz.cpp lib/*.cpp

Security + Stability > Memory Safety

Proposal: C++ attribute
[[fuzz]]

reference:

Oct 4, 2016

[cppcon2016] [c++] Improving Performance Through Compiler Switches - Tim Haines

Sep 30, 2015

[C++] compiler flags

-O3
-std=c++14
-stdlib=libc++
-lc++abi
-Wl, -rpath=~
-fno-exceptions
-fno-rtti
-Wall
-pedantic
-Werror
-isystem ~
-pthreads
-fno-omit-frame-pointer
-fno-elide-constructors // avoid nrvo rvo