・本の処分に困る
スキャンするとかゆー話ではなく、
置き場所がないんだけどすぐに読む余裕はなくて
でも読まずに捨てるのはどーよって話で、さてどうしよう。
Head First Statistics とか
Java のデザインパターン本とか
Effective C# とか
More Effective C# とか。
あ、今日もなんだかんだで shibuya.lisp#5 の話を書く時間がががが ○| ̄|_
_tcscpy_s(wcscpy_s)の第二引数って(1/1) | OKWave
の話のつづき。
#define _UNICODE
#define UNICODE
#define WIN32_MEAN_AND_LEAN
#include <windows.h>
#include <tchar.h>
TCHAR *fn;
void
OMG(LPCTSTR c)
{
int bytes = (_tcslen(c) + 1 )*sizeof(TCHAR);
int ret;
printf("bytes=%d\n", bytes);
if ( fn = (TCHAR*)malloc( bytes ) ) {
ret = _tcscpy_s(fn, bytes, c ); //実行しないでください
printf("ret=%d\n", ret);
}
else {
return;
}
/* fnを使用 */
free(fn);
fn=0;
}
int
_tmain()
{
OMG(_TEXT("HELLO"));
}
と、テキトーに _tmain() やら追加して試してみると、_UNICODEでもそうでなくても
パラメーターによっては「_tcscpy_s()の中で落っこちる」(実態は strcpy_s か wcscpy_s)
のが確認できました。んで、ソースをみると(2005のものです)
/***
*strcpy_s.c - contains strcpy_s()
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
*Purpose:
* strcpy_s() copies one string onto another.
*
*******************************************************************************/
#include <string.h>
#include <internal_securecrt.h>
#define _FUNC_PROLOGUE
#define _FUNC_NAME strcpy_s
#define _CHAR char
#define _DEST _Dst
#define _SIZE _SizeInBytes
#define _SRC _Src
#include <tcscpy_s.inl>
/***
*tcscpy_s.inl - general implementation of _tcscpy_s
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
*Purpose:
* This file contains the general algorithm for strcpy_s and its variants.
*
****/
_FUNC_PROLOGUE
errno_t __cdecl _FUNC_NAME(_CHAR *_DEST, size_t _SIZE, const _CHAR *_SRC)
{
_CHAR *p;
size_t available;
/* validation section */
_VALIDATE_STRING(_DEST, _SIZE);
_VALIDATE_POINTER_RESET_STRING(_SRC, _DEST, _SIZE);
p = _DEST;
available = _SIZE;
while ((*p++ = *_SRC++) != 0 && --available > 0)
{
}
if (available == 0)
{
_RESET_STRING(_DEST, _SIZE);
_RETURN_BUFFER_TOO_SMALL(_DEST, _SIZE);
}
_FILL_STRING(_DEST, _SIZE, _SIZE - available + 1);
_RETURN_NO_ERROR;
}
となっていて、どーしたってオーバーラン起こして落ちるようには見えない。
なんだろなあと思いつつ、デバッグモードでコンパイルして落ちた場所を確認すると
_VALIDATE_STRING(_DEST, _SIZE);
で、例外ハンドラーに飛んでいました。んじゃあとさらにソースを追いかけると
/***
*internal_securecrt.h - contains declarations of internal routines and variables for securecrt
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
*Purpose:
* Declares routines and variables used internally in the SecureCRT implementation.
* In this include file we define the macros needed to implement the secure functions
* inlined in the *.inl files like tcscpy_s.inl, etc.
* Note that this file is used for the CRT implementation, while internal_safecrt is used
* to build the downlevel library safecrt.lib.
*
* [Internal]
*
****/
#pragma once
#ifndef _INC_INTERNAL_SECURECRT
#define _INC_INTERNAL_SECURECRT
#include <internal.h>
(略)
/* validations */
#define _VALIDATE_STRING_ERROR(_String, _Size, _Ret) \
_VALIDATE_RETURN((_String) != NULL && (_Size) > 0, EINVAL, (_Ret))
#define _VALIDATE_STRING(_String, _Size) \
_VALIDATE_STRING_ERROR((_String), (_Size), EINVAL)
(略)
_VALIDATE_RETURN は別のファイルにあって、
internal.h
/*
* Assert in debug builds.
* set errno and return value
*/
#ifndef _VALIDATE_RETURN
#define _VALIDATE_RETURN( expr, errorcode, retexpr ) \
{ \
int _Expr_val=!!(expr); \
_ASSERT_EXPR( ( _Expr_val ), _CRT_WIDE(#expr) ); \
if ( !( _Expr_val ) ) \
{ \
errno = errorcode; \
_INVALID_PARAMETER(_CRT_WIDE(#expr) ); \
return ( retexpr ); \
} \
}
#endif /* _VALIDATE_RETURN */
こんなの。コメントを信じると、
リリースモードなら例外を送出しそうにないんですが、うーむ。
strcpy_s really safe? in VC Language
strcpy_s really safe?
richard posted on Thursday, February 15, 2007 10:21 AM
I get a fatal error in both debug and release mode using strcpy_s function
with the following code.
Same problem in VS2005 and VS2005 SP1
char sTest[5];
strcpy_s(sTest,5,"0123456789");
I think it should in this case only copy the 4th first characters together
with a '\0' character at the end...but having my application crashing is
quirte unexpected!
strcpy_s really safe?
P.J. Plauger posted on Thursday, February 15, 2007 11:58 AM
strcpy_s in this case should report a runtime constraint violation,
which may be the "crash" you're witnessing. If the constraint handler
returns, the function stores a null character at sTest[0] and returns
a nonzero value.
At least that's the behavior required by TR24731, and I think Microsoft
conforms in this regard.
P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com
I cannot believe it's a normal behaviour getting a fatal error from strcpy_s
richard posted on Thursday, February 15, 2007 12:39 PM
The strcpy_s doens't returns anything, it just crashes
This function is quite easy to understand, it copies bytes by bytes as long
it doesn't overlap.
In case of buffer overlap, that is the case in my sample, it should return
something, at least a return value ....
I never saw so far a function that voluntarily make the program crash with a
fatal error!
This is not an exception, it cannot be even catched by try method
strcpy_s function :
_FUNC_PROLOGUE
errno_t __cdecl _FUNC_NAME(_CHAR *_DEST, size_t _SIZE, const _CHAR *_SRC)
{
_CHAR *p;
size_t available;
/* validation section */
_VALIDATE_STRING(_DEST, _SIZE);
_VALIDATE_POINTER_RESET_STRING(_SRC, _DEST, _SIZE);
p = _DEST;
available = _SIZE;
while ((*p++ = *_SRC++) != 0 && --available > 0)
{
}
if (available == 0)
{
_RESET_STRING(_DEST, _SIZE);
_RETURN_BUFFER_TOO_SMALL(_DEST, _SIZE);
}
_FILL_STRING(_DEST, _SIZE, _SIZE - available + 1);
_RETURN_NO_ERROR;
}
reply
strcpy_s really safe?
Arnie posted on Thursday, February 15, 2007 3:26 PM
Tou're misunderstanding how it's supposed to work. Check the VS 2005
documentation for strcpy_s. Especially the part that says:
If strDestination or strSource is a null pointer, or if the destination
string is too small, the invalid parameter handler is invoked as described
in Parameter Validation. If execution is allowed to continue, these
functions return EINVAL and set errno to EINVAL.
- Arnie
reply
strcpy_s really safe?
Tamas Demjen posted on Thursday, February 15, 2007 5:41 PM
The behavior that you're looking for can be implemented using strncpy.
Note, however, that strncpy won't NUL terminate your string if it runs
out of the buffer. Take a look at this:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt_strncpy.2c_.wcsncpy.2c_._mbsncpy.asp
The strncpy function copies the initial count characters of strSource to
strDest and returns strDest. If count is less than or equal to the
length of strSource, a null character is not appended automatically to
the copied string. If count is greater than the length of strSource, the
destination string is padded with null characters up to length count.
What Microsoft calls a null character is actually a NUL (the '\0').
What you want to achieve can be done this way:
char sTest[5];
strncpy(sTest, "0123456789", 5);
sTest[4] = '\0'; // <- yes, this is necessary too!
Finally, there's also an strncpy_s function.
Tom
I cannot believe it's a normal behaviour getting a fatal error from strcpy_s
Tim Roberts posted on Friday, February 16, 2007 1:24 AM
No, it shouldn't. strcpy_s is merely an implementation of strcpy, and the
ISO definition of strcpy says that the behavior when the strings overlap is
undefined. That means it can do anything it wants, including crashing the
program.
What are you expecting it to do?
No, but it can certainly be detected before calling the function. If you
need to strcpy overlapping strings, you'll need to do this:
int x = strlen(src);
memmove( dst, src, x+1 );
--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.
I cannot believe it's a normal behaviour getting a fatal error from strcpy_s
Ulrich Eckhardt posted on Friday, February 16, 2007 3:26 AM
Firstly, did you read and understand what this 'constraint handler' is? Now,
two things:
1. It's not strcpy_s that makes your program not work but it is your code.
You are simply supplying invalid parameters that, if used with strcpy,
would have invoked undefined behaviour but are caught by strcpy_s. It
doesn't change the fact that your code is buggy though.
2. When strcpy_s detects that the calling code is buggy (as it is the case
in your example), what should it do? Should it just do "something" and then
return to the caller, possibly facing buffer overruns and the resulting
exploits? No, when it detects this, it simply aborts the process, because
when the process is already in an inconsistent state, there is nothing left
it could do.
Without looking at TR24731, I guess that it first calls the constraint
handler, which still gives you a way to customise what happens.
Ah well, how many people check the returnvalue of functions that "obviously
can't fail" because "no user will ever enter something that is longer than
200 characters".
Then take a look at the assert() macro. Aborting when nothing is left to be
saved is the only sane way to handle such errors.
An exception in C? Or are you using C++, then I wonder why you aren't using
std::string anyway.
Uli
Thanks for your help tamas demjen, tim roberts and Ulrich, indeed your are all
richard posted on Friday, February 16, 2007 4:08 AM
Thanks for your help tamas demjen, tim roberts and Ulrich, indeed your are
all right.
I simply misunderstood the function
ぷろーがー先生のリプライに
At least that's the behavior required by TR24731, and I think Microsoft conforms in this regard.
ってあるんですよねえ。
そらまあ、忘れた頃にこけるよりは百倍ましなんでしょうけども。
でもそうだとしても、MSDNにある記述とつじつま合ってないんじゃなかろうか…