質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.20%

void*によるcvectorで、バッファオーバーランの警告

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 599

asobinin

score 32

void*型をキャストすることでint型やconst char*型、ユーザー定義型に対応するcvectorというものを試作してみました。
ところが、PUSH_BACKマクロにてバッファオーバーランが発生したとの警告が発生してしまいます。
詳細を見てみると、
ARRAY_AT(T, tmp, i) = AT(T, CVECTOR, i);\
AT(T, CVECTOR, CVECTOR.size_) = ITEM;\
の二か所で「書き込み中にバッファオーバーランが発生しました。8バイト(テストケースの場合)を書き込む可能性があります。」という警告が出されています。
ITEMの代入はともかくとして、tmpとCVECTORは同じ型のはずなのに何故このような警告が出されているのでしょうか。

開発環境:VisualStudio2019 OS:Windows10

// main.c
#include <stdio.h>
#include "cvector.h"

int main(void)
{
    cvector test;
        INIT(test);
    int size = 20;
    for (int i = 0; i < size; i++) {
        PUSH_BACK(int, test, i * i);
    }
    for (int i = 0; i < size; i++) {
        printf("%d\n", AT(int, test, i));
    }

    CLEAR(test);
    return 0;
}
// cvector.h
#pragma  once
#include <stdlib.h>
#include <stdio.h>

// C言語による簡易vectorもどき
typedef struct cvector_t {
    void* data_;    // 要素の格納領域
    int capacity_;    // 格納可能な最大要素数
    int size_;        // 格納されている要素数
} cvector;

// 初期化
#define INIT(CVECTOR) CVECTOR.data_ = 0; CVECTOR.capacity_ = 0; CVECTOR.size_ = 0;

// 配列への参照(汎用)
#define ARRAY_AT(T, V, N) ((T*)V)[N]

// 要素への参照(cvector)
#define AT(T, CVECTOR, N) ARRAY_AT(T, CVECTOR.data_, N)

// 要素の末尾にデータを追加
#define PUSH_BACK(T, CVECTOR, ITEM)\
{\
    if (CVECTOR.size_ == CVECTOR.capacity_) {\
        CVECTOR.capacity_ += 10;\
        void* tmp;\
        tmp = (T*)malloc(sizeof(T) * CVECTOR.capacity_);\
        if (tmp == NULL) { printf("memory secure error\n"); exit(1); }\
        for (int i = 0; i < CVECTOR.size_; ++i)\
            ARRAY_AT(T, tmp, i) = AT(T, CVECTOR, i);\
        FREE(CVECTOR);\
        CVECTOR.data_ = tmp;\
    }\
    AT(T, CVECTOR, CVECTOR.size_) = ITEM;\
    CVECTOR.size_++;\
}

// 全ての要素を消去する
#define CLEAR(CVECTOR) free(CVECTOR.data_); CVECTOR.capacity_ = 0; CVECTOR.size_ = 0;

// data_のみを消去する
#define FREE(CVECTOR) free(CVECTOR.data_);
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • asobinin

    2019/07/14 22:05

    ワーニングメッセージを確認しようとしたところ、警告が消えていたことを確認しました・・・
    テストしてみたところ、INIT()による初期化では警告は発生せず、コントラスタにて初期化を行っていた場合においては警告が発生するようです。コントラスタで初期化した後、INIT()で再度初期化しても警告は発生しませんでした。
    どちらも同様のことをしておりますが、何故このようなことが起きているのでしょうか。

    キャンセル

  • asobinin

    2019/07/14 22:06

    ワーニングメッセージ全文
    警告 C6386 'test.data_' への書き込み中にバッファー オーバーランが発生しました: 書き込み可能なサイズは 'sizeof(int)*test.capacity_' バイトですが、'test.size_' バイトを書き込む可能性があります。
    警告 C6386 'tmp' への書き込み中にバッファー オーバーランが発生しました: 書き込み可能なサイズは 'sizeof(int)*test.capacity_' バイトですが、'8' バイトを書き込む可能性があります。

    キャンセル

  • pepperleaf

    2019/07/14 23:28

    [参考]
    VS 2017 Express では、エラー無しで終了。
    環境: WIndows10 64bit

    キャンセル

回答 1

checkベストアンサー

0

VisualStudio2019、Windows10 64bit環境です。

CVECTOR.size_とCVECTOR.capacity_の値によってはバッファオーバーランが発生するかもしれない。
という警告かと思われます。

PUSH_BACK実行時、仮に両方の変数に-10が設定されていた場合は、
mallocの時点でCVECTOR.capacity_が0になっているはずなので、サイズ0でmallocを呼びます。

処理系によってはmallocに0を渡すとNULL以外を返します。
その場合は次の行のif (tmp == NULL)をすり抜けます。

すり抜けた先で、もしこのままtmpにアクセスすることがあったらバッファオーバーランが発生しますよ?
という警告に読み取れます。

// 要素の末尾にデータを追加
#define PUSH_BACK(T, CVECTOR, ITEM)\
{\
    if(CVECTOR.size_ >= 0 && CVECTOR.capacity_ >= 0 ){\
        省略
    }/
}

両方0以上で通るようにしたら警告は発生しませんでした。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.20%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる