Search notes:

cl /Gs

cl /Gs sets the threshold for stack probes.

Example

This is an example that tries to demonstrate the effect of Visual Studio's option /Gs.

gs.c

gs.c is a simple C program with a function (func) that allocates a certain amount of bytes on the stack.
This amount is specified by the preprocessor macro BUFSIZE. When the compiler is invoked, a value is assigned to this macro with the /D option.
#include <windows.h>

void func() {

     char buf[BUFSIZE];

  //
  // Trying to write a byte at the end of the buf.
  //
  // If the size of buf is larger than the stack's guard page,
  // the OS (Windows) has no chance to realize that it had to
  // grow the commited size of the stack - thus, the instructino
  // will fail…
  // … except if /Gs inserts a call to chkstk in the beginning of
  // the function which will cause the necessary exception.
  //
     buf[BUFSIZE] = 0;

     MessageBoxA(NULL, "OK"                                     , "", 0);

}


int start() {
  func();
  ExitProcess(0);
}
Github repository about-cl, path: /options/G/s_/gs.c

Makefile

The makefile creates three exes from this source.
The first exe, gsOK.exe allocates a relatively small amount on the stack so that the stack does not grow beyond the stack's guard page (actually, it does not even grow into the guard page).
So, this exe runs ok when run.
The second exe, gsFail.exe, grows the stack by 200000 bytes: the end of buf is below the guard page and the OS didn't have a chance to commit more memory to the stack. Thus, when func tries to write a byte to the end of buf, it is outside of the process's committed memory which causes an exception to be raised.
The third exe, gsOk_2.exe allocates the same amount on the stack. But this time, the /Gs option instructs the compiler to insert a call to chkstk (which is defined in chkstk.asm) when the function is entered. chkstk touches every page that is needed on the stack, thus giving the OS the opportunity to commit more memory to the stack. So, this exe runs ok.
all: gsOK.exe gsFail.exe gsOk_2.exe


gsOK.exe:   $(@B).obj
	link /nologo $** /subsystem:console /entry:start /nodefaultlib user32.lib kernel32.lib            /OUT:$@

gsFail.exe: $(@B).obj
	link /nologo $** /subsystem:console /entry:start /nodefaultlib user32.lib kernel32.lib            /OUT:$@

gsOK_2.exe: $(@B).obj
	link /nologo $** /subsystem:console /entry:start /nodefaultlib user32.lib kernel32.lib chkstk.obj /OUT:$@

gsOK.obj:   gs.c
	cl /nologo /GS-            /c /W4 /DBUFSIZE=20     $** /Fo$@

gsFail.obj: gs.c
	cl /nologo /GS- /Gs1000000 /c /W4 /DBUFSIZE=200000 $** /Fo$@

gsOk_2.obj: gs.c
	cl /nologo /GS-            /c /W4 /DBUFSIZE=200000 $** /Fo$@

chkstk.obj: chkstk.asm
	ml $** /Fo$@

clean:
	del *.obj *.exe
Github repository about-cl, path: /options/G/s_/Makefile

chkstk.asm

This file is basically a copy lf chkstk.asm as found in Visual Studio's CRT. It is explicitly needed for this example because the example does not link with default libs.
In an application in the wild, this would not really be needed because the function is included with the CRT DLL.
;
; chkstk.asm: taken from Microsoft's Runtime chkstk.asm
;

_PAGESIZE_      equ     1000h


        CODESEG

page

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
Github repository about-cl, path: /options/G/s_/chkstk.asm

See also

chkstk.asm
cl options

Index