Fix kernel-mode executive atom implementation (mostly add SEH and tidy up the code). Then fix kernel32 implementation which was sending incorrect sizes, and also re-factored the entire code, since most functions were quatriplicated. now there are 3 main functions instead of 12. Also fixed a bug in RtlCreateAtomTable.

svn path=/trunk/; revision=20414
This commit is contained in:
Alex Ionescu 2005-12-29 08:43:45 +00:00
parent 00a70f69db
commit cf56f16a98
3 changed files with 699 additions and 608 deletions

File diff suppressed because it is too large Load diff

View file

@ -150,6 +150,9 @@ RtlCreateAtomTable(IN ULONG TableSize,
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
/* Use default if size was incorrect */
if (TableSize <= 1) TableSize = 37;
/* allocate atom table */ /* allocate atom table */
Table = RtlpAllocAtomTable(((TableSize - 1) * sizeof(PRTL_ATOM_TABLE_ENTRY)) + Table = RtlpAllocAtomTable(((TableSize - 1) * sizeof(PRTL_ATOM_TABLE_ENTRY)) +
sizeof(RTL_ATOM_TABLE)); sizeof(RTL_ATOM_TABLE));
@ -507,27 +510,22 @@ RtlLookupAtomInAtomTable(IN PRTL_ATOM_TABLE AtomTable,
} }
RtlpLockAtomTable(AtomTable); RtlpLockAtomTable(AtomTable);
Status = STATUS_OBJECT_NAME_NOT_FOUND; Status = STATUS_OBJECT_NAME_NOT_FOUND;
/* string atom */ /* string atom */
Entry = RtlpHashAtomName(AtomTable, Entry = RtlpHashAtomName(AtomTable,
AtomName, AtomName,
&HashLink); &HashLink);
if (Entry != NULL) if (Entry != NULL)
{ {
Status = STATUS_SUCCESS; Status = STATUS_SUCCESS;
FoundAtom = (RTL_ATOM)Entry->Atom; FoundAtom = (RTL_ATOM)Entry->Atom;
} }
RtlpUnlockAtomTable(AtomTable); RtlpUnlockAtomTable(AtomTable);
if (NT_SUCCESS(Status) && Atom != NULL) if (NT_SUCCESS(Status) && Atom != NULL)
{ {
*Atom = FoundAtom; *Atom = FoundAtom;
} }
return Status; return Status;
} }

View file

@ -13,6 +13,8 @@
#define NDEBUG #define NDEBUG
#include <internal/debug.h> #include <internal/debug.h>
#define TAG_ATOM TAG('A', 't', 'o', 'm')
/* GLOBALS ****************************************************************/ /* GLOBALS ****************************************************************/
/* /*
@ -45,79 +47,6 @@ ExpGetGlobalAtomTable(VOID)
return GlobalAtomTable; return GlobalAtomTable;
} }
NTSTATUS
NTAPI
RtlpQueryAtomInformation(PRTL_ATOM_TABLE AtomTable,
RTL_ATOM Atom,
PATOM_BASIC_INFORMATION AtomInformation,
ULONG AtomInformationLength,
PULONG ReturnLength)
{
NTSTATUS Status;
ULONG UsageCount;
ULONG Flags;
ULONG NameLength;
NameLength = AtomInformationLength - sizeof(ATOM_BASIC_INFORMATION) + sizeof(WCHAR);
Status = RtlQueryAtomInAtomTable(AtomTable,
Atom,
&UsageCount,
&Flags,
AtomInformation->Name,
&NameLength);
if (!NT_SUCCESS(Status)) return Status;
DPRINT("NameLength: %lu\n", NameLength);
if (ReturnLength != NULL)
{
*ReturnLength = NameLength + sizeof(ATOM_BASIC_INFORMATION);
}
if (NameLength + sizeof(ATOM_BASIC_INFORMATION) > AtomInformationLength)
{
return STATUS_INFO_LENGTH_MISMATCH;
}
AtomInformation->UsageCount = (USHORT)UsageCount;
AtomInformation->Flags = (USHORT)Flags;
AtomInformation->NameLength = (USHORT)NameLength;
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
RtlpQueryAtomTableInformation(PRTL_ATOM_TABLE AtomTable,
RTL_ATOM Atom,
PATOM_TABLE_INFORMATION AtomInformation,
ULONG AtomInformationLength,
PULONG ReturnLength)
{
ULONG Length;
NTSTATUS Status;
Length = sizeof(ATOM_TABLE_INFORMATION);
DPRINT("RequiredLength: %lu\n", Length);
if (ReturnLength) *ReturnLength = Length;
if (Length > AtomInformationLength) return STATUS_INFO_LENGTH_MISMATCH;
Status = RtlQueryAtomListInAtomTable(AtomTable,
(AtomInformationLength - Length) /
sizeof(RTL_ATOM),
&AtomInformation->NumberOfAtoms,
AtomInformation->Atoms);
if (NT_SUCCESS(Status))
{
ReturnLength += AtomInformation->NumberOfAtoms * sizeof(RTL_ATOM);
if (ReturnLength != NULL) *ReturnLength = Length;
}
return Status;
}
/* FUNCTIONS ****************************************************************/ /* FUNCTIONS ****************************************************************/
/* /*
@ -130,14 +59,96 @@ NtAddAtom(IN PWSTR AtomName,
OUT PRTL_ATOM Atom) OUT PRTL_ATOM Atom)
{ {
PRTL_ATOM_TABLE AtomTable = ExpGetGlobalAtomTable(); PRTL_ATOM_TABLE AtomTable = ExpGetGlobalAtomTable();
NTSTATUS Status = STATUS_SUCCESS;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
LPWSTR CapturedName = NULL;
ULONG CapturedSize;
RTL_ATOM SafeAtom;
PAGED_CODE();
/* Check for the table */ /* Check for the table */
if (AtomTable == NULL) return STATUS_ACCESS_DENIED; if (AtomTable == NULL) return STATUS_ACCESS_DENIED;
/* FIXME: SEH! */ /* Check for valid name */
if (AtomNameLength > (RTL_MAXIMUM_ATOM_LENGTH * sizeof(WCHAR)))
{
/* Fail */
DPRINT1("Atom name too long\n");
return STATUS_INVALID_PARAMETER;
}
/* Call the worker function */ /* Check if we're called from user-mode*/
return RtlAddAtomToAtomTable(AtomTable, AtomName, Atom); if (PreviousMode != KernelMode)
{
/* Enter SEH */
_SEH_TRY
{
/* Check if we have a name */
if (AtomName)
{
/* Probe the atom */
ProbeForRead(AtomName, AtomNameLength, sizeof(WCHAR));
/* Allocate an aligned buffer + the null char */
CapturedSize = ((AtomNameLength + sizeof(WCHAR)) &~
(sizeof(WCHAR) -1));
CapturedName = ExAllocatePoolWithTag(PagedPool,
CapturedSize,
TAG_ATOM);
if (!CapturedName)
{
/* Fail the call */
Status = STATUS_INSUFFICIENT_RESOURCES;
}
else
{
/* Copy the name and null-terminate it */
RtlMoveMemory(CapturedName, AtomName, AtomNameLength);
CapturedName[AtomNameLength / sizeof(WCHAR)] = UNICODE_NULL;
}
/* Probe the atom too */
if (Atom) ProbeForWriteUshort(Atom);
}
}
_SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
{
Status = _SEH_GetExceptionCode();
}
_SEH_END;
}
else
{
/* Simplify code and re-use one variable */
if (AtomName) CapturedName = AtomName;
}
/* Make sure probe worked */
if (NT_SUCCESS(Status))
{
/* Call the runtime function */
Status = RtlAddAtomToAtomTable(AtomTable, CapturedName, &SafeAtom);
if (NT_SUCCESS(Status) && (Atom))
{
/* Success and caller wants the atom back.. .enter SEH */
_SEH_TRY
{
/* Return the atom */
*Atom = SafeAtom;
}
_SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
{
Status = _SEH_GetExceptionCode();
}
_SEH_END;
}
}
/* If we captured anything, free it */
if ((CapturedName) && (CapturedName != AtomName)) ExFreePool(CapturedName);
/* Return to caller */
return Status;
} }
/* /*
@ -148,6 +159,7 @@ NTAPI
NtDeleteAtom(IN RTL_ATOM Atom) NtDeleteAtom(IN RTL_ATOM Atom)
{ {
PRTL_ATOM_TABLE AtomTable = ExpGetGlobalAtomTable(); PRTL_ATOM_TABLE AtomTable = ExpGetGlobalAtomTable();
PAGED_CODE();
/* Check for valid table */ /* Check for valid table */
if (AtomTable == NULL) return STATUS_ACCESS_DENIED; if (AtomTable == NULL) return STATUS_ACCESS_DENIED;
@ -166,14 +178,96 @@ NtFindAtom(IN PWSTR AtomName,
OUT PRTL_ATOM Atom) OUT PRTL_ATOM Atom)
{ {
PRTL_ATOM_TABLE AtomTable = ExpGetGlobalAtomTable(); PRTL_ATOM_TABLE AtomTable = ExpGetGlobalAtomTable();
NTSTATUS Status = STATUS_SUCCESS;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
LPWSTR CapturedName = NULL;
ULONG CapturedSize;
RTL_ATOM SafeAtom;
PAGED_CODE();
/* Check for valid table */ /* Check for the table */
if (AtomTable == NULL) return STATUS_ACCESS_DENIED; if (AtomTable == NULL) return STATUS_ACCESS_DENIED;
/* FIXME: SEH!!! */ /* Check for valid name */
if (AtomNameLength > (RTL_MAXIMUM_ATOM_LENGTH * sizeof(WCHAR)))
{
/* Fail */
DPRINT1("Atom name too long\n");
return STATUS_INVALID_PARAMETER;
}
/* Call worker function */ /* Check if we're called from user-mode*/
return RtlLookupAtomInAtomTable(AtomTable, AtomName, Atom); if (PreviousMode != KernelMode)
{
/* Enter SEH */
_SEH_TRY
{
/* Check if we have a name */
if (AtomName)
{
/* Probe the atom */
ProbeForRead(AtomName, AtomNameLength, sizeof(WCHAR));
/* Allocate an aligned buffer + the null char */
CapturedSize = ((AtomNameLength + sizeof(WCHAR)) &~
(sizeof(WCHAR) -1));
CapturedName = ExAllocatePoolWithTag(PagedPool,
CapturedSize,
TAG_ATOM);
if (!CapturedName)
{
/* Fail the call */
Status = STATUS_INSUFFICIENT_RESOURCES;
}
else
{
/* Copy the name and null-terminate it */
RtlMoveMemory(CapturedName, AtomName, AtomNameLength);
CapturedName[AtomNameLength / sizeof(WCHAR)] = UNICODE_NULL;
}
/* Probe the atom too */
if (Atom) ProbeForWriteUshort(Atom);
}
}
_SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
{
Status = _SEH_GetExceptionCode();
}
_SEH_END;
}
else
{
/* Simplify code and re-use one variable */
if (AtomName) CapturedName = AtomName;
}
/* Make sure probe worked */
if (NT_SUCCESS(Status))
{
/* Call the runtime function */
Status = RtlLookupAtomInAtomTable(AtomTable, CapturedName, &SafeAtom);
if (NT_SUCCESS(Status) && (Atom))
{
/* Success and caller wants the atom back.. .enter SEH */
_SEH_TRY
{
/* Return the atom */
*Atom = SafeAtom;
}
_SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
{
Status = _SEH_GetExceptionCode();
}
_SEH_END;
}
}
/* If we captured anything, free it */
if ((CapturedName) && (CapturedName != AtomName)) ExFreePool(CapturedName);
/* Return to caller */
return Status;
} }
/* /*
@ -188,7 +282,10 @@ NtQueryInformationAtom(RTL_ATOM Atom,
PULONG ReturnLength) PULONG ReturnLength)
{ {
PRTL_ATOM_TABLE AtomTable = ExpGetGlobalAtomTable(); PRTL_ATOM_TABLE AtomTable = ExpGetGlobalAtomTable();
PATOM_BASIC_INFORMATION BasicInformation = AtomInformation;
PATOM_TABLE_INFORMATION TableInformation = AtomInformation;
NTSTATUS Status; NTSTATUS Status;
ULONG Flags, UsageCount, NameLength;
/* Check for valid table */ /* Check for valid table */
if (AtomTable == NULL) return STATUS_ACCESS_DENIED; if (AtomTable == NULL) return STATUS_ACCESS_DENIED;
@ -198,23 +295,70 @@ NtQueryInformationAtom(RTL_ATOM Atom,
/* Choose class */ /* Choose class */
switch (AtomInformationClass) switch (AtomInformationClass)
{ {
/* Caller requested info about an atom */
case AtomBasicInformation: case AtomBasicInformation:
Status = RtlpQueryAtomInformation(AtomTable,
Atom, /* Size check */
AtomInformation, *ReturnLength = FIELD_OFFSET(ATOM_BASIC_INFORMATION, Name);
AtomInformationLength, if (*ReturnLength > AtomInformationLength)
ReturnLength); {
/* Fail */
DPRINT1("Buffer too small\n");
return STATUS_INFO_LENGTH_MISMATCH;
}
/* Prepare query */
UsageCount = 0;
NameLength = AtomInformationLength - *ReturnLength;
BasicInformation->Name[0] = UNICODE_NULL;
/* Query the data */
Status = RtlQueryAtomInAtomTable(AtomTable,
Atom,
&UsageCount,
&Flags,
BasicInformation->Name,
&NameLength);
if (NT_SUCCESS(Status))
{
/* Return data */
BasicInformation->UsageCount = (USHORT)UsageCount;
BasicInformation->Flags = (USHORT)Flags;
BasicInformation->NameLength = (USHORT)NameLength;
*ReturnLength += NameLength + sizeof(WCHAR);
}
break; break;
/* Caller requested info about an Atom Table */
case AtomTableInformation: case AtomTableInformation:
Status = RtlpQueryAtomTableInformation(AtomTable,
Atom, /* Size check */
AtomInformation, *ReturnLength = FIELD_OFFSET(ATOM_TABLE_INFORMATION, Atoms);
AtomInformationLength, if (*ReturnLength > AtomInformationLength)
ReturnLength); {
/* Fail */
DPRINT1("Buffer too small\n");
return STATUS_INFO_LENGTH_MISMATCH;
}
/* Query the data */
Status = RtlQueryAtomListInAtomTable(AtomTable,
(AtomInformationLength - *ReturnLength) /
sizeof(RTL_ATOM),
&TableInformation->NumberOfAtoms,
TableInformation->Atoms);
if (NT_SUCCESS(Status))
{
/* Update the return length */
*ReturnLength += TableInformation->NumberOfAtoms *
sizeof(RTL_ATOM);
}
break; break;
/* Caller was on crack */
default: default:
/* Unrecognized class */
Status = STATUS_INVALID_INFO_CLASS; Status = STATUS_INVALID_INFO_CLASS;
} }