RtlCopyMemory PUNICODE_STRING 到 WCHAR 段错误
RtlCopyMemory PUNICODE_STRING to WCHAR segfaults
我实际上是在我的内核驱动程序中将 PUNICODE_STRING 转换为恒定大小的 WCHAR[],试图避免溢出。我的方法在 99% 的情况下都有效,但有时我会从第一个 RtlCopyMemory 得到分段错误,调试器最有用的输出类似于:
PAGE_FAULT_IN_NONPAGED_AREA (50)
Invalid system memory was referenced. This cannot be protected by try-except,
it must be protected by a Probe. Typically the address is just plain bad or it
is pointing at freed memory.
Arguments:
Arg1: ffffc0016c0dd000, memory referenced.
Arg2: 0000000000000000, value 0 = read operation, 1 = write operation.
Arg3: fffff800adea85bd, If non-zero, the instruction address which referenced the bad memory
address.
Arg4: 0000000000000000, (reserved)
我的方法有什么问题(参见下面的示例)?
typedef struct _MYRESULT {
WCHAR Result[512];
} MYRESULT;
void myFunction(
_Inout_ MYRESULT *result,
_In_ PUNICODE_STRING s
)
{
if (s->Length < 511) {
// It is usually this RtlCopyMemory that crashes the kernel
RtlCopyMemory(result->Result, s->Buffer, sizeof(WCHAR)*s->Length);
// NULL terminate
result->Result[(sizeof)WCHAR)*s->Length)] = 0;
} else {
RtlCopyMemory(result->Result, s->Buffer, sizeof(WCHAR)*512);
// NULL terminate
result->Result[511] = 0;
}
}
代码复制了太多数据。
来自MSDN on UNICODE_STRING
(我强调):
Length
Specifies the length, in bytes, of the string pointed to by the Buffer member, not including the terminating NULL character, if any.
从对 RtlCopyMemory()
的调用中删除 sizeof(WCHAR)
。
void myFunction(
_Inout_ MYRESULT *result,
_In_ PUNICODE_STRING s
)
{
if (s->Length < (511 * sizeof * result)) {
// It is usually this RtlCopyMemory that crashes the kernel
RtlCopyMemory(result->Result, s->Buffer, s->Length);
// NULL terminate
result->Result[(sizeof)WCHAR)*s->Length)] = 0;
} else {
RtlCopyMemory(result->Result, s->Buffer, 512);
// NULL terminate
result->Result[511 * sizeof * result] = 0;
}
}
或不太容易出错(也遵循 DRY principle):
#define RESULT_MAXIMUMLENGTH (511) /* This needs to stay smaller
then USHORT_MAX / sizeof * MYRESULT.Result. */
typedef struct _MYRESULT {
WCHAR Result[RESULT_MAXIMUMLENGTH + 1];
} MYRESULT;
void myFunction(
_Inout_ MYRESULT *result,
_In_ PUNICODE_STRING s
)
{
USHORT len = (s->Length < (RESULT_MAXIMUMLENGTH * sizeof * result))
? s->Length
: RESULT_MAXIMUMLENGTH * sizeof * result;
RtlCopyMemory(result->Result, s->Buffer, len);
result->Result[len] = 0;
}
经验教训:RTFM 有帮助。
我实际上是在我的内核驱动程序中将 PUNICODE_STRING 转换为恒定大小的 WCHAR[],试图避免溢出。我的方法在 99% 的情况下都有效,但有时我会从第一个 RtlCopyMemory 得到分段错误,调试器最有用的输出类似于:
PAGE_FAULT_IN_NONPAGED_AREA (50)
Invalid system memory was referenced. This cannot be protected by try-except,
it must be protected by a Probe. Typically the address is just plain bad or it
is pointing at freed memory.
Arguments:
Arg1: ffffc0016c0dd000, memory referenced.
Arg2: 0000000000000000, value 0 = read operation, 1 = write operation.
Arg3: fffff800adea85bd, If non-zero, the instruction address which referenced the bad memory
address.
Arg4: 0000000000000000, (reserved)
我的方法有什么问题(参见下面的示例)?
typedef struct _MYRESULT {
WCHAR Result[512];
} MYRESULT;
void myFunction(
_Inout_ MYRESULT *result,
_In_ PUNICODE_STRING s
)
{
if (s->Length < 511) {
// It is usually this RtlCopyMemory that crashes the kernel
RtlCopyMemory(result->Result, s->Buffer, sizeof(WCHAR)*s->Length);
// NULL terminate
result->Result[(sizeof)WCHAR)*s->Length)] = 0;
} else {
RtlCopyMemory(result->Result, s->Buffer, sizeof(WCHAR)*512);
// NULL terminate
result->Result[511] = 0;
}
}
代码复制了太多数据。
来自MSDN on UNICODE_STRING
(我强调):
Length
Specifies the length, in bytes, of the string pointed to by the Buffer member, not including the terminating NULL character, if any.
从对 RtlCopyMemory()
的调用中删除 sizeof(WCHAR)
。
void myFunction(
_Inout_ MYRESULT *result,
_In_ PUNICODE_STRING s
)
{
if (s->Length < (511 * sizeof * result)) {
// It is usually this RtlCopyMemory that crashes the kernel
RtlCopyMemory(result->Result, s->Buffer, s->Length);
// NULL terminate
result->Result[(sizeof)WCHAR)*s->Length)] = 0;
} else {
RtlCopyMemory(result->Result, s->Buffer, 512);
// NULL terminate
result->Result[511 * sizeof * result] = 0;
}
}
或不太容易出错(也遵循 DRY principle):
#define RESULT_MAXIMUMLENGTH (511) /* This needs to stay smaller
then USHORT_MAX / sizeof * MYRESULT.Result. */
typedef struct _MYRESULT {
WCHAR Result[RESULT_MAXIMUMLENGTH + 1];
} MYRESULT;
void myFunction(
_Inout_ MYRESULT *result,
_In_ PUNICODE_STRING s
)
{
USHORT len = (s->Length < (RESULT_MAXIMUMLENGTH * sizeof * result))
? s->Length
: RESULT_MAXIMUMLENGTH * sizeof * result;
RtlCopyMemory(result->Result, s->Buffer, len);
result->Result[len] = 0;
}
经验教训:RTFM 有帮助。