line-bot-sdk-phpとreplyToken

LINE Messaging APIを使用した開発をやります。
$ php composer.phar require linecorp/line-bot-sdk
$ php composer.phar require guzzlehttp/guzzle

こちらでは上手くいかない

require("vendor/autoload.php");

use LINE\LINEBot\Constant\HTTPHeader;
use LINE\LINEBot\HTTPClient\CurlHTTPClient;
use LINE\LINEBot;

$channel_access_token = 'xxxx';
$channel_secret = 'xxxx';

$http_client = new CurlHTTPClient($channel_access_token);
$bot = new LINEBot($http_client, ['channelSecret' => $channel_secret]);
$signature = $_SERVER['HTTP_' . HTTPHeader::LINE_SIGNATURE];
$http_request_body = file_get_contents('php://input');
$events = $bot->parseEventRequest($http_request_body, $signature);
$event = $events[0];

$reply_token = $event->getReplyToken();
$reply_text = $event->getText();
$bot->replyText($reply_token, $reply_text);

Githubを見ながら少し内容を変更します。SDKのバージョンによってライブラリのclass構成が変わっているようです。
https://github.com/line/line-bot-sdk-php
replyTokenは、{“events”}[0]に入っている。line-bot-sdk-phpのsampleを見ても全然わからなかったので、凄い時間がかったw

ini_set("display_errors", 1);
error_reporting(E_ALL);
require("vendor/autoload.php");

$jsonString = file_get_contents('php://input'); error_log($jsonString); 
$jsonObj = json_decode($jsonString); $message = $jsonObj->{"events"}[0]->{"message"}; 
$replyToken = $jsonObj->{"events"}[0]->{"replyToken"};

$client = new \GuzzleHttp\Client();
$config = new \LINE\Clients\MessagingApi\Configuration();
$config->setAccessToken('');
$messagingApi = new \LINE\Clients\MessagingApi\Api\MessagingApiApi(
  client: $client,
  config: $config,
);

$message = new \LINE\Clients\MessagingApi\Model\TextMessage(['type' => 'text','text' => $message->{"text"}]);
$request = new \LINE\Clients\MessagingApi\Model\ReplyMessageRequest([
    'replyToken' => $replyToken,
    'messages' => [$message],
]);
$response = $messagingApi->replyMessage($request);

Ubuntu22.04にPHPとMySQLをインストールする

$ sudo apt update

### PHP
$ sudo apt install php libapache2-mod-php php-mysql
$ php -v
PHP 8.1.2-1ubuntu2.14 (cli) (built: Aug 18 2023 11:41:11) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.2, Copyright (c) Zend Technologies
with Zend OPcache v8.1.2-1ubuntu2.14, Copyright (c), by Zend Technologies

### MySQL
$ sudo apt install mysql-server

### composer.phar
$ curl -sS https://getcomposer.org/installer | php

[bitcoin] bitcoincoreのファイル構造 [その1]

まずGithubから bitcoincore のソースコードを clone してきます。
github上で見てもいいんですが、なんとなくローカルに落としたいですよね。。

$ git clone https://github.com/bitcoin/bitcoin.git
$ $ tree -L 3 -d
.
└── bitcoin
├── build-aux
│ └── m4
├── build_msvc
│ ├── bench_bitcoin
│ ├── bitcoin-cli
│ ├── bitcoind
│ ├── bitcoin-qt
│ ├── bitcoin-tx
│ ├── bitcoin-util
│ ├── bitcoin-wallet
│ ├── libbitcoin_cli
│ ├── libbitcoin_common
│ ├── libbitcoin_consensus
│ ├── libbitcoin_crypto
│ ├── libbitcoin_node
│ ├── libbitcoin_qt
│ ├── libbitcoin_util
│ ├── libbitcoin_wallet
│ ├── libbitcoin_wallet_tool
│ ├── libbitcoin_zmq
│ ├── libleveldb
│ ├── libminisketch
│ ├── libsecp256k1
│ ├── libtest_util
│ ├── libunivalue
│ ├── msbuild
│ ├── test_bitcoin
│ └── test_bitcoin-qt
├── ci
│ ├── lint
│ ├── retry
│ └── test
├── contrib
│ ├── completions
│ ├── debian
│ ├── devtools
│ ├── guix
│ ├── init
│ ├── linearize
│ ├── macdeploy
│ ├── message-capture
│ ├── qos
│ ├── seeds
│ ├── shell
│ ├── signet
│ ├── testgen
│ ├── tracing
│ ├── verify-binaries
│ ├── verify-commits
│ ├── windeploy
│ └── zmq
├── depends
│ ├── builders
│ ├── hosts
│ ├── packages
│ └── patches
├── doc
│ ├── design
│ ├── man
│ ├── policy
│ └── release-notes
├── share
│ ├── examples
│ ├── pixmaps
│ ├── qt
│ └── rpcauth
├── src
│ ├── bench
│ ├── common
│ ├── compat
│ ├── config
│ ├── consensus
│ ├── crc32c
│ ├── crypto
│ ├── index
│ ├── init
│ ├── interfaces
│ ├── ipc
│ ├── kernel
│ ├── leveldb
│ ├── logging
│ ├── minisketch
│ ├── node
│ ├── policy
│ ├── primitives
│ ├── qt
│ ├── rpc
│ ├── script
│ ├── secp256k1
│ ├── support
│ ├── test
│ ├── univalue
│ ├── util
│ ├── wallet
│ └── zmq
└── test
├── functional
├── fuzz
├── lint
├── sanitizer_suppressions
└── util

各ディレクトリ、各機能ごとの役割を細く見て行くことが必要ですね。

[C言語] 疑似乱数

rand()は 0 から RAND_MAXまでの疑似乱数を返す。stdlib.hに定義されている。
多くのプログラムはエポックからの経過秒数を種にして使用している。

#include <stdio.h>
#include <stdlib.h>

int main() {
    int i;
    printf("RAND_MAX: %u\n", RAND_MAX);
    srand(time(0));

    printf("0からRAND_MAXまでの乱数値\n");
    for(i=0; i< 8; i++)
        printf("%d\n", rand());
    printf("0から20までの乱数値\n");
    for(i=0; i< 8; i++)
        printf("%d\n", (rand()%20)+1);
    return 0;
}

$ ./a.out
RAND_MAX: 2147483647
0からRAND_MAXまでの乱数値
1059493860
583633074
1632571078
678819775
1658879329
1703267400
1565774963
996314262
0から20までの乱数値
13
4
2
13
13
7
11
18

[C言語] 関数のポインタ

#include <stdio.h>

int func_one() {
    printf("これは1つ目の関数です。\n");
    return 1;
}

int func_two() {
    printf("これは2つ目の関数です。\n");
    return 2;
}

int main() {
    int value;
    int (*function_ptr)();

    function_ptr = func_one;
    printf("function_ptr: 0x%08x\n", function_ptr);
    value = function_ptr();
    printf("戻り値: %d\n", value);

    function_ptr = func_two;
    printf("function_ptr: 0x%08x\n", function_ptr);
    value = function_ptr();
    printf("戻り値: %d\n", value);

    return 0;
}

$ ./a.out
function_ptr: 0xcdc907d4
これは1つ目の関数です。
戻り値: 1
function_ptr: 0xcdc907f4
これは2つ目の関数です。
戻り値: 2

[C言語] 構造体

time.hのtm構造体を使用する

#include <stdio.h>
#include <time.h>

int main() {
    long int seconds_since_epoch;
    struct tm current_time, *time_ptr;
    int hour, minute, second, day, month, year;

    seconds_since_epoch = time(0);
    printf("time() - エポックからの通算秒数: %ld\n", seconds_since_epoch);

    time_ptr = &current_time;

    localtime_r(&seconds_since_epoch, time_ptr);

    hour = current_time.tm_hour;
    minute = time_ptr->tm_min;
    second = *((int *) time_ptr);

    printf("現在の時間は: %02d:%02d:%02d\n", hour, minute, second);

    return 0;
}

$ ./a.out
time() – エポックからの通算秒数: 1707729486
現在の時間は: 03:18:06
$ ./a.out
time() – エポックからの通算秒数: 1707729492
現在の時間は: 03:18:12

#include <stdio.h>
#include <time.h>

void dump_time_struct_bytes(struct tm *time_ptr, int size){
    int i;
    unsigned char *raw_ptr;

    printf("0x%08x にある構造体の内容\n", time_ptr);
    raw_ptr = (unsigned char *) time_ptr;
    for(i=0; i<size; i++){
        printf("%02x ", raw_ptr[i]);
        if(i%16 == 15)
            printf("\n");
    }
    printf("\n");
}

int main() {
    long int seconds_since_epoch;
    struct tm current_time, *time_ptr;
    int hour, minute, second, i, *int_ptr;

    seconds_since_epoch = time(0);
    printf("time() - エポックからの通算秒数: %ld\n", seconds_since_epoch);

    time_ptr = &current_time;

    localtime_r(&seconds_since_epoch, time_ptr);

    hour = current_time.tm_hour;
    minute = time_ptr->tm_min;
    second = *((int *) time_ptr);

    printf("現在の時間は: %02d:%02d:%02d\n", hour, minute, second);

    dump_time_struct_bytes(time_ptr, sizeof(struct tm));

    minute = hour = 0;
    int_ptr = (int *) time_ptr;

    for(i=0; i < 3; i++) {
        printf("int ptr @ 0x08x : %d\n", int_ptr, *int_ptr);
        int_ptr++;
    }

    return 0;
}

$ ./a.out
time() – エポックからの通算秒数: 1707730079
現在の時間は: 03:27:59
0xf089a030 にある構造体の内容
3b 00 00 00 1b 00 00 00 03 00 00 00 0c 00 00 00
01 00 00 00 7c 00 00 00 01 00 00 00 2a 00 00 00
00 00 00 00 ff ff 00 00 a0 ab ff ff ff ff ff ff
00 a9 5d d4 aa aa 00 00
int ptr @ 0x08x : -259416016
int ptr @ 0x08x : -259416012
int ptr @ 0x08x : -259416008

[C言語] ユーザID

全てのユーザにはuidという個別の数値が割り当てられる

$ id root
uid=0(root) gid=0(root) groups=0(root)
$ id vagrant
uid=1000(vagrant) gid=1000(vagrant) groups=1000(vagrant),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),110(lxd)

hacking.h

void fatal(char *message) {
    char error_message[100];

    strcpy(error_message, "[!!]致命的なエラー:");
    strncat(error_message, message, 83);
    perror(error_message);
    exit(-1);
}

void *ec_malloc(unsigned int size) {
    void *ptr;
    ptr = malloc(size);
    if(ptr == NULL)
        fatal("ec_malloc()内でメモリ割り当てに失敗しました。");
    return ptr;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "hacking.h"

void usage(char *prog_name, char *filename){
    printf("使用方法: %s <%sに追加するデータ>\n", prog_name, filename);
    exit(0);
}

void fatal(char *);
void *ec_malloc(unsigned int);

int main(int argc, char *argv[]) {
    int userid, fd;
    char *buffer, *datafile;

    buffer = (char *) ec_malloc(100);
    datafile = (char *) ec_malloc(20);
    strcpy(datafile, "./notes");

    if(argc < 2)
        usage(argv[0], datafile);

    strcpy(buffer, argv[1]);

    printf("[DEBUG] buffer @ %p: \'%s\'\n", buffer, buffer);
    printf("[DEBUG] datafile @ %p: \'%s\'\n", datafile, datafile);

    fd = open(datafile, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR);
    if(fd == -1)
        fatal("main()内、ファイルのオープン中にエラーが発生しました。");
    printf("[DEBUG] ファイル記述子]:%d\n", fd);

    userid = getuid();

    if(write(fd, &userid, 4) == -1)
        fatal("main()内、ファイルへのユーザIDの書き込みでエラーが発生しました。");
    write(fd, "\n", 1);

    if(write(fd, buffer, strlen(buffer)) == -1)
        fatal("main()内、ファイルへのバッファの書き込みでエラーが発生しました。");
    write(fd, "\n", 1);

    if(close(fd) == -1)
        fatal("main()内、ファイルのクローズ中にエラーが発生しました。");

    printf("メモが保存されました。\n");
    free(buffer);
    free(datafile);

    return 0;
}

$ gcc -o main main.c
$ ls -l ./main
-rwxrwxr-x 1 vagrant vagrant 13664 Feb 12 02:26 ./main

$ sudo chown root:root ./main
$ sudo chmod u+s ./main
$ ls -l ./main
-rwsrwxr-x 1 root root 13664 Feb 12 02:26 ./main

$ ./main “this is a test of multiuser notes”
[DEBUG] buffer @ 0xaaaaf83ba2a0: ‘this is a test of multiuser notes’
[DEBUG] datafile @ 0xaaaaf83ba310: ‘./notes’
[DEBUG] ファイル記述子]:3
メモが保存されました。
$ ls -l ./notes
-rw——- 1 root vagrant 39 Feb 12 02:31 ./notes
$ sudo cat ./notes

this is a test of multiuser notes
$ sudo hexdump -C ./notes
00000000 e8 03 00 00 0a 74 68 69 73 20 69 73 20 61 20 74 |…..this is a t|
00000010 65 73 74 20 6f 66 20 6d 75 6c 74 69 75 73 65 72 |est of multiuser|
00000020 20 6e 6f 74 65 73 0a | notes.|

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "hacking.h"
#define FILENAME "./notes"

int print_notes(int, int, char *);
int find_user_note(int, int);
int search_note(char *, char *);
void fatal(char *);

int main(int argc, char *argv[]) {
    int userid, printing=1, fd;
    char searchstring[100];

    if(argc > 1)
        strcpy(searchstring, argv[1]);
    else
        searchstring[0] = 0;

    userid = getuid();
    fd = open(FILENAME, O_RDONLY);
    if(fd == -1)
        fatal("main()内、ファイルの読み込みオープンでエラーが発生しました。");

    while(printing)
        printing = print_notes(fd, userid, searchstring);
    printf("-----[ メモの終わり ]------\n");
    close(fd);    

    return 0;
}

int print_notes(int fd, int uid, char *searchstring) {
    int note_length;
    char byte=0, note_buffer[100];

    note_length = find_user_note(fd, uid);
    if(note_length == -1)
        return 0;

    read(fd, note_buffer, note_length);
    note_buffer[note_length] = 0;

    if(search_note(note_buffer, searchstring))
        printf(note_buffer);
    return 1;
}

int find_user_note(int fd, int user_uid) {
    int note_uid = -1;
    unsigned char byte;
    int length;

    while(note_uid != user_uid){
        if(read(fd, &note_uid, 4) != 4)
            return -1;
        if(read(fd, &byte, 1) != 1)
            return -1;

        byte = length = 0;
        while(byte != '\n'){
            if(read(fd, &byte, 1) != 1)
                return -1;
            length++;
        }
    }
    lseek(fd, length * -1L, SEEK_CUR);

    printf("[DEBUG] uid %dの%dバイトのメモを見つけました\n", note_uid, length);
    return length;
}

int search_note(char *note, char *keyword){
    int i, keyword_length, match=0;

    keyword_length = strlen(keyword);
    if(keyword_length == 0)
        return 1;

    for(i=0; i<strlen(note); i++){
        if(note[i] == keyword[match])
            match++;
        else {
            if(note[i] == keyword[0])
                match = 1;
            else
                match = 0;
        }
        if(match == keyword_length)
            return 1;
    }
    return 0;
}

$ ./main
[DEBUG] uid 1000の34バイトのメモを見つけました
this is a test of multiuser notes
—–[ メモの終わり ]——

[C言語] ファイルアクセス

ファイル記述子を使用する関数には、open, close, read, writeがある。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>

void usage(char *prog_name, char *filename){
    printf("使用方法: %s <%sに追加するデータ>\n", prog_name, filename);
    exit(0);
}

void fatal(char *);
void *ec_malloc(unsigned int);

int main(int argc, char *argv[]) {
    int fd;
    char *buffer, *datafile;

    buffer = (char *) ec_malloc(100);
    datafile = (char *) ec_malloc(20);
    strcpy(datafile, "./notes");

    if (argc < 2)
        usage(argv[0], datafile);

    strcpy(buffer, argv[1]);

    printf("[DEBUG] buffer @ %p: \'%s'\n", buffer, buffer);
    printf("[DEBUG] datafile @ %p: \'%s'\n", datafile, datafile);

    strncat(buffer, "\n", 1);

    fd = open(datafile, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR);
    if(fd == -1)
        fatal("main()内、ファイルのオープン中にエラーが発生しました。");
    printf("[DEBUG] ファイル記述子:%d\n", fd);

    if(write(fd, buffer, strlen(buffer)) == -1)
        fatal("main()内、ファイルへのバッファの書き込みでエラーが発生しました。");

    if(close(fd) == -1)
        fatal("main()内、ファイルのクローズ中にエラーが発生しました。");

    printf("メモが保存されました\n");
    free(buffer);
    free(datafile);

    return 0;
}

void fatal(char *message) {
    char error_message[100];

    strcpy(error_message, "[!!]致命的なエラー:");
    strncat(error_message, message, 79);
    perror(error_message);
    exit(-1);
}

void *ec_malloc(unsigned int size) {
    void *ptr;
    ptr = malloc(size);
    if(ptr == NULL)
        fatal("ec_malloc()内のメモリ割り当てでエラーが発生しました。");
    return ptr;
}

$ ./main
使用方法: ./main <./notesに追加するデータ>
$ ./main “this is a test note”
[DEBUG] buffer @ 0xaaaadc4a72a0: ‘this is a test note’
[DEBUG] datafile @ 0xaaaadc4a7310: ‘./notes’
[DEBUG] ファイル記述子:3
メモが保存されました

### ビット単位の演算

int main() {
    int i, bit_a, bit_b;
    printf("ビット単位の論理和演算子 |\n");
    for(i=0; i< 4; i++){
        bit_a = (i & 2) / 2;
        bit_b = (i & 1);
        printf("%d | %d = %d\n", bit_a, bit_b, bit_a | bit_b);
    }

    printf("ビット単位の論理積演算子 |\n");
    for(i=0; i< 4; i++){
        bit_a = (i & 2) / 2;
        bit_b = (i & 1);
        printf("%d | %d = %d\n", bit_a, bit_b, bit_a & bit_b);
    }

    return 0;
}

$ ./main
ビット単位の論理和演算子 |
0 | 0 = 0
0 | 1 = 1
1 | 0 = 1
1 | 1 = 1
ビット単位の論理積演算子 |
0 | 0 = 0
0 | 1 = 0
1 | 0 = 0
1 | 1 = 1

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>

void display_flags(char *, unsigned int);
void binary_print(unsigned int);

int main(int argc, char *argv[]) {
    display_flags("O_RDONLY\t\t", O_RDONLY);
    display_flags("O_WRONLY\t\t", O_WRONLY);
    display_flags("O_RDWR\t\t", O_RDWR);
    printf("\n");
    display_flags("O_APPEND\t\t", O_APPEND);
    display_flags("O_TRUNC\t\t", O_TRUNC);
    display_flags("O_CREAT\t\t", O_CREAT);

    printf("\n");
    display_flags("O_WRONLY|O_APPEND|O_CREAT", O_WRONLY|O_APPEND|O_CREAT);

    return 0;
}

void display_flags(char *label, unsigned int value){
    printf("%s\t %d\t:", label, value);;
    binary_print(value);
    printf("\n");
}

void binary_print(unsigned int value) {
    unsigned int mask = 0xff000000;
    unsigned int shift = 256*256*256;
    unsigned int byte, byte_iterator, bit_iterator;

    for(byte_iterator=0; byte_iterator < 4; byte_iterator++){
        byte = (value & mask) / shift;
        printf(" ");
        for(bit_iterator=0; bit_iterator < 8; bit_iterator++){
            if(byte & 0x80)
                printf("1");
            else
                printf("0");
            byte *= 2;
        }
        mask /= 256;
        shift /= 256;
    }
}

$ ./main
O_RDONLY 0 : 00000000 00000000 00000000 00000000
O_WRONLY 1 : 00000000 00000000 00000000 00000001
O_RDWR 2 : 00000000 00000000 00000000 00000010

O_APPEND 1024 : 00000000 00000000 00000100 00000000
O_TRUNC 512 : 00000000 00000000 00000010 00000000
O_CREAT 64 : 00000000 00000000 00000000 01000000

O_WRONLY|O_APPEND|O_CREAT 1089 : 00000000 00000000 00000100 01000001

[C言語] メモリのヒープの使用

ヒープセグメントに割り当てるには、malloc関数を使用する

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[]) {
    char *char_ptr;
    int *int_ptr;
    int mem_size;

    if(argc < 2)
        mem_size = 50;
    else
        mem_size = atoi(argv[1]);

    printf("\t[+]ヒープから%dバイトを割り当て、先頭アドレスをchar_ptrに代入します。\n", mem_size);
    char_ptr = (char *) malloc(mem_size);

    if(char_ptr == NULL){
        fprintf(stderr, "エラー:ヒープメモリの割り当てに失敗しました。\n");
        exit(-1);
    }

    strcpy(char_ptr, "KOREHA HEAP NI COPY SAREMASU");
    printf("char_ptr (%p) --> '%s'\n", char_ptr, char_ptr);

    printf("\t[+]ヒープから12バイトを割り当て、先頭アドレスをint_ptrに代入します。\n");
    int_ptr = (int *) malloc(12);

    if(int_ptr == NULL){
        fprintf(stderr, "エラー:ヒープメモリの割り当てに失敗しました。\n");
        exit(-1);
    }

    *int_ptr = 31337;
    printf("int_ptr (%p) --> '%d'\n", int_ptr, *int_ptr);

    printf("\t[-]char_ptrが指しているヒープメモリを解放します。\n");
    free(char_ptr);

    printf("\t[+]ヒープから再び15バイトを割り当て、先頭アドレスをchar_ptrに代入します。\n");
    char_ptr = (char *)malloc(15);

    if(char_ptr == NULL) {
        fprintf(stderr, "エラー:ヒープメモリの割り当てに失敗しました。\n");
        exit(-1);
    }

    strcpy(char_ptr, "NEW MEMORY");
    printf("char_ptr(%p) --> '%s'\n", char_ptr, char_ptr);

    printf("\t[-]int_ptrのヒープメモリを解放します。\n");
    free(int_ptr);

    printf("\t[-]char_ptrが指しているヒープメモリを解放します。\n");
    free(char_ptr);

    return 0;
}

$ ./a.out
[+]ヒープから50バイトを割り当て、先頭アドレスをchar_ptrに代入します。
char_ptr (0xaaaac973c6b0) –> ‘KOREHA HEAP NI COPY SAREMASU’
[+]ヒープから12バイトを割り当て、先頭アドレスをint_ptrに代入します。
int_ptr (0xaaaac973c6f0) –> ‘31337’
[-]char_ptrが指しているヒープメモリを解放します。
[+]ヒープから再び15バイトを割り当て、先頭アドレスをchar_ptrに代入します。
char_ptr(0xaaaac973c710) –> ‘NEW MEMORY’
[-]int_ptrのヒープメモリを解放します。
[-]char_ptrが指しているヒープメモリを解放します。

割り当ての値を変えてテストを行う

$ ./a.out 100
[+]ヒープから100バイトを割り当て、先頭アドレスをchar_ptrに代入します。
char_ptr (0xaaaafbe3c6b0) –> ‘KOREHA HEAP NI COPY SAREMASU’
[+]ヒープから12バイトを割り当て、先頭アドレスをint_ptrに代入します。
int_ptr (0xaaaafbe3c720) –> ‘31337’
[-]char_ptrが指しているヒープメモリを解放します。
[+]ヒープから再び15バイトを割り当て、先頭アドレスをchar_ptrに代入します。
char_ptr(0xaaaafbe3c740) –> ‘NEW MEMORY’
[-]int_ptrのヒープメモリを解放します。
[-]char_ptrが指しているヒープメモリを解放します。

### エラー判定を関数化してしまう

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void *errorchecked_malloc(unsigned int); 

int main(int argc, char *argv[]) {
    char *char_ptr;
    int *int_ptr;
    int mem_size;

    if(argc < 2)
        mem_size = 50;
    else
        mem_size = atoi(argv[1]);

    printf("\t[+]ヒープから%dバイトを割り当て、先頭アドレスをchar_ptrに代入します。\n", mem_size);
    char_ptr = (char *) errorchecked_malloc(mem_size);

    strcpy(char_ptr, "KOREHA HEAP NI COPY SAREMASU");
    printf("char_ptr (%p) --> '%s'\n", char_ptr, char_ptr);

    printf("\t[+]ヒープから12バイトを割り当て、先頭アドレスをint_ptrに代入します。\n");
    int_ptr = (int *) errorchecked_malloc(12);

    *int_ptr = 31337;
    printf("int_ptr (%p) --> '%d'\n", int_ptr, *int_ptr);

    printf("\t[-]char_ptrが指しているヒープメモリを解放します。\n");
    free(char_ptr);

    printf("\t[+]ヒープから再び15バイトを割り当て、先頭アドレスをchar_ptrに代入します。\n");
    char_ptr = (char *) errorchecked_malloc(15);

    strcpy(char_ptr, "NEW MEMORY");
    printf("char_ptr(%p) --> '%s'\n", char_ptr, char_ptr);

    printf("\t[-]int_ptrのヒープメモリを解放します。\n");
    free(int_ptr);

    printf("\t[-]char_ptrが指しているヒープメモリを解放します。\n");
    free(char_ptr);

    return 0;
}

void *errorchecked_malloc(unsigned int size){
    void *ptr;
    ptr = malloc(size);
    if(ptr == NULL) {
        fprintf(stderr, "エラー: ヒープメモリの割り当てに失敗しました。\n");
        exit(-1);
    }
    return ptr;
}

[C言語] メモリのスタック領域

void test_function(int a, int b, int c, int d){
    int flag;
    char buffer[10];

    flag = 31337;
    buffer[0] = 'A';
}

int main() {
    test_function(1, 2, 3, 4);
    return 0;
}

$ gcc -g main.c
$ gdb -q ./a.out
Reading symbols from ./a.out…
(gdb) disass main
Dump of assembler code for function main:
0x000000000000087c <+0>: stp x29, x30, [sp, #-16]!
0x0000000000000880 <+4>: mov x29, sp
0x0000000000000884 <+8>: mov w3, #0x4 // #4
0x0000000000000888 <+12>: mov w2, #0x3 // #3
0x000000000000088c <+16>: mov w1, #0x2 // #2
0x0000000000000890 <+20>: mov w0, #0x1 // #1
0x0000000000000894 <+24>: bl 0x814
0x0000000000000898 <+28>: mov w0, #0x0 // #0
0x000000000000089c <+32>: ldp x29, x30, [sp], #16
0x00000000000008a0 <+36>: ret
End of assembler dump.

(gdb) disass test_function
Dump of assembler code for function test_function:
0x0000000000000814 <+0>: stp x29, x30, [sp, #-64]!
0x0000000000000818 <+4>: mov x29, sp
0x000000000000081c <+8>: str w0, [sp, #28]
0x0000000000000820 <+12>: str w1, [sp, #24]
0x0000000000000824 <+16>: str w2, [sp, #20]
0x0000000000000828 <+20>: str w3, [sp, #16]
0x000000000000082c <+24>: adrp x0, 0x10000
0x0000000000000830 <+28>: ldr x0, [x0, #4072]
0x0000000000000834 <+32>: ldr x1, [x0]
0x0000000000000838 <+36>: str x1, [sp, #56]
0x000000000000083c <+40>: mov x1, #0x0 // #0
0x0000000000000840 <+44>: mov w0, #0x7a69 // #31337
0x0000000000000844 <+48>: str w0, [sp, #36]
–Type for more, q to quit, c to continue without paging–
0x0000000000000848 <+52>: mov w0, #0x41 // #65
0x000000000000084c <+56>: strb w0, [sp, #40]
0x0000000000000850 <+60>: nop
0x0000000000000854 <+64>: adrp x0, 0x10000
0x0000000000000858 <+68>: ldr x0, [x0, #4072]
0x000000000000085c <+72>: ldr x2, [sp, #56]
0x0000000000000860 <+76>: ldr x1, [x0]
0x0000000000000864 <+80>: subs x2, x2, x1
0x0000000000000868 <+84>: mov x1, #0x0 // #0
0x000000000000086c <+88>: b.eq 0x874 // b.none
0x0000000000000870 <+92>: bl 0x6a0 <__stack_chk_fail@plt>
0x0000000000000874 <+96>: ldp x29, x30, [sp], #64
0x0000000000000878 <+100>: ret
End of assembler dump.

4, 3, 2, 1はスタックフレームにpushされる

(gdb) list main
6
7 flag = 31337;
8 buffer[0] = ‘A’;
9 }
10
11 int main() {
12 test_function(1, 2, 3, 4);
13 return 0;
14 }
(gdb) break 12
Breakpoint 1 at 0x884: file main.c, line 12.
(gdb) break test_function
Breakpoint 2 at 0x82c: file main.c, line 3.
(gdb) run
Starting program: /home/vagrant/dev/c/a.out
[Thread debugging using libthread_db enabled]
Using host libthread_db library “/lib/aarch64-linux-gnu/libthread_db.so.1”.

Breakpoint 1, main () at main.c:12
12 test_function(1, 2, 3, 4);

メモリ中の各セグメントは、低位アドレスから高位アドレスへ向かって並べられていく

– 低位アドレス
テキスト(コード)セグメント
データセグメント
bssセグメント
ヒープセグメント
スタックセグメント
– 高位アドレス

### メモリセグメント

int global_var;
int global_initialized_var = 5;

void function() {
    int stack_var;

    printf("function()のstack_varは、アドレス0x%08xにあります。\n", &stack_var);
}

int main() {
    int stack_var;
    static int static_initialized_var = 5;
    static int static_var;
    int *heap_var_ptr;

    heap_var_ptr = (int *)malloc(4);

    // データセグメントに確保される
    printf("global_initialized_varはアドレス0x%08xにあります。\n", &global_initialized_var);
    printf("static_initialized_varはアドレス0x%08xにあります。\n", &static_initialized_var);

    // bssセグメントに確保される
    printf("static_varはアドレス0x%08xにあります。\n", &static_var);
    printf("global_varはアドレス0x%08xにあります。\n", &global_var);

    // ポインタ変数はヒープセグメント内に確保される
    printf("heap_var_ptrはアドレス0x%08xにあります。\n", heap_var_ptr);

    // 以下の変数はスタックセグメント内に確保される
    printf("stack_varはアドレス0x%08xにあります。\n", &stack_var);

    return 0;
}

$ ./a.out
global_initialized_varはアドレス0xc5b21010にあります。
static_initialized_varはアドレス0xc5b21014にあります。
static_varはアドレス0xc5b21020にあります。
global_varはアドレス0xc5b2101cにあります。
heap_var_ptrはアドレス0xefedb2a0にあります。
stack_varはアドレス0xecf4957cにあります。