`off_t` is a 64-bit signed integer, so passing it in a register on i686
is not the best idea.
This fix gets us one step closer to making the LLVM port work.
In particular, we track separately whether each AtExitEntry has already
been called, through a separate Bitmap. This has several side-effects:
- We now call malloc() during __cxa_finalize(). I believe this is fine,
and at that point during program execution memory pressure should be
low anyway.
- An attacker could prevent arbitrary entries from executing by writing
to atexit_called_entries. However, this already was possible (by
setting atexit_entry_count to zero), and this path is even more
troublesome (the attacker needs to overwrite atexit_called_entries,
and a region serving as *atexit_called_entries.m_data, and magically
know exactly how many entries already exist.)
- This reduces the size of AtExitEntry from 16 to 12 (on i686). As such,
we can reduce the initial memory allocation from two to one page,
reducing the initial capacity from 512 to 341 entries (or 256 to 170,
on x86_64). It seems that most programs only use 36-47 entries anyway.
For 'true', this shaves off about 69 syscalls, as measured by strace.
Same as Vector, ByteBuffer now also signals allocation failure by
returning an ENOMEM Error instead of a bool, allowing us to use the
TRY() and MUST() patterns.
Before this change, we would generate the static C library by running
the command `ar -qcs` to collect the various `*.o` files into a single
archive.
The `q` option stands for "quick append", which simply appends new files
to the archive, without replacing any pre-existing entries for the same
file. The problem with this is obvious: each LibC rebuild would add
approximately 1 MB (the size of a cleanly built libc.a) to the size of
the file. It got so bad on my machine that the total file size ended up
being 3 gigabytes.
Note that this did not affect the GNU toolchain, because, as the `ar(1)`
manpage says:
> Note - GNU ar treats the command qs as a synonym for r - replacing
> already existing files in the archive and appending new ones at the
> end.
We create a base class called GenericFramebufferDevice, which defines
all the virtual functions that must be implemented by a
FramebufferDevice. Then, we make the VirtIO FramebufferDevice and other
FramebufferDevice implementations inherit from it.
The most important consequence of rearranging the classes is that we now
have one IOCTL method, so all drivers should be committed to not
override the IOCTL method or make their own IOCTLs of FramebufferDevice.
All graphical IOCTLs are known to all FramebufferDevices, and it's up to
the specific implementation whether to support them or discard them (so
we require extensive usage of KResult and KResultOr, together with
virtual characteristic functions).
As a result, the interface is much cleaner and understandable to read.
Some ports (like `bc` with history enabled) sensibly set the termios
character size to 8 bits.
Previously, we left the character size value (given by the bitmask
CSIZE) as zero by default (meaning 5 bits per character), and returned
ENOTIMPL whenever someone modified it. This was dumb.
Also add a test to prevent this from happening again. There were two
bugs:
* The number of bytes just after processing the last value was written,
instead of the number of bytes after skipping remaining whitespace.
Confirmed by testing against GNU's `scanf()` since the man page
leaves something to be desired.
* The number of bytes was written to the wrong variable argument; i.e.
the first argument was overwritten.
We always use UTF-8, meaning that a single `wchar_t` might be converted
into up to 4 `char`s. This would cause a buffer overflow if something
actually relied on this being the right value.
The C standard states that these symbols should be declared as macros,
not as emum variants as we were doing previously. This is used in some
ports (e.g. bash) to conditionally compile locale-dependent
functionality.
We now use the same trick here as with the errno constants. We keep the
enum, but also create macros that defer to the enum variants.
The `wcsxfrm` function copies a wide character string into a buffer,
such that comparing the new string against any similarly pre-processed
string with `wcscmp` produces the same result as if the original strings
were compared with `wcscoll`.
Our current `wcscoll` implementation is simply an alias for `wcscmp`, so
`wcsxfrm` needs to perform no actions other than copying the string.
The ELAST macro is used on many systems to refer to the largest possible
valid errno value. LLVM's libc++ uses errno values of ELAST+1 and
ELAST+2 internally, and defines an arbitrary fallback value for
platforms which don't have the macro. This means that it's possible for
their internal errno numbers could coincide with values we actually use,
which would be a very bad thing.
This function converts a single wide character into its multibyte
representation (UTF-8 in our case). It is called from libc++'s
`std::basic_ostream<wchar_t>::flush`, which gets called at program exit
from a global destructor in order to flush `std::wcout`.