2022-05-18 23:44:03 +04:30
|
|
|
/**
|
|
|
|
|
* @file common.c
|
|
|
|
|
* @author M.H. Gholamrezaei (mh@hyperdbg.org)
|
2023-01-18 20:23:40 +09:00
|
|
|
*
|
2022-05-18 23:44:03 +04:30
|
|
|
* @details Common routines
|
|
|
|
|
* @version 0.1
|
|
|
|
|
* @date 2020-10-22
|
|
|
|
|
*
|
|
|
|
|
* @copyright This project is released under the GNU Public License v3.
|
|
|
|
|
*
|
|
|
|
|
*/
|
2021-06-10 15:25:18 +04:30
|
|
|
#include "pch.h"
|
2020-12-01 22:26:46 +03:30
|
|
|
|
|
|
|
|
/**
|
2022-05-18 16:00:16 +09:00
|
|
|
* @brief Allocates a new token
|
2020-12-01 22:26:46 +03:30
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @return PSCRIPT_ENGINE_TOKEN the allocated new unknown token
|
2020-12-01 22:26:46 +03:30
|
|
|
*/
|
2025-07-07 11:46:10 -07:00
|
|
|
PSCRIPT_ENGINE_TOKEN
|
2022-05-07 22:51:55 +09:00
|
|
|
NewUnknownToken()
|
2020-12-01 22:26:46 +03:30
|
|
|
{
|
2025-07-07 11:46:10 -07:00
|
|
|
PSCRIPT_ENGINE_TOKEN Token;
|
2020-12-01 22:26:46 +03:30
|
|
|
|
2021-03-22 18:19:39 +04:30
|
|
|
//
|
2022-05-07 22:51:55 +09:00
|
|
|
// Allocate memory for token and its value
|
2021-03-22 18:19:39 +04:30
|
|
|
//
|
2025-07-07 11:46:10 -07:00
|
|
|
Token = (PSCRIPT_ENGINE_TOKEN)malloc(sizeof(SCRIPT_ENGINE_TOKEN));
|
2024-03-17 20:33:02 +09:00
|
|
|
|
|
|
|
|
if (Token == NULL)
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
// There was an error allocating buffer
|
|
|
|
|
//
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-21 18:17:17 +03:30
|
|
|
Token->Value = (char *)calloc(TOKEN_VALUE_MAX_LEN + 1, sizeof(char));
|
2020-12-01 22:26:46 +03:30
|
|
|
|
2024-03-17 20:33:02 +09:00
|
|
|
if (Token->Value == NULL)
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
// There was an error allocating buffer
|
|
|
|
|
//
|
2024-04-05 16:13:13 +03:00
|
|
|
free(Token);
|
2024-03-17 20:33:02 +09:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-22 18:19:39 +04:30
|
|
|
//
|
|
|
|
|
// Init fields
|
|
|
|
|
//
|
2022-03-21 23:42:00 +03:30
|
|
|
strcpy(Token->Value, "");
|
2025-10-21 16:46:49 +08:00
|
|
|
Token->Type = UNKNOWN;
|
|
|
|
|
Token->Len = 0;
|
|
|
|
|
Token->MaxLen = TOKEN_VALUE_MAX_LEN;
|
2025-10-21 12:56:21 +02:00
|
|
|
Token->VariableType = (VARIABLE_TYPE *)VARIABLE_TYPE_LONG;
|
2025-10-21 16:46:49 +08:00
|
|
|
Token->VariableMemoryIdx = 0;
|
2026-07-18 22:28:45 +08:00
|
|
|
Token->AddressSpace = 0;
|
|
|
|
|
Token->IsAddress = FALSE;
|
2026-07-20 23:21:34 +08:00
|
|
|
Token->IsImplicitType = FALSE;
|
2026-08-09 23:24:21 +08:00
|
|
|
Token->IsSignedFunctionResult = FALSE;
|
2022-05-07 22:51:55 +09:00
|
|
|
|
|
|
|
|
return Token;
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-07 23:33:36 +01:00
|
|
|
/**
|
|
|
|
|
* @brief Allocates a new token with given type and value
|
|
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param Type the type of the token
|
|
|
|
|
* @param Value the value string of the token
|
|
|
|
|
* @return PSCRIPT_ENGINE_TOKEN the allocated new token
|
2026-02-07 23:33:36 +01:00
|
|
|
*/
|
2025-07-07 11:46:10 -07:00
|
|
|
PSCRIPT_ENGINE_TOKEN
|
|
|
|
|
NewToken(SCRIPT_ENGINE_TOKEN_TYPE Type, char * Value)
|
2022-05-07 22:51:55 +09:00
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
// Allocate memory for token]
|
|
|
|
|
//
|
2025-07-07 11:46:10 -07:00
|
|
|
PSCRIPT_ENGINE_TOKEN Token = (PSCRIPT_ENGINE_TOKEN)malloc(sizeof(SCRIPT_ENGINE_TOKEN));
|
2022-05-18 23:44:03 +04:30
|
|
|
|
2024-03-17 20:33:02 +09:00
|
|
|
if (Token == NULL)
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
// There was an error allocating buffer
|
|
|
|
|
//
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-07 22:51:55 +09:00
|
|
|
//
|
|
|
|
|
// Init fields
|
|
|
|
|
//
|
Fix memory-safety and robustness issues in script engine and PCI ID parser
Code audit of the script engine's scanner/token handling and of the PCI ID
database parser. Each of the issues below was reproduced against the current
code before the fix and re-checked afterwards.
script-engine/scanner.c
* An unterminated string literal ("abc or L"abc) hung the scanner in an
endless loop: sgetc() returns EOF without consuming input, and neither
string loop tested for it, so the token grew until allocation failed.
Both loops now stop at EOF and report the token as UNKNOWN.
script-engine/common.c
* AppendByte()/AppendWchar() doubled Token->MaxLen before checking whether
the larger buffer was actually allocated. After a failed allocation MaxLen
described memory that did not exist and the next append wrote past the end
of the old buffer. MaxLen is now committed only on success.
* CopyToken() allocated strlen(Value) + 1 bytes but carried over the source
token's Len and MaxLen, so the copy's advertised capacity did not match its
allocation, and WSTRING payloads were truncated at their first embedded
null byte. The copy is now sized from Len/MaxLen and copied by length, with
a fallback to the string length for the grammar tokens in parse-table.c,
which only initialize Type and Value.
* NewToken() set MaxLen to the value length, which is zero for an empty
value. The 'Len >= MaxLen - 1' test in the append routines is unsigned, so
a zero MaxLen wrapped and disabled buffer growth entirely.
* IsUnderscore() tested 'c >= '_'', which also accepted the backtick, the
lowercase letters, '{', '|', '}', '~' and DEL. Register scanning uses it,
so '@rax|1' was lexed as one malformed register name instead of a register,
an operator and a number. The pseudo-register path already compared against
'_' directly.
* NewTokenList() did not check the allocation of its Head buffer.
* NewTemp() kept the last handed-out id in a static, so an exhausted temp
list produced a token aliasing a temporary still in use, and it derived
MaxTempNumber from an out-of-range index. It also dereferenced the new
token without a null check.
* FreeTemp() indexed the MAX_TEMP_COUNT-entry map with an unchecked value
parsed out of the token text.
* RotateLeftStringOnce() wrote to str[-1] when handed an empty string.
libhyperdbg/debugger/misc/pci-id.cpp
* The database file was read into a malloc(Length) buffer that was never
null-terminated, while ReadLine() walks it with strchr(). Looking up an
absent vendor scans to the end and reads past the allocation.
* The matched Vendor was allocated with malloc() and its Devices list head
was only assigned once a device line was parsed, so a vendor with no
device entries left it uninitialized and FreeVendor() walked a garbage
pointer.
* FreeVendor() released the device and subdevice lists but never the Vendor
itself, leaking one per lookup for every enumerated PCI device.
* The file handle leaked when the buffer allocation failed, ftell() and
fread() results were unused, and several error paths leaked the Vendor or
the not-yet-linked Device/SubDevice.
* strncmp() compared sizeof(VendorId) bytes, which is the size of the
pointer rather than the length of a vendor id.
* ReadLine() passed an unclamped count to strncpy_s(), which triggers the
invalid parameter handler for a line longer than the destination.
* GetVendorById() ignored the GetModuleFileName() result and overwrote the
tail of the path buffer without checking the room left in it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W3C1DuhHtqK64eEkHjKCHM
2026-08-01 14:22:52 +00:00
|
|
|
// Note that MaxLen is never allowed to be zero here. AppendByte()/AppendWchar()
|
|
|
|
|
// test for a full buffer with 'Len >= MaxLen - 1' on an unsigned type, so a zero
|
|
|
|
|
// MaxLen would wrap around and let those routines write past the allocation
|
|
|
|
|
//
|
2025-10-21 16:46:49 +08:00
|
|
|
unsigned int Len = (unsigned int)strlen(Value);
|
|
|
|
|
Token->Type = Type;
|
|
|
|
|
Token->Len = Len;
|
Fix memory-safety and robustness issues in script engine and PCI ID parser
Code audit of the script engine's scanner/token handling and of the PCI ID
database parser. Each of the issues below was reproduced against the current
code before the fix and re-checked afterwards.
script-engine/scanner.c
* An unterminated string literal ("abc or L"abc) hung the scanner in an
endless loop: sgetc() returns EOF without consuming input, and neither
string loop tested for it, so the token grew until allocation failed.
Both loops now stop at EOF and report the token as UNKNOWN.
script-engine/common.c
* AppendByte()/AppendWchar() doubled Token->MaxLen before checking whether
the larger buffer was actually allocated. After a failed allocation MaxLen
described memory that did not exist and the next append wrote past the end
of the old buffer. MaxLen is now committed only on success.
* CopyToken() allocated strlen(Value) + 1 bytes but carried over the source
token's Len and MaxLen, so the copy's advertised capacity did not match its
allocation, and WSTRING payloads were truncated at their first embedded
null byte. The copy is now sized from Len/MaxLen and copied by length, with
a fallback to the string length for the grammar tokens in parse-table.c,
which only initialize Type and Value.
* NewToken() set MaxLen to the value length, which is zero for an empty
value. The 'Len >= MaxLen - 1' test in the append routines is unsigned, so
a zero MaxLen wrapped and disabled buffer growth entirely.
* IsUnderscore() tested 'c >= '_'', which also accepted the backtick, the
lowercase letters, '{', '|', '}', '~' and DEL. Register scanning uses it,
so '@rax|1' was lexed as one malformed register name instead of a register,
an operator and a number. The pseudo-register path already compared against
'_' directly.
* NewTokenList() did not check the allocation of its Head buffer.
* NewTemp() kept the last handed-out id in a static, so an exhausted temp
list produced a token aliasing a temporary still in use, and it derived
MaxTempNumber from an out-of-range index. It also dereferenced the new
token without a null check.
* FreeTemp() indexed the MAX_TEMP_COUNT-entry map with an unchecked value
parsed out of the token text.
* RotateLeftStringOnce() wrote to str[-1] when handed an empty string.
libhyperdbg/debugger/misc/pci-id.cpp
* The database file was read into a malloc(Length) buffer that was never
null-terminated, while ReadLine() walks it with strchr(). Looking up an
absent vendor scans to the end and reads past the allocation.
* The matched Vendor was allocated with malloc() and its Devices list head
was only assigned once a device line was parsed, so a vendor with no
device entries left it uninitialized and FreeVendor() walked a garbage
pointer.
* FreeVendor() released the device and subdevice lists but never the Vendor
itself, leaking one per lookup for every enumerated PCI device.
* The file handle leaked when the buffer allocation failed, ftell() and
fread() results were unused, and several error paths leaked the Vendor or
the not-yet-linked Device/SubDevice.
* strncmp() compared sizeof(VendorId) bytes, which is the size of the
pointer rather than the length of a vendor id.
* ReadLine() passed an unclamped count to strncpy_s(), which triggers the
invalid parameter handler for a line longer than the destination.
* GetVendorById() ignored the GetModuleFileName() result and overwrote the
tail of the path buffer without checking the room left in it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W3C1DuhHtqK64eEkHjKCHM
2026-08-01 14:22:52 +00:00
|
|
|
Token->MaxLen = Len > TOKEN_VALUE_MAX_LEN ? Len : TOKEN_VALUE_MAX_LEN;
|
2025-10-21 16:46:49 +08:00
|
|
|
Token->Value = (char *)calloc(Token->MaxLen + 1, sizeof(char));
|
2025-10-21 12:56:21 +02:00
|
|
|
Token->VariableType = (VARIABLE_TYPE *)VARIABLE_TYPE_LONG;
|
2025-10-21 16:46:49 +08:00
|
|
|
Token->VariableMemoryIdx = 0;
|
2026-07-18 22:28:45 +08:00
|
|
|
Token->AddressSpace = 0;
|
|
|
|
|
Token->IsAddress = FALSE;
|
2026-07-20 23:21:34 +08:00
|
|
|
Token->IsImplicitType = FALSE;
|
2026-08-09 23:24:21 +08:00
|
|
|
Token->IsSignedFunctionResult = FALSE;
|
2024-03-17 20:33:02 +09:00
|
|
|
|
|
|
|
|
if (Token->Value == NULL)
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
// There was an error allocating buffer
|
|
|
|
|
//
|
2024-04-05 16:13:13 +03:00
|
|
|
free(Token);
|
2024-03-17 20:33:02 +09:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-07 22:51:55 +09:00
|
|
|
strcpy(Token->Value, Value);
|
2020-12-01 22:26:46 +03:30
|
|
|
|
2021-03-22 18:19:39 +04:30
|
|
|
return Token;
|
2020-12-01 22:26:46 +03:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2022-05-18 16:00:16 +09:00
|
|
|
* @brief Removes allocated memory of a token
|
2020-12-01 22:26:46 +03:30
|
|
|
*
|
|
|
|
|
* @param Token
|
2026-05-31 02:21:47 +02:00
|
|
|
* @return void
|
2020-12-01 22:26:46 +03:30
|
|
|
*/
|
2021-03-22 18:19:39 +04:30
|
|
|
void
|
2025-07-07 11:46:10 -07:00
|
|
|
RemoveToken(PSCRIPT_ENGINE_TOKEN * Token)
|
2020-12-01 22:26:46 +03:30
|
|
|
{
|
2022-05-19 20:16:57 +09:00
|
|
|
free((*Token)->Value);
|
|
|
|
|
free(*Token);
|
|
|
|
|
*Token = NULL;
|
2021-03-22 18:19:39 +04:30
|
|
|
return;
|
2020-12-01 22:26:46 +03:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2022-05-18 16:00:16 +09:00
|
|
|
* @brief Prints token
|
2026-05-31 02:21:47 +02:00
|
|
|
* @details prints value and type of token
|
2020-12-01 22:26:46 +03:30
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param Token the token to print
|
|
|
|
|
* @return void
|
2020-12-01 22:26:46 +03:30
|
|
|
*/
|
2021-03-22 18:19:39 +04:30
|
|
|
void
|
2025-07-07 11:46:10 -07:00
|
|
|
PrintToken(PSCRIPT_ENGINE_TOKEN Token)
|
2021-03-22 18:19:39 +04:30
|
|
|
{
|
|
|
|
|
//
|
2024-03-17 18:49:51 +09:00
|
|
|
// Prints value of the Token
|
2021-03-22 18:19:39 +04:30
|
|
|
//
|
|
|
|
|
if (Token->Type == WHITE_SPACE)
|
|
|
|
|
{
|
|
|
|
|
printf("< :");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
printf("<'%s' : ", Token->Value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Prints type of the Token
|
|
|
|
|
//
|
|
|
|
|
switch (Token->Type)
|
|
|
|
|
{
|
2021-09-26 21:42:36 +09:00
|
|
|
case GLOBAL_ID:
|
|
|
|
|
printf(" GLOBAL_ID>\n");
|
2021-03-22 18:19:39 +04:30
|
|
|
break;
|
2021-09-26 21:42:36 +09:00
|
|
|
case GLOBAL_UNRESOLVED_ID:
|
|
|
|
|
printf(" GLOBAL_UNRESOLVED_ID>\n");
|
|
|
|
|
break;
|
|
|
|
|
case LOCAL_ID:
|
|
|
|
|
printf(" LOCAL_ID>\n");
|
|
|
|
|
break;
|
|
|
|
|
case LOCAL_UNRESOLVED_ID:
|
|
|
|
|
printf(" LOCAL_UNRESOLVED_ID>\n");
|
2021-06-27 19:48:25 +04:30
|
|
|
break;
|
|
|
|
|
case STATE_ID:
|
|
|
|
|
printf(" STATE_ID>\n");
|
|
|
|
|
break;
|
2021-03-22 18:19:39 +04:30
|
|
|
case DECIMAL:
|
|
|
|
|
printf(" DECIMAL>\n");
|
|
|
|
|
break;
|
|
|
|
|
case HEX:
|
|
|
|
|
printf(" HEX>\n");
|
|
|
|
|
break;
|
|
|
|
|
case OCTAL:
|
|
|
|
|
printf(" OCTAL>\n");
|
|
|
|
|
break;
|
|
|
|
|
case BINARY:
|
|
|
|
|
printf(" BINARY>\n");
|
|
|
|
|
break;
|
|
|
|
|
case SPECIAL_TOKEN:
|
|
|
|
|
printf(" SPECIAL_TOKEN>\n");
|
|
|
|
|
break;
|
|
|
|
|
case KEYWORD:
|
|
|
|
|
printf(" KEYWORD>\n");
|
|
|
|
|
break;
|
|
|
|
|
case WHITE_SPACE:
|
|
|
|
|
printf(" WHITE_SPACE>\n");
|
|
|
|
|
break;
|
|
|
|
|
case COMMENT:
|
|
|
|
|
printf(" COMMENT>\n");
|
|
|
|
|
break;
|
|
|
|
|
case REGISTER:
|
|
|
|
|
printf(" REGISTER>\n");
|
|
|
|
|
break;
|
|
|
|
|
case PSEUDO_REGISTER:
|
|
|
|
|
printf(" PSEUDO_REGISTER>\n");
|
|
|
|
|
break;
|
|
|
|
|
case SEMANTIC_RULE:
|
|
|
|
|
printf(" SEMANTIC_RULE>\n");
|
|
|
|
|
break;
|
|
|
|
|
case NON_TERMINAL:
|
|
|
|
|
printf(" NON_TERMINAL>\n");
|
|
|
|
|
break;
|
|
|
|
|
case END_OF_STACK:
|
|
|
|
|
printf(" END_OF_STACK>\n");
|
|
|
|
|
break;
|
|
|
|
|
case STRING:
|
|
|
|
|
printf(" STRING>\n");
|
|
|
|
|
break;
|
2023-11-08 23:48:59 +08:00
|
|
|
case WSTRING:
|
|
|
|
|
printf(" WSTRING>\n");
|
|
|
|
|
break;
|
2021-03-22 18:19:39 +04:30
|
|
|
case TEMP:
|
|
|
|
|
printf(" TEMP>\n");
|
|
|
|
|
break;
|
|
|
|
|
case UNKNOWN:
|
|
|
|
|
printf(" UNKNOWN>\n");
|
|
|
|
|
break;
|
2024-07-25 01:52:58 +08:00
|
|
|
case SCRIPT_VARIABLE_TYPE:
|
|
|
|
|
printf(" SCRIPT_VARIABLE_TYPE>\n");
|
2024-03-02 01:59:33 +08:00
|
|
|
break;
|
2024-08-21 03:42:03 +08:00
|
|
|
case FUNCTION_ID:
|
|
|
|
|
printf(" FUNCTION_ID>\n");
|
2024-03-02 01:59:33 +08:00
|
|
|
break;
|
|
|
|
|
case FUNCTION_PARAMETER_ID:
|
|
|
|
|
printf(" FUNCTION_PARAMETER_ID>\n");
|
|
|
|
|
break;
|
2025-10-21 16:46:49 +08:00
|
|
|
case DEFERENCE_TEMP:
|
|
|
|
|
printf(" DEFERENCE_TEMP>\n");
|
|
|
|
|
break;
|
2021-03-22 18:19:39 +04:30
|
|
|
default:
|
|
|
|
|
printf(" ERROR>\n");
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-12-01 22:26:46 +03:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2022-05-18 16:00:16 +09:00
|
|
|
* @brief Appends char to the token value
|
2020-12-01 22:26:46 +03:30
|
|
|
*
|
|
|
|
|
* @param Token
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param c the character to append
|
|
|
|
|
* @return void
|
2020-12-01 22:26:46 +03:30
|
|
|
*/
|
2021-03-22 18:19:39 +04:30
|
|
|
void
|
2025-07-07 11:46:10 -07:00
|
|
|
AppendByte(PSCRIPT_ENGINE_TOKEN Token, char c)
|
2021-03-22 18:19:39 +04:30
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
// Check overflow of the string
|
|
|
|
|
//
|
2022-05-07 22:51:55 +09:00
|
|
|
if (Token->Len >= Token->MaxLen - 1)
|
2021-03-22 18:19:39 +04:30
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
// Double the length of the allocated space for the string
|
|
|
|
|
//
|
Fix memory-safety and robustness issues in script engine and PCI ID parser
Code audit of the script engine's scanner/token handling and of the PCI ID
database parser. Each of the issues below was reproduced against the current
code before the fix and re-checked afterwards.
script-engine/scanner.c
* An unterminated string literal ("abc or L"abc) hung the scanner in an
endless loop: sgetc() returns EOF without consuming input, and neither
string loop tested for it, so the token grew until allocation failed.
Both loops now stop at EOF and report the token as UNKNOWN.
script-engine/common.c
* AppendByte()/AppendWchar() doubled Token->MaxLen before checking whether
the larger buffer was actually allocated. After a failed allocation MaxLen
described memory that did not exist and the next append wrote past the end
of the old buffer. MaxLen is now committed only on success.
* CopyToken() allocated strlen(Value) + 1 bytes but carried over the source
token's Len and MaxLen, so the copy's advertised capacity did not match its
allocation, and WSTRING payloads were truncated at their first embedded
null byte. The copy is now sized from Len/MaxLen and copied by length, with
a fallback to the string length for the grammar tokens in parse-table.c,
which only initialize Type and Value.
* NewToken() set MaxLen to the value length, which is zero for an empty
value. The 'Len >= MaxLen - 1' test in the append routines is unsigned, so
a zero MaxLen wrapped and disabled buffer growth entirely.
* IsUnderscore() tested 'c >= '_'', which also accepted the backtick, the
lowercase letters, '{', '|', '}', '~' and DEL. Register scanning uses it,
so '@rax|1' was lexed as one malformed register name instead of a register,
an operator and a number. The pseudo-register path already compared against
'_' directly.
* NewTokenList() did not check the allocation of its Head buffer.
* NewTemp() kept the last handed-out id in a static, so an exhausted temp
list produced a token aliasing a temporary still in use, and it derived
MaxTempNumber from an out-of-range index. It also dereferenced the new
token without a null check.
* FreeTemp() indexed the MAX_TEMP_COUNT-entry map with an unchecked value
parsed out of the token text.
* RotateLeftStringOnce() wrote to str[-1] when handed an empty string.
libhyperdbg/debugger/misc/pci-id.cpp
* The database file was read into a malloc(Length) buffer that was never
null-terminated, while ReadLine() walks it with strchr(). Looking up an
absent vendor scans to the end and reads past the allocation.
* The matched Vendor was allocated with malloc() and its Devices list head
was only assigned once a device line was parsed, so a vendor with no
device entries left it uninitialized and FreeVendor() walked a garbage
pointer.
* FreeVendor() released the device and subdevice lists but never the Vendor
itself, leaking one per lookup for every enumerated PCI device.
* The file handle leaked when the buffer allocation failed, ftell() and
fread() results were unused, and several error paths leaked the Vendor or
the not-yet-linked Device/SubDevice.
* strncmp() compared sizeof(VendorId) bytes, which is the size of the
pointer rather than the length of a vendor id.
* ReadLine() passed an unclamped count to strncpy_s(), which triggers the
invalid parameter handler for a line longer than the destination.
* GetVendorById() ignored the GetModuleFileName() result and overwrote the
tail of the path buffer without checking the room left in it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W3C1DuhHtqK64eEkHjKCHM
2026-08-01 14:22:52 +00:00
|
|
|
unsigned int NewMaxLen = Token->MaxLen * 2;
|
|
|
|
|
char * NewValue = (char *)calloc(NewMaxLen + 1, sizeof(char));
|
2021-03-22 18:19:39 +04:30
|
|
|
|
2024-03-17 20:33:02 +09:00
|
|
|
if (NewValue == NULL)
|
|
|
|
|
{
|
Fix memory-safety and robustness issues in script engine and PCI ID parser
Code audit of the script engine's scanner/token handling and of the PCI ID
database parser. Each of the issues below was reproduced against the current
code before the fix and re-checked afterwards.
script-engine/scanner.c
* An unterminated string literal ("abc or L"abc) hung the scanner in an
endless loop: sgetc() returns EOF without consuming input, and neither
string loop tested for it, so the token grew until allocation failed.
Both loops now stop at EOF and report the token as UNKNOWN.
script-engine/common.c
* AppendByte()/AppendWchar() doubled Token->MaxLen before checking whether
the larger buffer was actually allocated. After a failed allocation MaxLen
described memory that did not exist and the next append wrote past the end
of the old buffer. MaxLen is now committed only on success.
* CopyToken() allocated strlen(Value) + 1 bytes but carried over the source
token's Len and MaxLen, so the copy's advertised capacity did not match its
allocation, and WSTRING payloads were truncated at their first embedded
null byte. The copy is now sized from Len/MaxLen and copied by length, with
a fallback to the string length for the grammar tokens in parse-table.c,
which only initialize Type and Value.
* NewToken() set MaxLen to the value length, which is zero for an empty
value. The 'Len >= MaxLen - 1' test in the append routines is unsigned, so
a zero MaxLen wrapped and disabled buffer growth entirely.
* IsUnderscore() tested 'c >= '_'', which also accepted the backtick, the
lowercase letters, '{', '|', '}', '~' and DEL. Register scanning uses it,
so '@rax|1' was lexed as one malformed register name instead of a register,
an operator and a number. The pseudo-register path already compared against
'_' directly.
* NewTokenList() did not check the allocation of its Head buffer.
* NewTemp() kept the last handed-out id in a static, so an exhausted temp
list produced a token aliasing a temporary still in use, and it derived
MaxTempNumber from an out-of-range index. It also dereferenced the new
token without a null check.
* FreeTemp() indexed the MAX_TEMP_COUNT-entry map with an unchecked value
parsed out of the token text.
* RotateLeftStringOnce() wrote to str[-1] when handed an empty string.
libhyperdbg/debugger/misc/pci-id.cpp
* The database file was read into a malloc(Length) buffer that was never
null-terminated, while ReadLine() walks it with strchr(). Looking up an
absent vendor scans to the end and reads past the allocation.
* The matched Vendor was allocated with malloc() and its Devices list head
was only assigned once a device line was parsed, so a vendor with no
device entries left it uninitialized and FreeVendor() walked a garbage
pointer.
* FreeVendor() released the device and subdevice lists but never the Vendor
itself, leaking one per lookup for every enumerated PCI device.
* The file handle leaked when the buffer allocation failed, ftell() and
fread() results were unused, and several error paths leaked the Vendor or
the not-yet-linked Device/SubDevice.
* strncmp() compared sizeof(VendorId) bytes, which is the size of the
pointer rather than the length of a vendor id.
* ReadLine() passed an unclamped count to strncpy_s(), which triggers the
invalid parameter handler for a line longer than the destination.
* GetVendorById() ignored the GetModuleFileName() result and overwrote the
tail of the path buffer without checking the room left in it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W3C1DuhHtqK64eEkHjKCHM
2026-08-01 14:22:52 +00:00
|
|
|
//
|
|
|
|
|
// MaxLen is only committed once the bigger buffer is in hand, otherwise
|
|
|
|
|
// it would describe a buffer that was never allocated and the next call
|
|
|
|
|
// would consider the (still small) buffer to have free space in it
|
|
|
|
|
//
|
2024-03-17 20:33:02 +09:00
|
|
|
printf("err, could not allocate buffer");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-22 18:19:39 +04:30
|
|
|
//
|
|
|
|
|
// Free Old buffer and update the pointer
|
|
|
|
|
//
|
2023-11-23 01:07:20 +08:00
|
|
|
memcpy(NewValue, Token->Value, Token->Len);
|
2021-03-22 18:19:39 +04:30
|
|
|
free(Token->Value);
|
Fix memory-safety and robustness issues in script engine and PCI ID parser
Code audit of the script engine's scanner/token handling and of the PCI ID
database parser. Each of the issues below was reproduced against the current
code before the fix and re-checked afterwards.
script-engine/scanner.c
* An unterminated string literal ("abc or L"abc) hung the scanner in an
endless loop: sgetc() returns EOF without consuming input, and neither
string loop tested for it, so the token grew until allocation failed.
Both loops now stop at EOF and report the token as UNKNOWN.
script-engine/common.c
* AppendByte()/AppendWchar() doubled Token->MaxLen before checking whether
the larger buffer was actually allocated. After a failed allocation MaxLen
described memory that did not exist and the next append wrote past the end
of the old buffer. MaxLen is now committed only on success.
* CopyToken() allocated strlen(Value) + 1 bytes but carried over the source
token's Len and MaxLen, so the copy's advertised capacity did not match its
allocation, and WSTRING payloads were truncated at their first embedded
null byte. The copy is now sized from Len/MaxLen and copied by length, with
a fallback to the string length for the grammar tokens in parse-table.c,
which only initialize Type and Value.
* NewToken() set MaxLen to the value length, which is zero for an empty
value. The 'Len >= MaxLen - 1' test in the append routines is unsigned, so
a zero MaxLen wrapped and disabled buffer growth entirely.
* IsUnderscore() tested 'c >= '_'', which also accepted the backtick, the
lowercase letters, '{', '|', '}', '~' and DEL. Register scanning uses it,
so '@rax|1' was lexed as one malformed register name instead of a register,
an operator and a number. The pseudo-register path already compared against
'_' directly.
* NewTokenList() did not check the allocation of its Head buffer.
* NewTemp() kept the last handed-out id in a static, so an exhausted temp
list produced a token aliasing a temporary still in use, and it derived
MaxTempNumber from an out-of-range index. It also dereferenced the new
token without a null check.
* FreeTemp() indexed the MAX_TEMP_COUNT-entry map with an unchecked value
parsed out of the token text.
* RotateLeftStringOnce() wrote to str[-1] when handed an empty string.
libhyperdbg/debugger/misc/pci-id.cpp
* The database file was read into a malloc(Length) buffer that was never
null-terminated, while ReadLine() walks it with strchr(). Looking up an
absent vendor scans to the end and reads past the allocation.
* The matched Vendor was allocated with malloc() and its Devices list head
was only assigned once a device line was parsed, so a vendor with no
device entries left it uninitialized and FreeVendor() walked a garbage
pointer.
* FreeVendor() released the device and subdevice lists but never the Vendor
itself, leaking one per lookup for every enumerated PCI device.
* The file handle leaked when the buffer allocation failed, ftell() and
fread() results were unused, and several error paths leaked the Vendor or
the not-yet-linked Device/SubDevice.
* strncmp() compared sizeof(VendorId) bytes, which is the size of the
pointer rather than the length of a vendor id.
* ReadLine() passed an unclamped count to strncpy_s(), which triggers the
invalid parameter handler for a line longer than the destination.
* GetVendorById() ignored the GetModuleFileName() result and overwrote the
tail of the path buffer without checking the room left in it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W3C1DuhHtqK64eEkHjKCHM
2026-08-01 14:22:52 +00:00
|
|
|
Token->Value = NewValue;
|
|
|
|
|
Token->MaxLen = NewMaxLen;
|
2021-03-22 18:19:39 +04:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
2024-03-17 18:49:51 +09:00
|
|
|
// Append the new character to the string
|
2021-03-22 18:19:39 +04:30
|
|
|
//
|
2023-11-23 01:07:20 +08:00
|
|
|
Token->Value[Token->Len] = c;
|
2022-05-07 22:51:55 +09:00
|
|
|
Token->Len++;
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-08 23:48:59 +08:00
|
|
|
/**
|
2026-08-09 23:24:21 +08:00
|
|
|
* @brief Appends one fixed-width UTF-16 code unit to the token value
|
2023-11-08 23:48:59 +08:00
|
|
|
*
|
|
|
|
|
* @param Token
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param c the wide character to append
|
|
|
|
|
* @return void
|
2023-11-08 23:48:59 +08:00
|
|
|
*/
|
|
|
|
|
void
|
2026-08-09 23:24:21 +08:00
|
|
|
AppendWchar(PSCRIPT_ENGINE_TOKEN Token, UINT16 c)
|
2023-11-08 23:48:59 +08:00
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
// Check overflow of the string
|
|
|
|
|
//
|
|
|
|
|
if (Token->Len >= Token->MaxLen - 2)
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
// Double the length of the allocated space for the wstring
|
|
|
|
|
//
|
Fix memory-safety and robustness issues in script engine and PCI ID parser
Code audit of the script engine's scanner/token handling and of the PCI ID
database parser. Each of the issues below was reproduced against the current
code before the fix and re-checked afterwards.
script-engine/scanner.c
* An unterminated string literal ("abc or L"abc) hung the scanner in an
endless loop: sgetc() returns EOF without consuming input, and neither
string loop tested for it, so the token grew until allocation failed.
Both loops now stop at EOF and report the token as UNKNOWN.
script-engine/common.c
* AppendByte()/AppendWchar() doubled Token->MaxLen before checking whether
the larger buffer was actually allocated. After a failed allocation MaxLen
described memory that did not exist and the next append wrote past the end
of the old buffer. MaxLen is now committed only on success.
* CopyToken() allocated strlen(Value) + 1 bytes but carried over the source
token's Len and MaxLen, so the copy's advertised capacity did not match its
allocation, and WSTRING payloads were truncated at their first embedded
null byte. The copy is now sized from Len/MaxLen and copied by length, with
a fallback to the string length for the grammar tokens in parse-table.c,
which only initialize Type and Value.
* NewToken() set MaxLen to the value length, which is zero for an empty
value. The 'Len >= MaxLen - 1' test in the append routines is unsigned, so
a zero MaxLen wrapped and disabled buffer growth entirely.
* IsUnderscore() tested 'c >= '_'', which also accepted the backtick, the
lowercase letters, '{', '|', '}', '~' and DEL. Register scanning uses it,
so '@rax|1' was lexed as one malformed register name instead of a register,
an operator and a number. The pseudo-register path already compared against
'_' directly.
* NewTokenList() did not check the allocation of its Head buffer.
* NewTemp() kept the last handed-out id in a static, so an exhausted temp
list produced a token aliasing a temporary still in use, and it derived
MaxTempNumber from an out-of-range index. It also dereferenced the new
token without a null check.
* FreeTemp() indexed the MAX_TEMP_COUNT-entry map with an unchecked value
parsed out of the token text.
* RotateLeftStringOnce() wrote to str[-1] when handed an empty string.
libhyperdbg/debugger/misc/pci-id.cpp
* The database file was read into a malloc(Length) buffer that was never
null-terminated, while ReadLine() walks it with strchr(). Looking up an
absent vendor scans to the end and reads past the allocation.
* The matched Vendor was allocated with malloc() and its Devices list head
was only assigned once a device line was parsed, so a vendor with no
device entries left it uninitialized and FreeVendor() walked a garbage
pointer.
* FreeVendor() released the device and subdevice lists but never the Vendor
itself, leaking one per lookup for every enumerated PCI device.
* The file handle leaked when the buffer allocation failed, ftell() and
fread() results were unused, and several error paths leaked the Vendor or
the not-yet-linked Device/SubDevice.
* strncmp() compared sizeof(VendorId) bytes, which is the size of the
pointer rather than the length of a vendor id.
* ReadLine() passed an unclamped count to strncpy_s(), which triggers the
invalid parameter handler for a line longer than the destination.
* GetVendorById() ignored the GetModuleFileName() result and overwrote the
tail of the path buffer without checking the room left in it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W3C1DuhHtqK64eEkHjKCHM
2026-08-01 14:22:52 +00:00
|
|
|
unsigned int NewMaxLen = Token->MaxLen * 2;
|
|
|
|
|
char * NewValue = (char *)calloc(NewMaxLen + 2, sizeof(char));
|
2023-11-08 23:48:59 +08:00
|
|
|
|
2024-03-17 20:33:02 +09:00
|
|
|
if (NewValue == NULL)
|
|
|
|
|
{
|
Fix memory-safety and robustness issues in script engine and PCI ID parser
Code audit of the script engine's scanner/token handling and of the PCI ID
database parser. Each of the issues below was reproduced against the current
code before the fix and re-checked afterwards.
script-engine/scanner.c
* An unterminated string literal ("abc or L"abc) hung the scanner in an
endless loop: sgetc() returns EOF without consuming input, and neither
string loop tested for it, so the token grew until allocation failed.
Both loops now stop at EOF and report the token as UNKNOWN.
script-engine/common.c
* AppendByte()/AppendWchar() doubled Token->MaxLen before checking whether
the larger buffer was actually allocated. After a failed allocation MaxLen
described memory that did not exist and the next append wrote past the end
of the old buffer. MaxLen is now committed only on success.
* CopyToken() allocated strlen(Value) + 1 bytes but carried over the source
token's Len and MaxLen, so the copy's advertised capacity did not match its
allocation, and WSTRING payloads were truncated at their first embedded
null byte. The copy is now sized from Len/MaxLen and copied by length, with
a fallback to the string length for the grammar tokens in parse-table.c,
which only initialize Type and Value.
* NewToken() set MaxLen to the value length, which is zero for an empty
value. The 'Len >= MaxLen - 1' test in the append routines is unsigned, so
a zero MaxLen wrapped and disabled buffer growth entirely.
* IsUnderscore() tested 'c >= '_'', which also accepted the backtick, the
lowercase letters, '{', '|', '}', '~' and DEL. Register scanning uses it,
so '@rax|1' was lexed as one malformed register name instead of a register,
an operator and a number. The pseudo-register path already compared against
'_' directly.
* NewTokenList() did not check the allocation of its Head buffer.
* NewTemp() kept the last handed-out id in a static, so an exhausted temp
list produced a token aliasing a temporary still in use, and it derived
MaxTempNumber from an out-of-range index. It also dereferenced the new
token without a null check.
* FreeTemp() indexed the MAX_TEMP_COUNT-entry map with an unchecked value
parsed out of the token text.
* RotateLeftStringOnce() wrote to str[-1] when handed an empty string.
libhyperdbg/debugger/misc/pci-id.cpp
* The database file was read into a malloc(Length) buffer that was never
null-terminated, while ReadLine() walks it with strchr(). Looking up an
absent vendor scans to the end and reads past the allocation.
* The matched Vendor was allocated with malloc() and its Devices list head
was only assigned once a device line was parsed, so a vendor with no
device entries left it uninitialized and FreeVendor() walked a garbage
pointer.
* FreeVendor() released the device and subdevice lists but never the Vendor
itself, leaking one per lookup for every enumerated PCI device.
* The file handle leaked when the buffer allocation failed, ftell() and
fread() results were unused, and several error paths leaked the Vendor or
the not-yet-linked Device/SubDevice.
* strncmp() compared sizeof(VendorId) bytes, which is the size of the
pointer rather than the length of a vendor id.
* ReadLine() passed an unclamped count to strncpy_s(), which triggers the
invalid parameter handler for a line longer than the destination.
* GetVendorById() ignored the GetModuleFileName() result and overwrote the
tail of the path buffer without checking the room left in it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W3C1DuhHtqK64eEkHjKCHM
2026-08-01 14:22:52 +00:00
|
|
|
//
|
|
|
|
|
// Keep MaxLen describing the buffer that is actually allocated, see the
|
|
|
|
|
// matching comment in AppendByte()
|
|
|
|
|
//
|
2024-03-17 20:33:02 +09:00
|
|
|
printf("err, could not allocate buffer");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-08 23:48:59 +08:00
|
|
|
//
|
|
|
|
|
// Free Old buffer and update the pointer
|
|
|
|
|
//
|
2023-11-24 04:51:56 +08:00
|
|
|
memcpy(NewValue, Token->Value, Token->Len);
|
2023-11-08 23:48:59 +08:00
|
|
|
free(Token->Value);
|
Fix memory-safety and robustness issues in script engine and PCI ID parser
Code audit of the script engine's scanner/token handling and of the PCI ID
database parser. Each of the issues below was reproduced against the current
code before the fix and re-checked afterwards.
script-engine/scanner.c
* An unterminated string literal ("abc or L"abc) hung the scanner in an
endless loop: sgetc() returns EOF without consuming input, and neither
string loop tested for it, so the token grew until allocation failed.
Both loops now stop at EOF and report the token as UNKNOWN.
script-engine/common.c
* AppendByte()/AppendWchar() doubled Token->MaxLen before checking whether
the larger buffer was actually allocated. After a failed allocation MaxLen
described memory that did not exist and the next append wrote past the end
of the old buffer. MaxLen is now committed only on success.
* CopyToken() allocated strlen(Value) + 1 bytes but carried over the source
token's Len and MaxLen, so the copy's advertised capacity did not match its
allocation, and WSTRING payloads were truncated at their first embedded
null byte. The copy is now sized from Len/MaxLen and copied by length, with
a fallback to the string length for the grammar tokens in parse-table.c,
which only initialize Type and Value.
* NewToken() set MaxLen to the value length, which is zero for an empty
value. The 'Len >= MaxLen - 1' test in the append routines is unsigned, so
a zero MaxLen wrapped and disabled buffer growth entirely.
* IsUnderscore() tested 'c >= '_'', which also accepted the backtick, the
lowercase letters, '{', '|', '}', '~' and DEL. Register scanning uses it,
so '@rax|1' was lexed as one malformed register name instead of a register,
an operator and a number. The pseudo-register path already compared against
'_' directly.
* NewTokenList() did not check the allocation of its Head buffer.
* NewTemp() kept the last handed-out id in a static, so an exhausted temp
list produced a token aliasing a temporary still in use, and it derived
MaxTempNumber from an out-of-range index. It also dereferenced the new
token without a null check.
* FreeTemp() indexed the MAX_TEMP_COUNT-entry map with an unchecked value
parsed out of the token text.
* RotateLeftStringOnce() wrote to str[-1] when handed an empty string.
libhyperdbg/debugger/misc/pci-id.cpp
* The database file was read into a malloc(Length) buffer that was never
null-terminated, while ReadLine() walks it with strchr(). Looking up an
absent vendor scans to the end and reads past the allocation.
* The matched Vendor was allocated with malloc() and its Devices list head
was only assigned once a device line was parsed, so a vendor with no
device entries left it uninitialized and FreeVendor() walked a garbage
pointer.
* FreeVendor() released the device and subdevice lists but never the Vendor
itself, leaking one per lookup for every enumerated PCI device.
* The file handle leaked when the buffer allocation failed, ftell() and
fread() results were unused, and several error paths leaked the Vendor or
the not-yet-linked Device/SubDevice.
* strncmp() compared sizeof(VendorId) bytes, which is the size of the
pointer rather than the length of a vendor id.
* ReadLine() passed an unclamped count to strncpy_s(), which triggers the
invalid parameter handler for a line longer than the destination.
* GetVendorById() ignored the GetModuleFileName() result and overwrote the
tail of the path buffer without checking the room left in it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W3C1DuhHtqK64eEkHjKCHM
2026-08-01 14:22:52 +00:00
|
|
|
Token->Value = NewValue;
|
|
|
|
|
Token->MaxLen = NewMaxLen;
|
2023-11-08 23:48:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
2024-03-17 18:49:51 +09:00
|
|
|
// Append the new character to the wstring
|
2023-11-08 23:48:59 +08:00
|
|
|
//
|
2026-08-09 23:24:21 +08:00
|
|
|
memcpy(Token->Value + Token->Len, &c, sizeof(c));
|
2023-11-08 23:48:59 +08:00
|
|
|
Token->Len += 2;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-07 22:51:55 +09:00
|
|
|
/**
|
2022-05-18 16:00:16 +09:00
|
|
|
* @brief Copies a PTOKEN
|
2022-05-07 22:51:55 +09:00
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param Token the token to copy
|
|
|
|
|
* @return PSCRIPT_ENGINE_TOKEN the copied token
|
2022-05-07 22:51:55 +09:00
|
|
|
*/
|
2025-07-07 11:46:10 -07:00
|
|
|
PSCRIPT_ENGINE_TOKEN
|
|
|
|
|
CopyToken(PSCRIPT_ENGINE_TOKEN Token)
|
2022-05-07 22:51:55 +09:00
|
|
|
{
|
2025-07-07 11:46:10 -07:00
|
|
|
PSCRIPT_ENGINE_TOKEN TokenCopy = (PSCRIPT_ENGINE_TOKEN)malloc(sizeof(SCRIPT_ENGINE_TOKEN));
|
2024-03-17 20:33:02 +09:00
|
|
|
|
|
|
|
|
if (TokenCopy == NULL)
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
// There was an error allocating buffer
|
|
|
|
|
//
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
Fix memory-safety and robustness issues in script engine and PCI ID parser
Code audit of the script engine's scanner/token handling and of the PCI ID
database parser. Each of the issues below was reproduced against the current
code before the fix and re-checked afterwards.
script-engine/scanner.c
* An unterminated string literal ("abc or L"abc) hung the scanner in an
endless loop: sgetc() returns EOF without consuming input, and neither
string loop tested for it, so the token grew until allocation failed.
Both loops now stop at EOF and report the token as UNKNOWN.
script-engine/common.c
* AppendByte()/AppendWchar() doubled Token->MaxLen before checking whether
the larger buffer was actually allocated. After a failed allocation MaxLen
described memory that did not exist and the next append wrote past the end
of the old buffer. MaxLen is now committed only on success.
* CopyToken() allocated strlen(Value) + 1 bytes but carried over the source
token's Len and MaxLen, so the copy's advertised capacity did not match its
allocation, and WSTRING payloads were truncated at their first embedded
null byte. The copy is now sized from Len/MaxLen and copied by length, with
a fallback to the string length for the grammar tokens in parse-table.c,
which only initialize Type and Value.
* NewToken() set MaxLen to the value length, which is zero for an empty
value. The 'Len >= MaxLen - 1' test in the append routines is unsigned, so
a zero MaxLen wrapped and disabled buffer growth entirely.
* IsUnderscore() tested 'c >= '_'', which also accepted the backtick, the
lowercase letters, '{', '|', '}', '~' and DEL. Register scanning uses it,
so '@rax|1' was lexed as one malformed register name instead of a register,
an operator and a number. The pseudo-register path already compared against
'_' directly.
* NewTokenList() did not check the allocation of its Head buffer.
* NewTemp() kept the last handed-out id in a static, so an exhausted temp
list produced a token aliasing a temporary still in use, and it derived
MaxTempNumber from an out-of-range index. It also dereferenced the new
token without a null check.
* FreeTemp() indexed the MAX_TEMP_COUNT-entry map with an unchecked value
parsed out of the token text.
* RotateLeftStringOnce() wrote to str[-1] when handed an empty string.
libhyperdbg/debugger/misc/pci-id.cpp
* The database file was read into a malloc(Length) buffer that was never
null-terminated, while ReadLine() walks it with strchr(). Looking up an
absent vendor scans to the end and reads past the allocation.
* The matched Vendor was allocated with malloc() and its Devices list head
was only assigned once a device line was parsed, so a vendor with no
device entries left it uninitialized and FreeVendor() walked a garbage
pointer.
* FreeVendor() released the device and subdevice lists but never the Vendor
itself, leaking one per lookup for every enumerated PCI device.
* The file handle leaked when the buffer allocation failed, ftell() and
fread() results were unused, and several error paths leaked the Vendor or
the not-yet-linked Device/SubDevice.
* strncmp() compared sizeof(VendorId) bytes, which is the size of the
pointer rather than the length of a vendor id.
* ReadLine() passed an unclamped count to strncpy_s(), which triggers the
invalid parameter handler for a line longer than the destination.
* GetVendorById() ignored the GetModuleFileName() result and overwrote the
tail of the path buffer without checking the room left in it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W3C1DuhHtqK64eEkHjKCHM
2026-08-01 14:22:52 +00:00
|
|
|
//
|
|
|
|
|
// The number of bytes to copy is the larger of Len and the string length:
|
|
|
|
|
//
|
|
|
|
|
// - WSTRING tokens hold UTF-16 data whose embedded null bytes make strlen()
|
|
|
|
|
// (and strcpy()) stop early, so Len is the meaningful size for them
|
|
|
|
|
// - tokens taken from the static grammar tables in parse-table.c only have
|
|
|
|
|
// their Type and Value initialized, leaving Len at zero, so the string
|
|
|
|
|
// length is the meaningful size for those
|
|
|
|
|
//
|
|
|
|
|
unsigned int ValueLen = (unsigned int)strlen(Token->Value);
|
|
|
|
|
unsigned int CopyLen = Token->Len > ValueLen ? Token->Len : ValueLen;
|
|
|
|
|
unsigned int MaxLen = Token->MaxLen > CopyLen ? Token->MaxLen : CopyLen;
|
|
|
|
|
|
|
|
|
|
if (MaxLen < TOKEN_VALUE_MAX_LEN)
|
|
|
|
|
{
|
|
|
|
|
MaxLen = TOKEN_VALUE_MAX_LEN;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TokenCopy->Type = Token->Type;
|
|
|
|
|
//
|
|
|
|
|
// MaxLen describes the buffer that is actually allocated below. It used to be
|
|
|
|
|
// copied verbatim from the source token while the allocation was sized from the
|
|
|
|
|
// string length, so the two could disagree and let AppendByte()/AppendWchar()
|
|
|
|
|
// write past the end of the copy
|
|
|
|
|
//
|
|
|
|
|
TokenCopy->MaxLen = MaxLen;
|
|
|
|
|
TokenCopy->Len = Token->Len;
|
|
|
|
|
TokenCopy->Value = (char *)calloc(MaxLen + 2, sizeof(char));
|
|
|
|
|
TokenCopy->VariableType = Token->VariableType;
|
2026-07-18 22:28:45 +08:00
|
|
|
TokenCopy->VariableMemoryIdx = Token->VariableMemoryIdx;
|
|
|
|
|
TokenCopy->AddressSpace = Token->AddressSpace;
|
|
|
|
|
TokenCopy->IsAddress = Token->IsAddress;
|
2026-07-20 23:21:34 +08:00
|
|
|
TokenCopy->IsImplicitType = Token->IsImplicitType;
|
2026-08-09 23:24:21 +08:00
|
|
|
TokenCopy->IsSignedFunctionResult = Token->IsSignedFunctionResult;
|
2024-03-17 20:33:02 +09:00
|
|
|
|
|
|
|
|
if (TokenCopy->Value == NULL)
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
// There was an error allocating buffer
|
|
|
|
|
//
|
2024-04-05 16:13:13 +03:00
|
|
|
free(TokenCopy);
|
2024-03-17 20:33:02 +09:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
Fix memory-safety and robustness issues in script engine and PCI ID parser
Code audit of the script engine's scanner/token handling and of the PCI ID
database parser. Each of the issues below was reproduced against the current
code before the fix and re-checked afterwards.
script-engine/scanner.c
* An unterminated string literal ("abc or L"abc) hung the scanner in an
endless loop: sgetc() returns EOF without consuming input, and neither
string loop tested for it, so the token grew until allocation failed.
Both loops now stop at EOF and report the token as UNKNOWN.
script-engine/common.c
* AppendByte()/AppendWchar() doubled Token->MaxLen before checking whether
the larger buffer was actually allocated. After a failed allocation MaxLen
described memory that did not exist and the next append wrote past the end
of the old buffer. MaxLen is now committed only on success.
* CopyToken() allocated strlen(Value) + 1 bytes but carried over the source
token's Len and MaxLen, so the copy's advertised capacity did not match its
allocation, and WSTRING payloads were truncated at their first embedded
null byte. The copy is now sized from Len/MaxLen and copied by length, with
a fallback to the string length for the grammar tokens in parse-table.c,
which only initialize Type and Value.
* NewToken() set MaxLen to the value length, which is zero for an empty
value. The 'Len >= MaxLen - 1' test in the append routines is unsigned, so
a zero MaxLen wrapped and disabled buffer growth entirely.
* IsUnderscore() tested 'c >= '_'', which also accepted the backtick, the
lowercase letters, '{', '|', '}', '~' and DEL. Register scanning uses it,
so '@rax|1' was lexed as one malformed register name instead of a register,
an operator and a number. The pseudo-register path already compared against
'_' directly.
* NewTokenList() did not check the allocation of its Head buffer.
* NewTemp() kept the last handed-out id in a static, so an exhausted temp
list produced a token aliasing a temporary still in use, and it derived
MaxTempNumber from an out-of-range index. It also dereferenced the new
token without a null check.
* FreeTemp() indexed the MAX_TEMP_COUNT-entry map with an unchecked value
parsed out of the token text.
* RotateLeftStringOnce() wrote to str[-1] when handed an empty string.
libhyperdbg/debugger/misc/pci-id.cpp
* The database file was read into a malloc(Length) buffer that was never
null-terminated, while ReadLine() walks it with strchr(). Looking up an
absent vendor scans to the end and reads past the allocation.
* The matched Vendor was allocated with malloc() and its Devices list head
was only assigned once a device line was parsed, so a vendor with no
device entries left it uninitialized and FreeVendor() walked a garbage
pointer.
* FreeVendor() released the device and subdevice lists but never the Vendor
itself, leaking one per lookup for every enumerated PCI device.
* The file handle leaked when the buffer allocation failed, ftell() and
fread() results were unused, and several error paths leaked the Vendor or
the not-yet-linked Device/SubDevice.
* strncmp() compared sizeof(VendorId) bytes, which is the size of the
pointer rather than the length of a vendor id.
* ReadLine() passed an unclamped count to strncpy_s(), which triggers the
invalid parameter handler for a line longer than the destination.
* GetVendorById() ignored the GetModuleFileName() result and overwrote the
tail of the path buffer without checking the room left in it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W3C1DuhHtqK64eEkHjKCHM
2026-08-01 14:22:52 +00:00
|
|
|
memcpy(TokenCopy->Value, Token->Value, CopyLen);
|
2022-05-18 23:44:03 +04:30
|
|
|
|
2022-05-07 22:51:55 +09:00
|
|
|
return TokenCopy;
|
2020-12-01 22:26:46 +03:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2026-05-31 02:21:47 +02:00
|
|
|
* @brief Allocates a new SCRIPT_ENGINE_TOKEN_LIST
|
2020-12-01 22:26:46 +03:30
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @return PSCRIPT_ENGINE_TOKEN_LIST the allocated token list
|
2020-12-01 22:26:46 +03:30
|
|
|
*/
|
2025-07-07 11:46:10 -07:00
|
|
|
PSCRIPT_ENGINE_TOKEN_LIST
|
2021-03-22 18:19:39 +04:30
|
|
|
NewTokenList(void)
|
2020-12-01 22:26:46 +03:30
|
|
|
{
|
2025-07-07 11:46:10 -07:00
|
|
|
PSCRIPT_ENGINE_TOKEN_LIST TokenList = NULL;
|
2020-12-01 22:26:46 +03:30
|
|
|
|
2021-03-22 18:19:39 +04:30
|
|
|
//
|
2025-07-07 11:46:10 -07:00
|
|
|
// Allocation of memory for SCRIPT_ENGINE_TOKEN_LIST structure
|
2021-03-22 18:19:39 +04:30
|
|
|
//
|
2025-07-07 11:46:10 -07:00
|
|
|
TokenList = (PSCRIPT_ENGINE_TOKEN_LIST)malloc(sizeof(*TokenList));
|
2020-12-01 22:26:46 +03:30
|
|
|
|
2024-03-17 20:33:02 +09:00
|
|
|
if (TokenList == NULL)
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
// There was an error allocating buffer
|
|
|
|
|
//
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-22 18:19:39 +04:30
|
|
|
//
|
2025-07-07 11:46:10 -07:00
|
|
|
// Initialize fields of SCRIPT_ENGINE_TOKEN_LIST
|
2021-03-22 18:19:39 +04:30
|
|
|
//
|
|
|
|
|
TokenList->Pointer = 0;
|
|
|
|
|
TokenList->Size = TOKEN_LIST_INIT_SIZE;
|
2020-12-01 22:26:46 +03:30
|
|
|
|
2021-03-22 18:19:39 +04:30
|
|
|
//
|
2025-07-07 11:46:10 -07:00
|
|
|
// Allocation of memory for SCRIPT_ENGINE_TOKEN_LIST buffer
|
2021-03-22 18:19:39 +04:30
|
|
|
//
|
2025-07-07 11:46:10 -07:00
|
|
|
TokenList->Head = (PSCRIPT_ENGINE_TOKEN *)malloc(TokenList->Size * sizeof(PSCRIPT_ENGINE_TOKEN));
|
2020-12-01 22:26:46 +03:30
|
|
|
|
Fix memory-safety and robustness issues in script engine and PCI ID parser
Code audit of the script engine's scanner/token handling and of the PCI ID
database parser. Each of the issues below was reproduced against the current
code before the fix and re-checked afterwards.
script-engine/scanner.c
* An unterminated string literal ("abc or L"abc) hung the scanner in an
endless loop: sgetc() returns EOF without consuming input, and neither
string loop tested for it, so the token grew until allocation failed.
Both loops now stop at EOF and report the token as UNKNOWN.
script-engine/common.c
* AppendByte()/AppendWchar() doubled Token->MaxLen before checking whether
the larger buffer was actually allocated. After a failed allocation MaxLen
described memory that did not exist and the next append wrote past the end
of the old buffer. MaxLen is now committed only on success.
* CopyToken() allocated strlen(Value) + 1 bytes but carried over the source
token's Len and MaxLen, so the copy's advertised capacity did not match its
allocation, and WSTRING payloads were truncated at their first embedded
null byte. The copy is now sized from Len/MaxLen and copied by length, with
a fallback to the string length for the grammar tokens in parse-table.c,
which only initialize Type and Value.
* NewToken() set MaxLen to the value length, which is zero for an empty
value. The 'Len >= MaxLen - 1' test in the append routines is unsigned, so
a zero MaxLen wrapped and disabled buffer growth entirely.
* IsUnderscore() tested 'c >= '_'', which also accepted the backtick, the
lowercase letters, '{', '|', '}', '~' and DEL. Register scanning uses it,
so '@rax|1' was lexed as one malformed register name instead of a register,
an operator and a number. The pseudo-register path already compared against
'_' directly.
* NewTokenList() did not check the allocation of its Head buffer.
* NewTemp() kept the last handed-out id in a static, so an exhausted temp
list produced a token aliasing a temporary still in use, and it derived
MaxTempNumber from an out-of-range index. It also dereferenced the new
token without a null check.
* FreeTemp() indexed the MAX_TEMP_COUNT-entry map with an unchecked value
parsed out of the token text.
* RotateLeftStringOnce() wrote to str[-1] when handed an empty string.
libhyperdbg/debugger/misc/pci-id.cpp
* The database file was read into a malloc(Length) buffer that was never
null-terminated, while ReadLine() walks it with strchr(). Looking up an
absent vendor scans to the end and reads past the allocation.
* The matched Vendor was allocated with malloc() and its Devices list head
was only assigned once a device line was parsed, so a vendor with no
device entries left it uninitialized and FreeVendor() walked a garbage
pointer.
* FreeVendor() released the device and subdevice lists but never the Vendor
itself, leaking one per lookup for every enumerated PCI device.
* The file handle leaked when the buffer allocation failed, ftell() and
fread() results were unused, and several error paths leaked the Vendor or
the not-yet-linked Device/SubDevice.
* strncmp() compared sizeof(VendorId) bytes, which is the size of the
pointer rather than the length of a vendor id.
* ReadLine() passed an unclamped count to strncpy_s(), which triggers the
invalid parameter handler for a line longer than the destination.
* GetVendorById() ignored the GetModuleFileName() result and overwrote the
tail of the path buffer without checking the room left in it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W3C1DuhHtqK64eEkHjKCHM
2026-08-01 14:22:52 +00:00
|
|
|
if (TokenList->Head == NULL)
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
// There was an error allocating buffer
|
|
|
|
|
//
|
|
|
|
|
free(TokenList);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-22 18:19:39 +04:30
|
|
|
return TokenList;
|
2020-12-01 22:26:46 +03:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2025-07-07 11:46:10 -07:00
|
|
|
* @brief Removes allocated memory of a SCRIPT_ENGINE_TOKEN_LIST
|
2020-12-01 22:26:46 +03:30
|
|
|
*
|
|
|
|
|
* @param TokenList
|
2026-05-31 02:21:47 +02:00
|
|
|
* @return void
|
2020-12-01 22:26:46 +03:30
|
|
|
*/
|
2021-03-22 18:19:39 +04:30
|
|
|
void
|
2025-07-07 11:46:10 -07:00
|
|
|
RemoveTokenList(PSCRIPT_ENGINE_TOKEN_LIST TokenList)
|
2020-12-01 22:26:46 +03:30
|
|
|
{
|
2025-07-07 11:46:10 -07:00
|
|
|
PSCRIPT_ENGINE_TOKEN Token;
|
2021-03-22 18:19:39 +04:30
|
|
|
for (uintptr_t i = 0; i < TokenList->Pointer; i++)
|
|
|
|
|
{
|
|
|
|
|
Token = *(TokenList->Head + i);
|
2022-05-19 20:16:57 +09:00
|
|
|
RemoveToken(&Token);
|
2021-03-22 18:19:39 +04:30
|
|
|
}
|
2022-01-30 01:02:29 +09:00
|
|
|
free(TokenList->Head);
|
|
|
|
|
free(TokenList);
|
2021-12-29 21:10:09 +03:30
|
|
|
|
2021-03-22 18:19:39 +04:30
|
|
|
return;
|
2020-12-01 22:26:46 +03:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2022-05-18 16:00:16 +09:00
|
|
|
* @brief Prints each Token inside a TokenList
|
2020-12-01 22:26:46 +03:30
|
|
|
*
|
|
|
|
|
* @param TokenList
|
2026-05-31 02:21:47 +02:00
|
|
|
* @return void
|
2020-12-01 22:26:46 +03:30
|
|
|
*/
|
2021-03-22 18:19:39 +04:30
|
|
|
void
|
2025-07-07 11:46:10 -07:00
|
|
|
PrintTokenList(PSCRIPT_ENGINE_TOKEN_LIST TokenList)
|
2020-12-01 22:26:46 +03:30
|
|
|
{
|
2025-07-07 11:46:10 -07:00
|
|
|
PSCRIPT_ENGINE_TOKEN Token;
|
2021-03-22 18:19:39 +04:30
|
|
|
for (uintptr_t i = 0; i < TokenList->Pointer; i++)
|
|
|
|
|
{
|
|
|
|
|
Token = *(TokenList->Head + i);
|
|
|
|
|
PrintToken(Token);
|
|
|
|
|
}
|
2020-12-01 22:26:46 +03:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2022-05-18 16:00:16 +09:00
|
|
|
* @brief Adds Token to the last empty position of TokenList
|
2020-12-01 22:26:46 +03:30
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param TokenList the token list to push into
|
|
|
|
|
* @param Token the token to add
|
|
|
|
|
* @return PSCRIPT_ENGINE_TOKEN_LIST
|
2020-12-01 22:26:46 +03:30
|
|
|
*/
|
2025-07-07 11:46:10 -07:00
|
|
|
PSCRIPT_ENGINE_TOKEN_LIST
|
|
|
|
|
Push(PSCRIPT_ENGINE_TOKEN_LIST TokenList, PSCRIPT_ENGINE_TOKEN Token)
|
2021-03-22 18:19:39 +04:30
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
// Calculate address to write new token
|
|
|
|
|
//
|
2025-07-07 11:46:10 -07:00
|
|
|
uintptr_t Head = (uintptr_t)TokenList->Head;
|
|
|
|
|
uintptr_t Pointer = (uintptr_t)TokenList->Pointer;
|
|
|
|
|
PSCRIPT_ENGINE_TOKEN * WriteAddr = (PSCRIPT_ENGINE_TOKEN *)(Head + Pointer * sizeof(PSCRIPT_ENGINE_TOKEN));
|
2021-03-22 18:19:39 +04:30
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Write Token to appropriate address in TokenList
|
|
|
|
|
//
|
|
|
|
|
*WriteAddr = Token;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Update Pointer
|
|
|
|
|
//
|
|
|
|
|
TokenList->Pointer++;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Handle overflow
|
|
|
|
|
//
|
|
|
|
|
if (Pointer == TokenList->Size - 1)
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
// Allocate a new buffer for string list with doubled length
|
|
|
|
|
//
|
2025-07-07 11:46:10 -07:00
|
|
|
PSCRIPT_ENGINE_TOKEN * NewHead = (PSCRIPT_ENGINE_TOKEN *)malloc(2 * TokenList->Size * sizeof(PSCRIPT_ENGINE_TOKEN));
|
2021-03-22 18:19:39 +04:30
|
|
|
|
2024-03-17 20:33:02 +09:00
|
|
|
if (NewHead == NULL)
|
|
|
|
|
{
|
|
|
|
|
printf("err, could not allocate buffer");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-22 18:19:39 +04:30
|
|
|
//
|
|
|
|
|
// Copy old buffer to new buffer
|
|
|
|
|
//
|
2025-07-07 11:46:10 -07:00
|
|
|
memcpy(NewHead, TokenList->Head, TokenList->Size * sizeof(PSCRIPT_ENGINE_TOKEN));
|
2021-03-22 18:19:39 +04:30
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Free old buffer
|
|
|
|
|
//
|
|
|
|
|
free(TokenList->Head);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Update Head and size of TokenList
|
|
|
|
|
//
|
|
|
|
|
TokenList->Size = TokenList->Size * 2;
|
|
|
|
|
TokenList->Head = NewHead;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TokenList;
|
2020-12-01 22:26:46 +03:30
|
|
|
}
|
|
|
|
|
/**
|
2022-05-18 16:00:16 +09:00
|
|
|
* @brief Removes last Token of a TokenList and returns it
|
2020-12-01 22:26:46 +03:30
|
|
|
*
|
|
|
|
|
* @param TokenList
|
2026-05-31 02:21:47 +02:00
|
|
|
* @return PSCRIPT_ENGINE_TOKEN
|
2020-12-01 22:26:46 +03:30
|
|
|
*/
|
2025-07-07 11:46:10 -07:00
|
|
|
PSCRIPT_ENGINE_TOKEN
|
|
|
|
|
Pop(PSCRIPT_ENGINE_TOKEN_LIST TokenList)
|
2020-12-01 22:26:46 +03:30
|
|
|
{
|
2021-03-22 18:19:39 +04:30
|
|
|
//
|
|
|
|
|
// Calculate address to read most recent token
|
|
|
|
|
//
|
|
|
|
|
if (TokenList->Pointer > 0)
|
2024-03-02 01:59:33 +08:00
|
|
|
TokenList->Pointer--; // not consider what if the token's type is string or wstring
|
2025-07-07 11:46:10 -07:00
|
|
|
uintptr_t Head = (uintptr_t)TokenList->Head;
|
|
|
|
|
uintptr_t Pointer = (uintptr_t)TokenList->Pointer;
|
|
|
|
|
PSCRIPT_ENGINE_TOKEN * ReadAddr = (PSCRIPT_ENGINE_TOKEN *)(Head + Pointer * sizeof(PSCRIPT_ENGINE_TOKEN));
|
2020-12-01 22:26:46 +03:30
|
|
|
|
2021-03-22 18:19:39 +04:30
|
|
|
return *ReadAddr;
|
2020-12-01 22:26:46 +03:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2022-05-18 16:00:16 +09:00
|
|
|
* @brief Returns last Token of a TokenList
|
2020-12-01 22:26:46 +03:30
|
|
|
*
|
|
|
|
|
* @param TokenList
|
2026-05-31 02:21:47 +02:00
|
|
|
* @return PSCRIPT_ENGINE_TOKEN
|
2020-12-01 22:26:46 +03:30
|
|
|
*/
|
2025-07-07 11:46:10 -07:00
|
|
|
PSCRIPT_ENGINE_TOKEN
|
|
|
|
|
Top(PSCRIPT_ENGINE_TOKEN_LIST TokenList)
|
2020-12-01 22:26:46 +03:30
|
|
|
{
|
2021-03-22 18:19:39 +04:30
|
|
|
//
|
2021-07-04 15:27:29 +04:30
|
|
|
// Calculate address to read most recent pushed token
|
2021-03-22 18:19:39 +04:30
|
|
|
//
|
2025-07-07 11:46:10 -07:00
|
|
|
uintptr_t Head = (uintptr_t)TokenList->Head;
|
|
|
|
|
uintptr_t Pointer = (uintptr_t)TokenList->Pointer - 1;
|
|
|
|
|
PSCRIPT_ENGINE_TOKEN * ReadAddr = (PSCRIPT_ENGINE_TOKEN *)(Head + Pointer * sizeof(PSCRIPT_ENGINE_TOKEN));
|
2020-12-01 22:26:46 +03:30
|
|
|
|
2021-03-22 18:19:39 +04:30
|
|
|
return *ReadAddr;
|
2020-12-01 22:26:46 +03:30
|
|
|
}
|
|
|
|
|
|
2025-10-15 08:01:17 +08:00
|
|
|
/**
|
2026-05-31 02:21:47 +02:00
|
|
|
* @brief Returns the token at a specific index from the top of the token list
|
2025-10-15 08:01:17 +08:00
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param TokenList the token list to index into
|
|
|
|
|
* @param Index the zero-based index from the top
|
|
|
|
|
* @return PSCRIPT_ENGINE_TOKEN
|
2025-10-15 08:01:17 +08:00
|
|
|
*/
|
|
|
|
|
PSCRIPT_ENGINE_TOKEN
|
|
|
|
|
TopIndexed(PSCRIPT_ENGINE_TOKEN_LIST TokenList, int Index)
|
|
|
|
|
{
|
2025-10-21 16:46:49 +08:00
|
|
|
uintptr_t Head = (uintptr_t)TokenList->Head;
|
|
|
|
|
uintptr_t Pointer = (uintptr_t)TokenList->Pointer - 1 - Index;
|
|
|
|
|
PSCRIPT_ENGINE_TOKEN * ReadAddr = (PSCRIPT_ENGINE_TOKEN *)(Head + Pointer * sizeof(PSCRIPT_ENGINE_TOKEN));
|
2025-10-15 08:01:17 +08:00
|
|
|
|
|
|
|
|
return *ReadAddr;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-01 22:26:46 +03:30
|
|
|
/**
|
2023-01-18 20:23:40 +09:00
|
|
|
* @brief Checks whether input char belongs to hexadecimal digit-set or not
|
|
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param c the character to check
|
2024-06-21 17:09:41 +09:00
|
|
|
* @return char
|
2023-01-18 20:23:40 +09:00
|
|
|
*/
|
2021-03-22 18:19:39 +04:30
|
|
|
char
|
|
|
|
|
IsHex(char c)
|
2020-12-01 22:26:46 +03:30
|
|
|
{
|
2021-03-22 18:19:39 +04:30
|
|
|
if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))
|
|
|
|
|
return 1;
|
|
|
|
|
else
|
|
|
|
|
return 0;
|
2020-12-01 22:26:46 +03:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2023-01-18 20:23:40 +09:00
|
|
|
* @brief Checks whether input char belongs to decimal digit-set or not
|
|
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param c the character to check
|
2024-06-21 17:09:41 +09:00
|
|
|
* @return char
|
2023-01-18 20:23:40 +09:00
|
|
|
*/
|
2021-03-22 18:19:39 +04:30
|
|
|
char
|
|
|
|
|
IsDecimal(char c)
|
2020-12-01 22:26:46 +03:30
|
|
|
{
|
2021-03-22 18:19:39 +04:30
|
|
|
if (c >= '0' && c <= '9')
|
|
|
|
|
return 1;
|
|
|
|
|
else
|
|
|
|
|
return 0;
|
2020-12-01 22:26:46 +03:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2023-01-18 20:23:40 +09:00
|
|
|
* @brief Checks whether input char belongs to alphabet set or not
|
|
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param c the character to check
|
2024-06-21 17:09:41 +09:00
|
|
|
* @return char
|
2023-01-18 20:23:40 +09:00
|
|
|
*/
|
2021-03-22 18:19:39 +04:30
|
|
|
char
|
|
|
|
|
IsLetter(char c)
|
2020-12-01 22:26:46 +03:30
|
|
|
{
|
2021-03-22 18:19:39 +04:30
|
|
|
if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))
|
|
|
|
|
return 1;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2020-12-01 22:26:46 +03:30
|
|
|
}
|
|
|
|
|
|
2024-06-21 17:09:41 +09:00
|
|
|
/**
|
|
|
|
|
* @brief Checks whether input char is underscore (_) or not
|
|
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param c the character to check
|
2024-06-21 17:09:41 +09:00
|
|
|
* @return char
|
|
|
|
|
*/
|
|
|
|
|
char
|
|
|
|
|
IsUnderscore(char c)
|
|
|
|
|
{
|
Fix memory-safety and robustness issues in script engine and PCI ID parser
Code audit of the script engine's scanner/token handling and of the PCI ID
database parser. Each of the issues below was reproduced against the current
code before the fix and re-checked afterwards.
script-engine/scanner.c
* An unterminated string literal ("abc or L"abc) hung the scanner in an
endless loop: sgetc() returns EOF without consuming input, and neither
string loop tested for it, so the token grew until allocation failed.
Both loops now stop at EOF and report the token as UNKNOWN.
script-engine/common.c
* AppendByte()/AppendWchar() doubled Token->MaxLen before checking whether
the larger buffer was actually allocated. After a failed allocation MaxLen
described memory that did not exist and the next append wrote past the end
of the old buffer. MaxLen is now committed only on success.
* CopyToken() allocated strlen(Value) + 1 bytes but carried over the source
token's Len and MaxLen, so the copy's advertised capacity did not match its
allocation, and WSTRING payloads were truncated at their first embedded
null byte. The copy is now sized from Len/MaxLen and copied by length, with
a fallback to the string length for the grammar tokens in parse-table.c,
which only initialize Type and Value.
* NewToken() set MaxLen to the value length, which is zero for an empty
value. The 'Len >= MaxLen - 1' test in the append routines is unsigned, so
a zero MaxLen wrapped and disabled buffer growth entirely.
* IsUnderscore() tested 'c >= '_'', which also accepted the backtick, the
lowercase letters, '{', '|', '}', '~' and DEL. Register scanning uses it,
so '@rax|1' was lexed as one malformed register name instead of a register,
an operator and a number. The pseudo-register path already compared against
'_' directly.
* NewTokenList() did not check the allocation of its Head buffer.
* NewTemp() kept the last handed-out id in a static, so an exhausted temp
list produced a token aliasing a temporary still in use, and it derived
MaxTempNumber from an out-of-range index. It also dereferenced the new
token without a null check.
* FreeTemp() indexed the MAX_TEMP_COUNT-entry map with an unchecked value
parsed out of the token text.
* RotateLeftStringOnce() wrote to str[-1] when handed an empty string.
libhyperdbg/debugger/misc/pci-id.cpp
* The database file was read into a malloc(Length) buffer that was never
null-terminated, while ReadLine() walks it with strchr(). Looking up an
absent vendor scans to the end and reads past the allocation.
* The matched Vendor was allocated with malloc() and its Devices list head
was only assigned once a device line was parsed, so a vendor with no
device entries left it uninitialized and FreeVendor() walked a garbage
pointer.
* FreeVendor() released the device and subdevice lists but never the Vendor
itself, leaking one per lookup for every enumerated PCI device.
* The file handle leaked when the buffer allocation failed, ftell() and
fread() results were unused, and several error paths leaked the Vendor or
the not-yet-linked Device/SubDevice.
* strncmp() compared sizeof(VendorId) bytes, which is the size of the
pointer rather than the length of a vendor id.
* ReadLine() passed an unclamped count to strncpy_s(), which triggers the
invalid parameter handler for a line longer than the destination.
* GetVendorById() ignored the GetModuleFileName() result and overwrote the
tail of the path buffer without checking the room left in it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W3C1DuhHtqK64eEkHjKCHM
2026-08-01 14:22:52 +00:00
|
|
|
if (c == '_')
|
2024-06-21 17:09:41 +09:00
|
|
|
return 1;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-01 22:26:46 +03:30
|
|
|
/**
|
2023-01-18 20:23:40 +09:00
|
|
|
* @brief Checks whether input char belongs to binary digit-set or not
|
|
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param c the character to check
|
|
|
|
|
* @return char
|
2023-01-18 20:23:40 +09:00
|
|
|
*/
|
2021-03-22 18:19:39 +04:30
|
|
|
char
|
|
|
|
|
IsBinary(char c)
|
2020-12-01 22:26:46 +03:30
|
|
|
{
|
2021-03-22 18:19:39 +04:30
|
|
|
if (c == '0' || c == '1')
|
|
|
|
|
return 1;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2020-12-01 22:26:46 +03:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2023-01-18 20:23:40 +09:00
|
|
|
* @brief Checks whether input char belongs to octal digit-set or not
|
|
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param c the character to check
|
2024-06-21 17:09:41 +09:00
|
|
|
* @return char
|
2023-01-18 20:23:40 +09:00
|
|
|
*/
|
2021-03-22 18:19:39 +04:30
|
|
|
char
|
|
|
|
|
IsOctal(char c)
|
|
|
|
|
{
|
|
|
|
|
if (c >= '0' && c <= '7')
|
|
|
|
|
return 1;
|
|
|
|
|
else
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-07 11:46:10 -07:00
|
|
|
PSCRIPT_ENGINE_TOKEN
|
2024-08-21 03:42:03 +08:00
|
|
|
NewTemp(PSCRIPT_ENGINE_ERROR_TYPE Error)
|
2021-03-22 18:19:39 +04:30
|
|
|
{
|
2026-08-02 11:01:19 +02:00
|
|
|
static unsigned int TempID = 0;
|
|
|
|
|
int i;
|
2021-03-22 18:19:39 +04:30
|
|
|
for (i = 0; i < MAX_TEMP_COUNT; i++)
|
|
|
|
|
{
|
2024-08-21 03:42:03 +08:00
|
|
|
if (CurrentUserDefinedFunction->TempMap[i] == 0)
|
2021-03-22 18:19:39 +04:30
|
|
|
{
|
2024-08-21 03:42:03 +08:00
|
|
|
TempID = i;
|
|
|
|
|
CurrentUserDefinedFunction->TempMap[i] = 1;
|
2021-03-22 18:19:39 +04:30
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (i == MAX_TEMP_COUNT)
|
|
|
|
|
{
|
2022-01-28 02:11:15 +09:00
|
|
|
*Error = SCRIPT_ENGINE_ERROR_TEMP_LIST_FULL;
|
2021-03-22 18:19:39 +04:30
|
|
|
}
|
2025-07-07 11:46:10 -07:00
|
|
|
PSCRIPT_ENGINE_TOKEN Temp = NewUnknownToken();
|
2026-08-02 11:01:19 +02:00
|
|
|
char TempValue[8];
|
2021-03-22 18:19:39 +04:30
|
|
|
sprintf(TempValue, "%d", TempID);
|
|
|
|
|
strcpy(Temp->Value, TempValue);
|
2024-07-24 21:25:55 +08:00
|
|
|
Temp->Type = TEMP;
|
|
|
|
|
|
2026-08-02 11:01:19 +02:00
|
|
|
if (CurrentUserDefinedFunction->MaxTempNumber < (i + 1))
|
2024-07-24 21:25:55 +08:00
|
|
|
{
|
2024-08-21 03:42:03 +08:00
|
|
|
CurrentUserDefinedFunction->MaxTempNumber = i + 1;
|
2024-07-24 21:25:55 +08:00
|
|
|
}
|
|
|
|
|
|
2021-03-22 18:19:39 +04:30
|
|
|
return Temp;
|
|
|
|
|
}
|
2022-05-10 15:08:24 +04:30
|
|
|
|
|
|
|
|
/**
|
2022-05-18 16:00:16 +09:00
|
|
|
* @brief Frees the memory allocated by Temp
|
2023-01-18 20:23:40 +09:00
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param Temp the token representing the temporary variable
|
2026-05-31 16:38:21 +02:00
|
|
|
* @return VOID
|
2022-05-10 15:08:24 +04:30
|
|
|
*/
|
2026-05-31 16:38:21 +02:00
|
|
|
VOID
|
2025-07-07 11:46:10 -07:00
|
|
|
FreeTemp(PSCRIPT_ENGINE_TOKEN Temp)
|
2021-03-22 18:19:39 +04:30
|
|
|
{
|
Fix memory-safety and robustness issues in script engine and PCI ID parser
Code audit of the script engine's scanner/token handling and of the PCI ID
database parser. Each of the issues below was reproduced against the current
code before the fix and re-checked afterwards.
script-engine/scanner.c
* An unterminated string literal ("abc or L"abc) hung the scanner in an
endless loop: sgetc() returns EOF without consuming input, and neither
string loop tested for it, so the token grew until allocation failed.
Both loops now stop at EOF and report the token as UNKNOWN.
script-engine/common.c
* AppendByte()/AppendWchar() doubled Token->MaxLen before checking whether
the larger buffer was actually allocated. After a failed allocation MaxLen
described memory that did not exist and the next append wrote past the end
of the old buffer. MaxLen is now committed only on success.
* CopyToken() allocated strlen(Value) + 1 bytes but carried over the source
token's Len and MaxLen, so the copy's advertised capacity did not match its
allocation, and WSTRING payloads were truncated at their first embedded
null byte. The copy is now sized from Len/MaxLen and copied by length, with
a fallback to the string length for the grammar tokens in parse-table.c,
which only initialize Type and Value.
* NewToken() set MaxLen to the value length, which is zero for an empty
value. The 'Len >= MaxLen - 1' test in the append routines is unsigned, so
a zero MaxLen wrapped and disabled buffer growth entirely.
* IsUnderscore() tested 'c >= '_'', which also accepted the backtick, the
lowercase letters, '{', '|', '}', '~' and DEL. Register scanning uses it,
so '@rax|1' was lexed as one malformed register name instead of a register,
an operator and a number. The pseudo-register path already compared against
'_' directly.
* NewTokenList() did not check the allocation of its Head buffer.
* NewTemp() kept the last handed-out id in a static, so an exhausted temp
list produced a token aliasing a temporary still in use, and it derived
MaxTempNumber from an out-of-range index. It also dereferenced the new
token without a null check.
* FreeTemp() indexed the MAX_TEMP_COUNT-entry map with an unchecked value
parsed out of the token text.
* RotateLeftStringOnce() wrote to str[-1] when handed an empty string.
libhyperdbg/debugger/misc/pci-id.cpp
* The database file was read into a malloc(Length) buffer that was never
null-terminated, while ReadLine() walks it with strchr(). Looking up an
absent vendor scans to the end and reads past the allocation.
* The matched Vendor was allocated with malloc() and its Devices list head
was only assigned once a device line was parsed, so a vendor with no
device entries left it uninitialized and FreeVendor() walked a garbage
pointer.
* FreeVendor() released the device and subdevice lists but never the Vendor
itself, leaking one per lookup for every enumerated PCI device.
* The file handle leaked when the buffer allocation failed, ftell() and
fread() results were unused, and several error paths leaked the Vendor or
the not-yet-linked Device/SubDevice.
* strncmp() compared sizeof(VendorId) bytes, which is the size of the
pointer rather than the length of a vendor id.
* ReadLine() passed an unclamped count to strncpy_s(), which triggers the
invalid parameter handler for a line longer than the destination.
* GetVendorById() ignored the GetModuleFileName() result and overwrote the
tail of the path buffer without checking the room left in it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W3C1DuhHtqK64eEkHjKCHM
2026-08-01 14:22:52 +00:00
|
|
|
if (Temp->Type != TEMP && Temp->Type != DEFERENCE_TEMP)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// The index is derived from the token's textual value, so it is range-checked
|
|
|
|
|
// before indexing the MAX_TEMP_COUNT-entry map
|
|
|
|
|
//
|
2026-05-31 02:21:47 +02:00
|
|
|
INT Id = (INT)DecimalToInt(Temp->Value);
|
Fix memory-safety and robustness issues in script engine and PCI ID parser
Code audit of the script engine's scanner/token handling and of the PCI ID
database parser. Each of the issues below was reproduced against the current
code before the fix and re-checked afterwards.
script-engine/scanner.c
* An unterminated string literal ("abc or L"abc) hung the scanner in an
endless loop: sgetc() returns EOF without consuming input, and neither
string loop tested for it, so the token grew until allocation failed.
Both loops now stop at EOF and report the token as UNKNOWN.
script-engine/common.c
* AppendByte()/AppendWchar() doubled Token->MaxLen before checking whether
the larger buffer was actually allocated. After a failed allocation MaxLen
described memory that did not exist and the next append wrote past the end
of the old buffer. MaxLen is now committed only on success.
* CopyToken() allocated strlen(Value) + 1 bytes but carried over the source
token's Len and MaxLen, so the copy's advertised capacity did not match its
allocation, and WSTRING payloads were truncated at their first embedded
null byte. The copy is now sized from Len/MaxLen and copied by length, with
a fallback to the string length for the grammar tokens in parse-table.c,
which only initialize Type and Value.
* NewToken() set MaxLen to the value length, which is zero for an empty
value. The 'Len >= MaxLen - 1' test in the append routines is unsigned, so
a zero MaxLen wrapped and disabled buffer growth entirely.
* IsUnderscore() tested 'c >= '_'', which also accepted the backtick, the
lowercase letters, '{', '|', '}', '~' and DEL. Register scanning uses it,
so '@rax|1' was lexed as one malformed register name instead of a register,
an operator and a number. The pseudo-register path already compared against
'_' directly.
* NewTokenList() did not check the allocation of its Head buffer.
* NewTemp() kept the last handed-out id in a static, so an exhausted temp
list produced a token aliasing a temporary still in use, and it derived
MaxTempNumber from an out-of-range index. It also dereferenced the new
token without a null check.
* FreeTemp() indexed the MAX_TEMP_COUNT-entry map with an unchecked value
parsed out of the token text.
* RotateLeftStringOnce() wrote to str[-1] when handed an empty string.
libhyperdbg/debugger/misc/pci-id.cpp
* The database file was read into a malloc(Length) buffer that was never
null-terminated, while ReadLine() walks it with strchr(). Looking up an
absent vendor scans to the end and reads past the allocation.
* The matched Vendor was allocated with malloc() and its Devices list head
was only assigned once a device line was parsed, so a vendor with no
device entries left it uninitialized and FreeVendor() walked a garbage
pointer.
* FreeVendor() released the device and subdevice lists but never the Vendor
itself, leaking one per lookup for every enumerated PCI device.
* The file handle leaked when the buffer allocation failed, ftell() and
fread() results were unused, and several error paths leaked the Vendor or
the not-yet-linked Device/SubDevice.
* strncmp() compared sizeof(VendorId) bytes, which is the size of the
pointer rather than the length of a vendor id.
* ReadLine() passed an unclamped count to strncpy_s(), which triggers the
invalid parameter handler for a line longer than the destination.
* GetVendorById() ignored the GetModuleFileName() result and overwrote the
tail of the path buffer without checking the room left in it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W3C1DuhHtqK64eEkHjKCHM
2026-08-01 14:22:52 +00:00
|
|
|
|
|
|
|
|
if (Id >= 0 && Id < MAX_TEMP_COUNT)
|
2021-03-22 18:19:39 +04:30
|
|
|
{
|
2026-05-31 02:21:47 +02:00
|
|
|
CurrentUserDefinedFunction->TempMap[Id] = 0;
|
2022-01-28 02:11:15 +09:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-18 16:00:16 +09:00
|
|
|
/**
|
|
|
|
|
* @brief Checks whether this Token type is OneOpFunc1
|
2023-01-18 20:23:40 +09:00
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param Operator the token to check
|
2023-01-18 20:23:40 +09:00
|
|
|
* @return char
|
2022-05-18 16:00:16 +09:00
|
|
|
*/
|
2021-03-22 18:19:39 +04:30
|
|
|
char
|
2025-07-07 11:46:10 -07:00
|
|
|
IsType1Func(PSCRIPT_ENGINE_TOKEN Operator)
|
2021-03-22 18:19:39 +04:30
|
|
|
{
|
|
|
|
|
unsigned int n = ONEOPFUNC1_LENGTH;
|
2024-03-17 20:33:02 +09:00
|
|
|
for (unsigned int i = 0; i < n; i++)
|
2021-03-22 18:19:39 +04:30
|
|
|
{
|
|
|
|
|
if (!strcmp(Operator->Value, OneOpFunc1[i]))
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-10 15:08:24 +04:30
|
|
|
/**
|
2022-05-18 16:00:16 +09:00
|
|
|
* @brief Checks whether this Token type is OneOpFunc2
|
2023-01-18 20:23:40 +09:00
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param Operator the token to check
|
2023-01-18 20:23:40 +09:00
|
|
|
* @return char
|
2022-05-10 15:08:24 +04:30
|
|
|
*/
|
2021-03-22 18:19:39 +04:30
|
|
|
char
|
2025-07-07 11:46:10 -07:00
|
|
|
IsType2Func(PSCRIPT_ENGINE_TOKEN Operator)
|
2021-03-22 18:19:39 +04:30
|
|
|
{
|
|
|
|
|
unsigned int n = ONEOPFUNC2_LENGTH;
|
2024-03-17 20:33:02 +09:00
|
|
|
for (unsigned int i = 0; i < n; i++)
|
2021-03-22 18:19:39 +04:30
|
|
|
{
|
|
|
|
|
if (!strcmp(Operator->Value, OneOpFunc2[i]))
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-10 15:08:24 +04:30
|
|
|
/**
|
2022-05-18 16:00:16 +09:00
|
|
|
* @brief Checks whether this Token type is OperatorsTwoOperandList
|
2023-01-18 20:23:40 +09:00
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param Operator the token to check
|
2023-01-18 20:23:40 +09:00
|
|
|
* @return char
|
2022-05-10 15:08:24 +04:30
|
|
|
*/
|
2021-03-22 18:19:39 +04:30
|
|
|
char
|
2025-07-07 11:46:10 -07:00
|
|
|
IsTwoOperandOperator(PSCRIPT_ENGINE_TOKEN Operator)
|
2021-03-22 18:19:39 +04:30
|
|
|
{
|
2021-04-13 22:53:02 +04:30
|
|
|
unsigned int n = OPERATORS_TWO_OPERAND_LIST_LENGTH;
|
2024-03-17 20:33:02 +09:00
|
|
|
for (unsigned int i = 0; i < n; i++)
|
2021-03-22 18:19:39 +04:30
|
|
|
{
|
2021-04-13 22:53:02 +04:30
|
|
|
if (!strcmp(Operator->Value, OperatorsTwoOperandList[i]))
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-10 15:08:24 +04:30
|
|
|
/**
|
2022-05-18 16:00:16 +09:00
|
|
|
* @brief Checks whether this Token type is OperatorsOneOperandList
|
2023-01-18 20:23:40 +09:00
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param Operator the token to check
|
2023-01-18 20:23:40 +09:00
|
|
|
* @return char
|
2022-05-10 15:08:24 +04:30
|
|
|
*/
|
2021-04-13 22:53:02 +04:30
|
|
|
char
|
2025-07-07 11:46:10 -07:00
|
|
|
IsOneOperandOperator(PSCRIPT_ENGINE_TOKEN Operator)
|
2021-04-13 22:53:02 +04:30
|
|
|
{
|
|
|
|
|
unsigned int n = OPERATORS_ONE_OPERAND_LIST_LENGTH;
|
2024-03-17 20:33:02 +09:00
|
|
|
for (unsigned int i = 0; i < n; i++)
|
2021-04-13 22:53:02 +04:30
|
|
|
{
|
|
|
|
|
if (!strcmp(Operator->Value, OperatorsOneOperandList[i]))
|
2021-03-22 18:19:39 +04:30
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-10 15:08:24 +04:30
|
|
|
/**
|
2022-05-18 16:00:16 +09:00
|
|
|
* @brief Checks whether this Token type is VarArgFunc1
|
2023-01-18 20:23:40 +09:00
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param Operator the token to check
|
2023-01-18 20:23:40 +09:00
|
|
|
* @return char
|
2022-05-10 15:08:24 +04:30
|
|
|
*/
|
2021-03-22 18:19:39 +04:30
|
|
|
char
|
2025-07-07 11:46:10 -07:00
|
|
|
IsType4Func(PSCRIPT_ENGINE_TOKEN Operator)
|
2021-03-22 18:19:39 +04:30
|
|
|
{
|
|
|
|
|
unsigned int n = VARARGFUNC1_LENGTH;
|
2024-03-17 20:33:02 +09:00
|
|
|
for (unsigned int i = 0; i < n; i++)
|
2021-03-22 18:19:39 +04:30
|
|
|
{
|
|
|
|
|
if (!strcmp(Operator->Value, VarArgFunc1[i]))
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-10 15:08:24 +04:30
|
|
|
/**
|
2022-05-18 16:00:16 +09:00
|
|
|
* @brief Checks whether this Token type is ZeroOpFunc1
|
2023-01-18 20:23:40 +09:00
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param Operator the token to check
|
2023-01-18 20:23:40 +09:00
|
|
|
* @return char
|
2022-05-10 15:08:24 +04:30
|
|
|
*/
|
2021-03-22 18:19:39 +04:30
|
|
|
char
|
2025-07-07 11:46:10 -07:00
|
|
|
IsType5Func(PSCRIPT_ENGINE_TOKEN Operator)
|
2021-03-22 18:19:39 +04:30
|
|
|
{
|
|
|
|
|
unsigned int n = ZEROOPFUNC1_LENGTH;
|
2024-03-17 20:33:02 +09:00
|
|
|
for (unsigned int i = 0; i < n; i++)
|
2021-03-22 18:19:39 +04:30
|
|
|
{
|
|
|
|
|
if (!strcmp(Operator->Value, ZeroOpFunc1[i]))
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
2021-02-14 18:43:46 +03:30
|
|
|
}
|
|
|
|
|
|
2022-05-10 15:08:24 +04:30
|
|
|
/**
|
2022-05-18 16:00:16 +09:00
|
|
|
* @brief Checks whether this Token type is TwoOpFunc1
|
2023-01-18 20:23:40 +09:00
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param Operator the token to check
|
2023-01-18 20:23:40 +09:00
|
|
|
* @return char
|
2022-05-10 15:08:24 +04:30
|
|
|
*/
|
2021-05-19 15:17:14 +04:30
|
|
|
char
|
2025-07-07 11:46:10 -07:00
|
|
|
IsType6Func(PSCRIPT_ENGINE_TOKEN Operator)
|
2021-05-19 15:17:14 +04:30
|
|
|
{
|
2021-06-11 15:26:08 +04:30
|
|
|
unsigned int n = TWOOPFUNC1_LENGTH;
|
2024-03-17 20:33:02 +09:00
|
|
|
for (unsigned int i = 0; i < n; i++)
|
2021-05-19 15:17:14 +04:30
|
|
|
{
|
2021-06-11 15:26:08 +04:30
|
|
|
if (!strcmp(Operator->Value, TwoOpFunc1[i]))
|
2021-05-19 15:17:14 +04:30
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-10 15:08:24 +04:30
|
|
|
/**
|
2022-05-18 16:00:16 +09:00
|
|
|
* @brief Checks whether this Token type is TwoOpFunc2
|
2023-01-18 20:23:40 +09:00
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param Operator the token to check
|
2023-01-18 20:23:40 +09:00
|
|
|
* @return char
|
2022-05-10 15:08:24 +04:30
|
|
|
*/
|
2021-09-08 18:28:58 +09:00
|
|
|
char
|
2025-07-07 11:46:10 -07:00
|
|
|
IsType7Func(PSCRIPT_ENGINE_TOKEN Operator)
|
2021-09-08 18:28:58 +09:00
|
|
|
{
|
|
|
|
|
unsigned int n = TWOOPFUNC2_LENGTH;
|
2024-03-17 20:33:02 +09:00
|
|
|
for (unsigned int i = 0; i < n; i++)
|
2021-09-08 18:28:58 +09:00
|
|
|
{
|
|
|
|
|
if (!strcmp(Operator->Value, TwoOpFunc2[i]))
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-10 15:08:24 +04:30
|
|
|
/**
|
2022-05-18 16:00:16 +09:00
|
|
|
* @brief Checks whether this Token type is ThreeOpFunc1
|
2023-01-18 20:23:40 +09:00
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param Operator the token to check
|
2023-01-18 20:23:40 +09:00
|
|
|
* @return char
|
2022-05-10 15:08:24 +04:30
|
|
|
*/
|
2021-09-08 18:28:58 +09:00
|
|
|
char
|
2025-07-07 11:46:10 -07:00
|
|
|
IsType8Func(PSCRIPT_ENGINE_TOKEN Operator)
|
2021-09-08 18:28:58 +09:00
|
|
|
{
|
|
|
|
|
unsigned int n = THREEOPFUNC1_LENGTH;
|
2024-03-17 20:33:02 +09:00
|
|
|
for (unsigned int i = 0; i < n; i++)
|
2021-09-08 18:28:58 +09:00
|
|
|
{
|
|
|
|
|
if (!strcmp(Operator->Value, ThreeOpFunc1[i]))
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-02 23:25:46 +08:00
|
|
|
/**
|
|
|
|
|
* @brief Checks whether this Token type is OneOpFunc3
|
|
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param Operator the token to check
|
2023-11-02 23:25:46 +08:00
|
|
|
* @return char
|
|
|
|
|
*/
|
|
|
|
|
char
|
2025-07-07 11:46:10 -07:00
|
|
|
IsType9Func(PSCRIPT_ENGINE_TOKEN Operator)
|
2023-11-02 23:25:46 +08:00
|
|
|
{
|
|
|
|
|
unsigned int n = ONEOPFUNC3_LENGTH;
|
2024-03-17 20:33:02 +09:00
|
|
|
for (unsigned int i = 0; i < n; i++)
|
2023-11-02 23:25:46 +08:00
|
|
|
{
|
|
|
|
|
if (!strcmp(Operator->Value, OneOpFunc3[i]))
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Checks whether this Token type is TwoOpFunc3
|
|
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param Operator the token to check
|
2023-11-02 23:25:46 +08:00
|
|
|
* @return char
|
|
|
|
|
*/
|
|
|
|
|
char
|
2025-07-07 11:46:10 -07:00
|
|
|
IsType10Func(PSCRIPT_ENGINE_TOKEN Operator)
|
2023-11-02 23:25:46 +08:00
|
|
|
{
|
|
|
|
|
unsigned int n = TWOOPFUNC3_LENGTH;
|
2024-03-17 20:33:02 +09:00
|
|
|
for (unsigned int i = 0; i < n; i++)
|
2023-11-02 23:25:46 +08:00
|
|
|
{
|
|
|
|
|
if (!strcmp(Operator->Value, TwoOpFunc3[i]))
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Checks whether this Token type is ThreeOpFunc3
|
|
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param Operator the token to check
|
2023-11-02 23:25:46 +08:00
|
|
|
* @return char
|
|
|
|
|
*/
|
|
|
|
|
char
|
2025-07-07 11:46:10 -07:00
|
|
|
IsType11Func(PSCRIPT_ENGINE_TOKEN Operator)
|
2023-11-02 23:25:46 +08:00
|
|
|
{
|
|
|
|
|
unsigned int n = THREEOPFUNC3_LENGTH;
|
2024-03-17 20:33:02 +09:00
|
|
|
for (unsigned int i = 0; i < n; i++)
|
2023-11-02 23:25:46 +08:00
|
|
|
{
|
|
|
|
|
if (!strcmp(Operator->Value, ThreeOpFunc3[i]))
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-08 23:48:59 +08:00
|
|
|
/**
|
|
|
|
|
* @brief Checks whether this Token type is OneOpFunc4
|
|
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param Operator the token to check
|
2023-11-08 23:48:59 +08:00
|
|
|
* @return char
|
|
|
|
|
*/
|
|
|
|
|
char
|
2025-07-07 11:46:10 -07:00
|
|
|
IsType12Func(PSCRIPT_ENGINE_TOKEN Operator)
|
2023-11-08 23:48:59 +08:00
|
|
|
{
|
|
|
|
|
unsigned int n = ONEOPFUNC4_LENGTH;
|
2024-03-17 20:33:02 +09:00
|
|
|
for (unsigned int i = 0; i < n; i++)
|
2023-11-08 23:48:59 +08:00
|
|
|
{
|
|
|
|
|
if (!strcmp(Operator->Value, OneOpFunc4[i]))
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Checks whether this Token type is TwoOpFunc4
|
|
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param Operator the token to check
|
2023-11-08 23:48:59 +08:00
|
|
|
* @return char
|
|
|
|
|
*/
|
|
|
|
|
char
|
2025-07-07 11:46:10 -07:00
|
|
|
IsType13Func(PSCRIPT_ENGINE_TOKEN Operator)
|
2023-11-08 23:48:59 +08:00
|
|
|
{
|
|
|
|
|
unsigned int n = TWOOPFUNC4_LENGTH;
|
2024-03-17 20:33:02 +09:00
|
|
|
for (unsigned int i = 0; i < n; i++)
|
2023-11-08 23:48:59 +08:00
|
|
|
{
|
|
|
|
|
if (!strcmp(Operator->Value, TwoOpFunc4[i]))
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-10 00:22:31 +08:00
|
|
|
/**
|
|
|
|
|
* @brief Checks whether this Token type is ThreeOpFunc2
|
|
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param Operator the token to check
|
2023-11-10 00:22:31 +08:00
|
|
|
* @return char
|
|
|
|
|
*/
|
|
|
|
|
char
|
2025-07-07 11:46:10 -07:00
|
|
|
IsType14Func(PSCRIPT_ENGINE_TOKEN Operator)
|
2023-11-10 00:22:31 +08:00
|
|
|
{
|
|
|
|
|
unsigned int n = THREEOPFUNC2_LENGTH;
|
2024-03-17 20:33:02 +09:00
|
|
|
for (unsigned int i = 0; i < n; i++)
|
2023-11-10 00:22:31 +08:00
|
|
|
{
|
|
|
|
|
if (!strcmp(Operator->Value, ThreeOpFunc2[i]))
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-13 14:42:43 +09:00
|
|
|
/**
|
|
|
|
|
* @brief Checks whether this Token type is ThreeOpFunc4
|
|
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param Operator the token to check
|
2024-06-13 14:42:43 +09:00
|
|
|
* @return char
|
|
|
|
|
*/
|
|
|
|
|
char
|
2025-07-07 11:46:10 -07:00
|
|
|
IsType15Func(PSCRIPT_ENGINE_TOKEN Operator)
|
2024-06-13 14:42:43 +09:00
|
|
|
{
|
|
|
|
|
unsigned int n = THREEOPFUNC4_LENGTH;
|
|
|
|
|
for (unsigned int i = 0; i < n; i++)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp(Operator->Value, ThreeOpFunc4[i]))
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-03 10:00:08 +02:00
|
|
|
/**
|
|
|
|
|
* @brief Checks whether this Token type is ZeroOpFunc2
|
|
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param Operator the token to check
|
2025-06-03 10:00:08 +02:00
|
|
|
* @return char
|
|
|
|
|
*/
|
|
|
|
|
char
|
2025-07-07 11:46:10 -07:00
|
|
|
IsType16Func(PSCRIPT_ENGINE_TOKEN Operator)
|
2025-06-03 10:00:08 +02:00
|
|
|
{
|
|
|
|
|
unsigned int n = ZEROOPFUNC2_LENGTH;
|
|
|
|
|
for (unsigned int i = 0; i < n; i++)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp(Operator->Value, ZeroOpFunc2[i]))
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-22 00:30:23 +08:00
|
|
|
/**
|
2026-04-23 12:38:48 +00:00
|
|
|
* @brief Checks whether this Token type is assignment operator
|
2024-08-22 00:30:23 +08:00
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param Operator the token to check
|
2024-08-22 00:30:23 +08:00
|
|
|
* @return char
|
|
|
|
|
*/
|
|
|
|
|
char
|
2025-07-07 11:46:10 -07:00
|
|
|
IsAssignmentOperator(PSCRIPT_ENGINE_TOKEN Operator)
|
2024-08-22 00:30:23 +08:00
|
|
|
{
|
|
|
|
|
unsigned int n = ASSIGNMENT_OPERATOR_LIST_LENGTH;
|
|
|
|
|
for (unsigned int i = 0; i < n; i++)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp(Operator->Value, AssignmentOperatorList[i]))
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-02 02:32:49 +03:30
|
|
|
/**
|
2022-05-18 16:00:16 +09:00
|
|
|
* @brief Checks whether this Token is noneterminal
|
|
|
|
|
* NoneTerminal token starts with capital letter
|
2023-01-18 20:23:40 +09:00
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param Token the token to check
|
2023-01-18 20:23:40 +09:00
|
|
|
* @return char
|
2022-05-10 15:08:24 +04:30
|
|
|
*/
|
2021-03-22 18:19:39 +04:30
|
|
|
char
|
2025-07-07 11:46:10 -07:00
|
|
|
IsNoneTerminal(PSCRIPT_ENGINE_TOKEN Token)
|
2020-12-02 02:32:49 +03:30
|
|
|
{
|
2021-03-22 18:19:39 +04:30
|
|
|
if (Token->Value[0] >= 'A' && Token->Value[0] <= 'Z')
|
|
|
|
|
return 1;
|
|
|
|
|
else
|
|
|
|
|
return 0;
|
2020-12-02 02:32:49 +03:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2022-05-18 16:00:16 +09:00
|
|
|
* @brief Checks whether this Token is semantic rule
|
|
|
|
|
* SemanticRule token starts with '@'
|
2023-01-18 20:23:40 +09:00
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param Token the token to check
|
2023-01-18 20:23:40 +09:00
|
|
|
* @return char
|
2022-05-10 15:08:24 +04:30
|
|
|
*/
|
2021-03-22 18:19:39 +04:30
|
|
|
char
|
2025-07-07 11:46:10 -07:00
|
|
|
IsSemanticRule(PSCRIPT_ENGINE_TOKEN Token)
|
2020-12-02 02:32:49 +03:30
|
|
|
{
|
2021-03-22 18:19:39 +04:30
|
|
|
if (Token->Value[0] == '@')
|
|
|
|
|
return 1;
|
|
|
|
|
else
|
|
|
|
|
return 0;
|
2020-12-02 02:32:49 +03:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2022-05-18 16:00:16 +09:00
|
|
|
* @brief Gets the Non Terminal Id object
|
2023-01-18 20:23:40 +09:00
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param Token the token to get the non-terminal ID of
|
|
|
|
|
* @return int the non-terminal ID or INVALID
|
2022-05-10 15:08:24 +04:30
|
|
|
*/
|
2021-03-22 18:19:39 +04:30
|
|
|
int
|
2025-07-07 11:46:10 -07:00
|
|
|
GetNonTerminalId(PSCRIPT_ENGINE_TOKEN Token)
|
2020-12-02 02:32:49 +03:30
|
|
|
{
|
2021-03-22 18:19:39 +04:30
|
|
|
for (int i = 0; i < NONETERMINAL_COUNT; i++)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp(Token->Value, NoneTerminalMap[i]))
|
|
|
|
|
return i;
|
|
|
|
|
}
|
2021-06-27 19:48:25 +04:30
|
|
|
return INVALID;
|
2020-12-02 02:32:49 +03:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2022-05-18 16:00:16 +09:00
|
|
|
* @brief Gets the Terminal Id object
|
2023-01-18 20:23:40 +09:00
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param Token the token to get the terminal ID of
|
|
|
|
|
* @return int the terminal ID or INVALID
|
2022-05-10 15:08:24 +04:30
|
|
|
*/
|
2021-03-22 18:19:39 +04:30
|
|
|
int
|
2025-07-07 11:46:10 -07:00
|
|
|
GetTerminalId(PSCRIPT_ENGINE_TOKEN Token)
|
2021-03-22 18:19:39 +04:30
|
|
|
{
|
|
|
|
|
for (int i = 0; i < TERMINAL_COUNT; i++)
|
|
|
|
|
{
|
|
|
|
|
if (Token->Type == HEX)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp("_hex", TerminalMap[i]))
|
|
|
|
|
return i;
|
|
|
|
|
}
|
2026-07-20 15:03:45 +08:00
|
|
|
else if (Token->Type == FLOAT_LITERAL)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp("_float", TerminalMap[i]))
|
|
|
|
|
return i;
|
|
|
|
|
}
|
2021-09-26 21:42:36 +09:00
|
|
|
else if (Token->Type == GLOBAL_ID || Token->Type == GLOBAL_UNRESOLVED_ID)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp("_global_id", TerminalMap[i]))
|
|
|
|
|
{
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (Token->Type == LOCAL_ID || Token->Type == LOCAL_UNRESOLVED_ID)
|
2021-03-22 18:19:39 +04:30
|
|
|
{
|
2021-09-26 21:42:36 +09:00
|
|
|
if (!strcmp("_local_id", TerminalMap[i]))
|
2021-03-22 18:19:39 +04:30
|
|
|
{
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-08-21 03:42:03 +08:00
|
|
|
else if (Token->Type == FUNCTION_ID)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp("_function_id", TerminalMap[i]))
|
|
|
|
|
{
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-03-02 01:59:33 +08:00
|
|
|
else if (Token->Type == FUNCTION_PARAMETER_ID)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp("_function_parameter_id", TerminalMap[i]))
|
|
|
|
|
{
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-03-22 18:19:39 +04:30
|
|
|
else if (Token->Type == REGISTER)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp("_register", TerminalMap[i]))
|
|
|
|
|
{
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (Token->Type == PSEUDO_REGISTER)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp("_pseudo_register", TerminalMap[i]))
|
|
|
|
|
{
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-07-25 01:52:58 +08:00
|
|
|
else if (Token->Type == SCRIPT_VARIABLE_TYPE)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp("_script_variable_type", TerminalMap[i]))
|
|
|
|
|
{
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-03-22 18:19:39 +04:30
|
|
|
else if (Token->Type == DECIMAL)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp("_decimal", TerminalMap[i]))
|
|
|
|
|
{
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (Token->Type == BINARY)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp("_binary", TerminalMap[i]))
|
|
|
|
|
{
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (Token->Type == OCTAL)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp("_octal", TerminalMap[i]))
|
|
|
|
|
{
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (Token->Type == STRING)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp("_string", TerminalMap[i]))
|
|
|
|
|
{
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-11-08 23:48:59 +08:00
|
|
|
else if (Token->Type == WSTRING)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp("_wstring", TerminalMap[i]))
|
|
|
|
|
{
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-03-22 18:19:39 +04:30
|
|
|
else // Keyword
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp(Token->Value, TerminalMap[i]))
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-06-27 19:48:25 +04:30
|
|
|
return INVALID;
|
2020-12-02 02:32:49 +03:30
|
|
|
}
|
|
|
|
|
|
2021-04-10 19:02:23 +04:30
|
|
|
/**
|
2022-05-18 16:00:16 +09:00
|
|
|
* @brief Gets the Non Terminal Id object
|
2023-01-18 20:23:40 +09:00
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param Token the token to get the non-terminal ID of
|
|
|
|
|
* @return int the non-terminal ID or INVALID
|
2022-05-10 15:08:24 +04:30
|
|
|
*/
|
2021-04-11 18:27:23 +04:30
|
|
|
int
|
2025-07-07 11:46:10 -07:00
|
|
|
LalrGetNonTerminalId(PSCRIPT_ENGINE_TOKEN Token)
|
2021-04-10 19:02:23 +04:30
|
|
|
{
|
2021-04-11 18:27:23 +04:30
|
|
|
for (int i = 0; i < LALR_NONTERMINAL_COUNT; i++)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp(Token->Value, LalrNoneTerminalMap[i]))
|
|
|
|
|
return i;
|
|
|
|
|
}
|
2021-06-27 19:48:25 +04:30
|
|
|
return INVALID;
|
2021-04-10 19:02:23 +04:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2022-05-18 16:00:16 +09:00
|
|
|
* @brief Gets the Terminal Id object
|
2023-01-18 20:23:40 +09:00
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param Token the token to get the terminal ID of
|
|
|
|
|
* @return int the terminal ID or INVALID
|
2022-05-10 15:08:24 +04:30
|
|
|
*/
|
2021-04-11 18:27:23 +04:30
|
|
|
int
|
2025-07-07 11:46:10 -07:00
|
|
|
LalrGetTerminalId(PSCRIPT_ENGINE_TOKEN Token)
|
2021-04-11 18:27:23 +04:30
|
|
|
{
|
|
|
|
|
for (int i = 0; i < LALR_TERMINAL_COUNT; i++)
|
|
|
|
|
{
|
|
|
|
|
if (Token->Type == HEX)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp("_hex", LalrTerminalMap[i]))
|
|
|
|
|
return i;
|
|
|
|
|
}
|
2026-07-20 15:03:45 +08:00
|
|
|
else if (Token->Type == FLOAT_LITERAL)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp("_float", LalrTerminalMap[i]))
|
|
|
|
|
return i;
|
2021-04-11 18:27:23 +04:30
|
|
|
}
|
2021-09-26 21:42:36 +09:00
|
|
|
else if (Token->Type == GLOBAL_ID || Token->Type == GLOBAL_UNRESOLVED_ID)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp("_global_id", LalrTerminalMap[i]))
|
|
|
|
|
{
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (Token->Type == LOCAL_ID || Token->Type == LOCAL_UNRESOLVED_ID)
|
2021-04-11 18:27:23 +04:30
|
|
|
{
|
2021-09-26 21:42:36 +09:00
|
|
|
if (!strcmp("_local_id", LalrTerminalMap[i]))
|
2021-04-11 18:27:23 +04:30
|
|
|
{
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-08-21 03:42:03 +08:00
|
|
|
else if (Token->Type == FUNCTION_ID)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp("_function_id", LalrTerminalMap[i]))
|
|
|
|
|
{
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-03-02 01:59:33 +08:00
|
|
|
else if (Token->Type == FUNCTION_PARAMETER_ID)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp("_function_parameter_id", LalrTerminalMap[i]))
|
|
|
|
|
{
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-07-20 23:21:34 +08:00
|
|
|
else if (Token->Type == SCRIPT_VARIABLE_TYPE)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp("_script_variable_type", LalrTerminalMap[i]))
|
|
|
|
|
{
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-04-11 18:27:23 +04:30
|
|
|
else if (Token->Type == REGISTER)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp("_register", LalrTerminalMap[i]))
|
|
|
|
|
{
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (Token->Type == PSEUDO_REGISTER)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp("_pseudo_register", LalrTerminalMap[i]))
|
|
|
|
|
{
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (Token->Type == DECIMAL)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp("_decimal", LalrTerminalMap[i]))
|
|
|
|
|
{
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (Token->Type == BINARY)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp("_binary", LalrTerminalMap[i]))
|
|
|
|
|
{
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (Token->Type == OCTAL)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp("_octal", LalrTerminalMap[i]))
|
|
|
|
|
{
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (Token->Type == STRING)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp("_string", LalrTerminalMap[i]))
|
|
|
|
|
{
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-11-08 23:48:59 +08:00
|
|
|
else if (Token->Type == WSTRING)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp("_wstring", LalrTerminalMap[i]))
|
|
|
|
|
{
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-04-11 18:27:23 +04:30
|
|
|
else // Keyword
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp(Token->Value, LalrTerminalMap[i]))
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-06-27 19:48:25 +04:30
|
|
|
return INVALID;
|
2021-04-10 19:02:23 +04:30
|
|
|
}
|
|
|
|
|
|
2020-12-02 02:32:49 +03:30
|
|
|
/**
|
2024-03-17 18:49:51 +09:00
|
|
|
* @brief Checks whether the value and type of Token1 and Token2 are the same
|
2023-01-18 20:23:40 +09:00
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param Token1 the first token to compare
|
|
|
|
|
* @param Token2 the second token to compare
|
2023-01-18 20:23:40 +09:00
|
|
|
* @return char
|
2022-05-10 15:08:24 +04:30
|
|
|
*/
|
2021-04-11 18:27:23 +04:30
|
|
|
char
|
2025-07-07 11:46:10 -07:00
|
|
|
IsEqual(const PSCRIPT_ENGINE_TOKEN Token1, const PSCRIPT_ENGINE_TOKEN Token2)
|
2021-04-11 18:27:23 +04:30
|
|
|
{
|
|
|
|
|
if (Token1->Type == Token2->Type)
|
|
|
|
|
{
|
|
|
|
|
if (Token1->Type == SPECIAL_TOKEN)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp(Token1->Value, Token2->Value))
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-09-26 21:42:36 +09:00
|
|
|
if (Token1->Type == GLOBAL_ID && Token2->Type == GLOBAL_UNRESOLVED_ID)
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
if (Token1->Type == GLOBAL_UNRESOLVED_ID && Token2->Type == GLOBAL_ID)
|
2021-06-27 19:48:25 +04:30
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2021-09-26 21:42:36 +09:00
|
|
|
|
|
|
|
|
if (Token1->Type == LOCAL_ID && Token2->Type == LOCAL_UNRESOLVED_ID)
|
2021-06-27 19:48:25 +04:30
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2021-09-26 21:42:36 +09:00
|
|
|
if (Token1->Type == LOCAL_UNRESOLVED_ID && Token2->Type == LOCAL_ID)
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-11 18:27:23 +04:30
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-10 15:08:24 +04:30
|
|
|
/**
|
|
|
|
|
* @brief Set the Type object
|
2023-01-18 20:23:40 +09:00
|
|
|
*
|
|
|
|
|
* @param Val
|
|
|
|
|
* @param Type
|
2026-05-31 02:21:47 +02:00
|
|
|
* @return void
|
2022-05-10 15:08:24 +04:30
|
|
|
*/
|
2021-04-11 18:27:23 +04:30
|
|
|
void
|
|
|
|
|
SetType(unsigned long long * Val, unsigned char Type)
|
|
|
|
|
{
|
|
|
|
|
*Val = (unsigned long long int)Type;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-10 15:08:24 +04:30
|
|
|
/**
|
2023-01-18 20:23:40 +09:00
|
|
|
* @brief Converts an decimal string to a integer
|
|
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param str the decimal string to convert
|
2023-01-18 20:23:40 +09:00
|
|
|
* @return unsigned long long int
|
2022-05-10 15:08:24 +04:30
|
|
|
*/
|
2024-03-18 12:31:11 +09:00
|
|
|
unsigned long long
|
2021-04-11 18:27:23 +04:30
|
|
|
DecimalToInt(char * str)
|
|
|
|
|
{
|
2024-03-18 12:31:11 +09:00
|
|
|
unsigned long long Acc = 0;
|
2026-05-31 02:21:47 +02:00
|
|
|
SIZE_T Len;
|
2021-12-29 21:10:09 +03:30
|
|
|
|
|
|
|
|
Len = strlen(str);
|
|
|
|
|
for (int i = 0; i < Len; i++)
|
2021-04-11 18:27:23 +04:30
|
|
|
{
|
2021-12-29 21:10:09 +03:30
|
|
|
Acc *= 10;
|
|
|
|
|
Acc += (str[i] - '0');
|
2021-04-11 18:27:23 +04:30
|
|
|
}
|
2021-12-29 21:10:09 +03:30
|
|
|
return Acc;
|
2021-04-11 18:27:23 +04:30
|
|
|
}
|
|
|
|
|
|
2022-05-10 15:08:24 +04:30
|
|
|
/**
|
2023-01-18 20:23:40 +09:00
|
|
|
* @brief Converts an decimal string to a signed integer
|
|
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param str the decimal string to convert
|
2024-03-18 12:31:11 +09:00
|
|
|
* @return unsigned long long
|
2022-05-10 15:08:24 +04:30
|
|
|
*/
|
2024-03-18 12:31:11 +09:00
|
|
|
unsigned long long
|
2021-04-11 18:27:23 +04:30
|
|
|
DecimalToSignedInt(char * str)
|
|
|
|
|
{
|
2024-03-18 12:31:11 +09:00
|
|
|
long long Acc = 0;
|
2026-05-31 02:21:47 +02:00
|
|
|
SIZE_T Len;
|
2021-12-29 21:10:09 +03:30
|
|
|
|
2021-04-11 18:27:23 +04:30
|
|
|
if (str[0] == '-')
|
|
|
|
|
{
|
2021-12-29 21:10:09 +03:30
|
|
|
Len = strlen(str);
|
|
|
|
|
for (int i = 1; i < Len; i++)
|
2021-04-11 18:27:23 +04:30
|
|
|
{
|
2021-12-29 21:10:09 +03:30
|
|
|
Acc *= 10;
|
|
|
|
|
Acc += (str[i] - '0');
|
2021-04-11 18:27:23 +04:30
|
|
|
}
|
2021-12-29 21:10:09 +03:30
|
|
|
return -Acc;
|
2021-04-11 18:27:23 +04:30
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2021-12-29 21:10:09 +03:30
|
|
|
Len = strlen(str);
|
|
|
|
|
for (int i = 0; i < Len; i++)
|
2021-04-11 18:27:23 +04:30
|
|
|
{
|
2021-12-29 21:10:09 +03:30
|
|
|
Acc *= 10;
|
|
|
|
|
Acc += (str[i] - '0');
|
2021-04-11 18:27:23 +04:30
|
|
|
}
|
2021-12-29 21:10:09 +03:30
|
|
|
return Acc;
|
2021-04-11 18:27:23 +04:30
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-10 15:08:24 +04:30
|
|
|
/**
|
2023-01-18 20:23:40 +09:00
|
|
|
* @brief Converts an hexadecimal string to integer
|
|
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param str the hexadecimal string to convert
|
2024-03-18 12:31:11 +09:00
|
|
|
* @return unsigned long long
|
2022-05-10 15:08:24 +04:30
|
|
|
*/
|
2024-03-18 12:31:11 +09:00
|
|
|
unsigned long long
|
2021-04-11 18:27:23 +04:30
|
|
|
HexToInt(char * str)
|
|
|
|
|
{
|
2026-05-31 02:21:47 +02:00
|
|
|
CHAR Temp;
|
|
|
|
|
SIZE_T Len = strlen(str);
|
2024-03-18 12:31:11 +09:00
|
|
|
unsigned long long Acc = 0;
|
2026-05-31 02:21:47 +02:00
|
|
|
for (int i = 0; i < Len; i++)
|
2021-04-11 18:27:23 +04:30
|
|
|
{
|
2021-12-29 21:10:09 +03:30
|
|
|
Acc <<= 4;
|
2021-04-11 18:27:23 +04:30
|
|
|
if (str[i] >= '0' && str[i] <= '9')
|
|
|
|
|
{
|
2026-05-31 02:21:47 +02:00
|
|
|
Temp = str[i] - '0';
|
2021-04-11 18:27:23 +04:30
|
|
|
}
|
|
|
|
|
else if (str[i] >= 'a' && str[i] <= 'f')
|
|
|
|
|
{
|
2026-05-31 02:21:47 +02:00
|
|
|
Temp = str[i] - 'a' + 10;
|
2021-04-11 18:27:23 +04:30
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2026-05-31 02:21:47 +02:00
|
|
|
Temp = str[i] - 'A' + 10;
|
2021-04-11 18:27:23 +04:30
|
|
|
}
|
2026-05-31 02:21:47 +02:00
|
|
|
Acc += Temp;
|
2021-04-11 18:27:23 +04:30
|
|
|
}
|
|
|
|
|
|
2021-12-29 21:10:09 +03:30
|
|
|
return Acc;
|
2021-04-11 18:27:23 +04:30
|
|
|
}
|
2022-05-10 15:08:24 +04:30
|
|
|
|
|
|
|
|
/**
|
2023-01-18 20:23:40 +09:00
|
|
|
* @brief Converts an octal string to integer
|
|
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param str the octal string to convert
|
2024-03-18 12:31:11 +09:00
|
|
|
* @return unsigned long long
|
2022-05-10 15:08:24 +04:30
|
|
|
*/
|
2024-03-18 12:31:11 +09:00
|
|
|
unsigned long long
|
2021-04-11 18:27:23 +04:30
|
|
|
OctalToInt(char * str)
|
|
|
|
|
{
|
2026-05-31 02:21:47 +02:00
|
|
|
SIZE_T Len;
|
2024-03-18 12:31:11 +09:00
|
|
|
unsigned long long Acc = 0;
|
2021-12-29 21:10:09 +03:30
|
|
|
|
|
|
|
|
Len = strlen(str);
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < Len; i++)
|
2021-04-11 18:27:23 +04:30
|
|
|
{
|
2021-12-29 21:10:09 +03:30
|
|
|
Acc <<= 3;
|
|
|
|
|
Acc += (str[i] - '0');
|
2021-04-11 18:27:23 +04:30
|
|
|
}
|
2021-12-29 21:10:09 +03:30
|
|
|
return Acc;
|
2020-12-02 02:32:49 +03:30
|
|
|
}
|
2022-05-10 15:08:24 +04:30
|
|
|
|
|
|
|
|
/**
|
2023-01-18 20:23:40 +09:00
|
|
|
* @brief Converts a binary string to integer
|
|
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param str the binary string to convert
|
2024-03-18 12:31:11 +09:00
|
|
|
* @return unsigned long long
|
2022-05-10 15:08:24 +04:30
|
|
|
*/
|
2024-03-18 12:31:11 +09:00
|
|
|
unsigned long long
|
2021-03-22 18:19:39 +04:30
|
|
|
BinaryToInt(char * str)
|
|
|
|
|
{
|
2026-05-31 02:21:47 +02:00
|
|
|
SIZE_T Len;
|
2024-03-18 12:31:11 +09:00
|
|
|
unsigned long long Acc = 0;
|
2021-12-29 21:10:09 +03:30
|
|
|
|
|
|
|
|
Len = strlen(str);
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < Len; i++)
|
2021-03-22 18:19:39 +04:30
|
|
|
{
|
2021-12-29 21:10:09 +03:30
|
|
|
Acc <<= 1;
|
|
|
|
|
Acc += (str[i] - '0');
|
2021-03-22 18:19:39 +04:30
|
|
|
}
|
2021-12-29 21:10:09 +03:30
|
|
|
return Acc;
|
2021-04-11 18:27:23 +04:30
|
|
|
}
|
2023-11-24 04:51:56 +08:00
|
|
|
|
|
|
|
|
/**
|
2024-03-02 01:59:33 +08:00
|
|
|
* @brief Rotate a character array to the left by one time
|
|
|
|
|
*
|
2026-05-31 02:21:47 +02:00
|
|
|
* @param str the string to rotate
|
|
|
|
|
* @return void
|
2024-03-02 01:59:33 +08:00
|
|
|
*/
|
2023-11-24 04:51:56 +08:00
|
|
|
void
|
|
|
|
|
RotateLeftStringOnce(char * str)
|
|
|
|
|
{
|
2026-05-31 02:21:47 +02:00
|
|
|
INT Length = (INT)strlen(str);
|
|
|
|
|
CHAR Temp = str[0];
|
Fix memory-safety and robustness issues in script engine and PCI ID parser
Code audit of the script engine's scanner/token handling and of the PCI ID
database parser. Each of the issues below was reproduced against the current
code before the fix and re-checked afterwards.
script-engine/scanner.c
* An unterminated string literal ("abc or L"abc) hung the scanner in an
endless loop: sgetc() returns EOF without consuming input, and neither
string loop tested for it, so the token grew until allocation failed.
Both loops now stop at EOF and report the token as UNKNOWN.
script-engine/common.c
* AppendByte()/AppendWchar() doubled Token->MaxLen before checking whether
the larger buffer was actually allocated. After a failed allocation MaxLen
described memory that did not exist and the next append wrote past the end
of the old buffer. MaxLen is now committed only on success.
* CopyToken() allocated strlen(Value) + 1 bytes but carried over the source
token's Len and MaxLen, so the copy's advertised capacity did not match its
allocation, and WSTRING payloads were truncated at their first embedded
null byte. The copy is now sized from Len/MaxLen and copied by length, with
a fallback to the string length for the grammar tokens in parse-table.c,
which only initialize Type and Value.
* NewToken() set MaxLen to the value length, which is zero for an empty
value. The 'Len >= MaxLen - 1' test in the append routines is unsigned, so
a zero MaxLen wrapped and disabled buffer growth entirely.
* IsUnderscore() tested 'c >= '_'', which also accepted the backtick, the
lowercase letters, '{', '|', '}', '~' and DEL. Register scanning uses it,
so '@rax|1' was lexed as one malformed register name instead of a register,
an operator and a number. The pseudo-register path already compared against
'_' directly.
* NewTokenList() did not check the allocation of its Head buffer.
* NewTemp() kept the last handed-out id in a static, so an exhausted temp
list produced a token aliasing a temporary still in use, and it derived
MaxTempNumber from an out-of-range index. It also dereferenced the new
token without a null check.
* FreeTemp() indexed the MAX_TEMP_COUNT-entry map with an unchecked value
parsed out of the token text.
* RotateLeftStringOnce() wrote to str[-1] when handed an empty string.
libhyperdbg/debugger/misc/pci-id.cpp
* The database file was read into a malloc(Length) buffer that was never
null-terminated, while ReadLine() walks it with strchr(). Looking up an
absent vendor scans to the end and reads past the allocation.
* The matched Vendor was allocated with malloc() and its Devices list head
was only assigned once a device line was parsed, so a vendor with no
device entries left it uninitialized and FreeVendor() walked a garbage
pointer.
* FreeVendor() released the device and subdevice lists but never the Vendor
itself, leaking one per lookup for every enumerated PCI device.
* The file handle leaked when the buffer allocation failed, ftell() and
fread() results were unused, and several error paths leaked the Vendor or
the not-yet-linked Device/SubDevice.
* strncmp() compared sizeof(VendorId) bytes, which is the size of the
pointer rather than the length of a vendor id.
* ReadLine() passed an unclamped count to strncpy_s(), which triggers the
invalid parameter handler for a line longer than the destination.
* GetVendorById() ignored the GetModuleFileName() result and overwrote the
tail of the path buffer without checking the room left in it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W3C1DuhHtqK64eEkHjKCHM
2026-08-01 14:22:52 +00:00
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// An empty string has nothing to rotate, and writing the saved character back
|
|
|
|
|
// would land on str[-1]
|
|
|
|
|
//
|
|
|
|
|
if (Length == 0)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-31 02:21:47 +02:00
|
|
|
for (int i = 0; i < (Length - 1); i++)
|
2023-11-24 04:51:56 +08:00
|
|
|
{
|
|
|
|
|
str[i] = str[i + 1];
|
|
|
|
|
}
|
2026-05-31 02:21:47 +02:00
|
|
|
str[Length - 1] = Temp;
|
2024-03-17 20:33:02 +09:00
|
|
|
}
|