Windows 10での、Visual Studio 2005です。
プログラムが走って、C言語側のコードは全く走らず、いきなり、
int main(void){
の処で、スタックオーバーフローです。
アセンブラが走って、その最後から4行目の処で、引っ掛かりました。
メッセージは、
Edge_Det.exe の 0x004126c7 でハンドルされていない例外が発生しました:
0xC00000FD:
Stack over flow
何が悪いのでしょうか?
page ,132
title chkstk - C stack checking routine
;
;chkstk.asm - C stack checking routine
;
; Copyright (c) Microsoft Corporation. All rights reserved.
;
;Purpose:
; Provides support for automatic stack checking in C procedures
; when stack checking is enabled.
;
;***************************************************************************
*
.xlist
include cruntime.inc
.list
; size of a page of memory
_PAGESIZE_ equ 1000h
CODESEG
page
;
;_chkstk - check stack upon procedure entry
;
;Purpose:
; Provide stack checking on procedure entry. Method is to simply probe
; each page of memory required for the stack in descending order. This
; causes the necessary pages of memory to be allocated via the guard
; page scheme, if possible. In the event of failure, the OS raises the
; _XCPT_UNABLE_TO_GROW_STACK exception.
;
; NOTE: Currently, the (EAX < _PAGESIZE_) code path falls through
; to the lastpage label of the (EAX >= _PAGESIZE_) code path. This
; is small; a minor speed optimization would be to special case
; this up top. This would avoid the painful save/restore of
; ecx and would shorten the code path by 4-6 instructions.
;
;Entry:
; EAX = size of local frame
;
;Exit:
; ESP = new stackframe, if successful
;
;Uses:
; EAX
;
;Exceptions:
; _XCPT_GUARD_PAGE_VIOLATION - May be raised on a page probe. NEVER TRAP
; THIS!!!! It is used by the OS to grow the
; stack on demand.
; _XCPT_UNABLE_TO_GROW_STACK - The stack cannot be grown. More precisely,
; the attempt by the OS memory manager to
; allocate another guard page in response
; to a _XCPT_GUARD_PAGE_VIOLATION has
; failed.
;
;***************************************************************************
*
public _alloca_probe
_chkstk proc
_alloca_probe = _chkstk
push ecx
; Calculate new TOS.
lea ecx, [esp] + 8 - 4 ; TOS before entering function + size
for ret value
sub ecx, eax ; new TOS
; Handle allocation size that results in wraparound.
; Wraparound will result in StackOverflow exception.
sbb eax, eax ; 0 if CF==0, ~0 if CF==1
not eax ; ~0 if TOS did not wrapped around, 0
otherwise
and ecx, eax ; set to 0 if wraparound
mov eax, esp ; current TOS
and eax, not ( _PAGESIZE_ - 1) ; Round down to current page
boundary
cs10:
cmp ecx, eax ; Is new TOS
jb short cs20 ; in probed page?
mov eax, ecx ; yes.
pop ecx
xchg esp, eax ; update esp
mov eax, dword ptr [eax] ; get return address
mov dword ptr [esp], eax ; and put it at new TOS
ret
; Find next lower page and probe
cs20:
sub eax, _PAGESIZE_ ; decrease by PAGESIZE
test dword ptr [eax],eax ; probe page. <== エラー箇所
jmp short cs10
_chkstk endp
end
今回の現象、ある程度、解析できました。
ソースの方で、
#include<stdio.h>
#include<math.h>
#include<string.h>
#define PATH 256
#define WIDTH 600
#define HEIGHT 600
main(){
char path[PATH];
unsigned char img[WIDTH][HEIGHT][3];
となっていた処を、と、メモリの確保領域を狭くすべく、
#include<stdio.h>
#include<math.h>
#include<string.h>
#define PATH 256
#define WIDTH 450
#define HEIGHT 450
main(){
char path[PATH];
unsigned char img[WIDTH][HEIGHT][3];
に変えてみたのです。
つまり、WIDTHとHEIGHTを、それぞれ600⇒450にしてみました。
そんなら、走り始め、以前のような、
頭からの、スタックオーバーフローで、ハングする現象が消えました。
しかし、これら、2つは、画像処理する上での、
画像ファイルの横幅と高さの最高値ですので、元々のように、
出来るだけ、大きく数字は持っておきたいものです。
どうすればようのでしょうか?
int だったらば、long intなんていう指定もできたような気がするのですが、
unsigned charをいじって、何らかの解決方法は、ないでしょうか?
よろしく、お願いします。
>Windows 10での、Visual Studio 2005です。
アップグレードなんでしょうかね?
VS2005はWindows10ではインストールできなかったかと思いますが。
# 手持ちのVS2005Stdが使えなくなった(TT
>どうすればようのでしょうか?
ローカル変数(自動変数)は一般的にスタックから取られます。
ということで、「サイズの大きなローカル変数は使わないようにする」というのが普通な
のですが……。
・mallocなどで動的確保する。
もちろんこの場合はポインタ使用ということになりますから、単純な三次元配列のよう
には使えません。
・グローバル変数にする。
ちゃんと管理しないと意図しないところで変更されてしまいます。
・static変数にする。
無難…なのかなぁ……。
・スタックのサイズを増やす。
リンカのオプションにあります。
が、どこまで増やせばいいのか…という問題もありますのでご注意を。
確かVSでは規定値が1Mだったかと。
うーーん、
600 X 600 X 3 = 1080000
1Mbyte 1048576
30424 約32Kbyteオーバーですね。
画像の場合は意外と解決しやすいですね。
顧客と最大画素数を決めて、使用メモリーを計算する。
それを
瀬戸っぷさんの意見どうりに
・mallocなどで動的確保する。
・グローバル変数にする。
ですね。
ちなみに僕はnewを使いますね。
スタックサイズは変えないようにしたほうがいいですね。