目次: C言語とlibc
Cライブラリがメモリを確保する際、内部でシステムコールを呼んでOSにメモリ確保を依頼します。現状のLinuxですとメモリ確保は2種類用意されています。1つは懐かしのbrk(), sbrk() で、もう1つはmmap() で匿名ページ(MAP_ANONYMOUS)を割り当てる方法です。
匿名ページ(MAP_ANONYMOUS)によるメモリ確保の場合、0初期化されていることが定められています。brk, sbrkが返す領域はどうでしょう?SUSv3を見ましたがbrk, sbrkの項目そのものがありません。
SUSv2を見るとLEGACY扱いではあるものの、brkの項目が(brkへのリンク)ありました。説明を見ると、
DESCRIPTION
The brk() and sbrk() functions are used to change the amount of space allocated for the calling process. The change is made by resetting the process' break value and allocating the appropriate amount of space. The amount of allocated space increases as the break value increases. The newly-allocated space is set to 0.
とのことです。0初期化は必須ですね。
自作OSもどきを作っていて、brkで確保した領域を未初期化で返していました。newlibだと動いてしまうんですが、glibcはたまに死んでしまうことがあって気づきました。実装する前に規格を見ましょう。行き当たりばったりは良くないです……はい。
GNU tarのxオプションは圧縮されたtarでも正しく展開してくれます。圧縮方法はgzip, bzip, xz, ... など複数存在しますが、どのように判定しているんでしょう?まさか拡張子でしょうか?
こういうときにOSSは便利です。ソースコードを見ればわかるはず。バージョンはどれでも仕組み自体は同じだと思いますが、とりあえず最新版リリースGNU tar 1.34にしました。gitリポジトリへのリンクも貼っておきます。
// src/buffer.c
/* Compression detection */
enum compress_type {
ct_none, /* Unknown compression type */
ct_tar, /* Plain tar file */
ct_compress,
ct_gzip,
ct_bzip2,
ct_lzip,
ct_lzma,
ct_lzop,
ct_xz,
ct_zstd
};
static enum compress_type archive_compression_type = ct_none;
struct zip_magic
{
enum compress_type type;
size_t length;
char const *magic;
};
struct zip_program
{
enum compress_type type;
char const *program;
char const *option;
};
static struct zip_magic const magic[] = {
{ ct_none, 0, 0 },
{ ct_tar, 0, 0 },
{ ct_compress, 2, "\037\235" },
{ ct_gzip, 2, "\037\213" },
{ ct_bzip2, 3, "BZh" },
{ ct_lzip, 4, "LZIP" },
{ ct_lzma, 6, "\xFFLZMA" },
{ ct_lzop, 4, "\211LZO" },
{ ct_xz, 6, "\xFD" "7zXZ" },
{ ct_zstd, 4, "\x28\xB5\x2F\xFD" },
};
各圧縮方式に固有のマジックヘッダを定義している部分がありました。さすがに拡張子だけ見る雑な判定ではなさそうです。そりゃそうか。
// src/buffer.c
/* Check if the file ARCHIVE is a compressed archive. */
static enum compress_type
check_compressed_archive (bool *pshort)
{
struct zip_magic const *p;
bool sfr;
bool temp;
if (!pshort)
pshort = &temp;
/* Prepare global data needed for find_next_block: */
record_end = record_start; /* set up for 1st record = # 0 */
sfr = read_full_records;
read_full_records = true; /* Suppress fatal error on reading a partial
record */
*pshort = find_next_block () == 0;
/* Restore global values */
read_full_records = sfr;
if (record_start != record_end /* no files smaller than BLOCKSIZE */
&& (strcmp (record_start->header.magic, TMAGIC) == 0
|| strcmp (record_start->buffer + offsetof (struct posix_header,
magic),
OLDGNU_MAGIC) == 0)
&& tar_checksum (record_start, true) == HEADER_SUCCESS)
/* Probably a valid header */
return ct_tar;
for (p = magic + 2; p < magic + NMAGIC; p++) //★★magicはさきほど示したコードで定義していた配列★★
if (memcmp (record_start->buffer, p->magic, p->length) == 0) //★★ここで比較★★
return p->type;
return ct_none;
}
各圧縮方式に固有のバイナリ列が存在するか?をmemcmp() で見ています。結構シンプルな仕組みですね。
Might and Magic Book One TAS US版をさらに6秒くらい短縮(7:32.39 → 7:25.80)しました(ニコニコ動画へのリンク)。
TASVideosに再投稿するなら何かもう1つくらいは改善してから送りたいですが、良いアイデアが思いつかないです……。
< | 2022 | > | ||||
<< | < | 07 | > | >> | ||
日 | 月 | 火 | 水 | 木 | 金 | 土 |
- | - | - | - | - | 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 | - | - | - | - | - | - |
合計:
本日: