1
0

proj/test-memory: Add getline() and getdelim()

This commit is contained in:
2025-05-06 18:36:51 +02:00
parent b29e8fb7d9
commit 2fff206f6a
5 changed files with 129 additions and 27 deletions

View File

@@ -1,16 +1,26 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Optional, TypedDict, NotRequired, BinaryIO
from typing import Optional, TypedDict, NamedTuple, NotRequired, BinaryIO
from socketserver import UnixStreamServer, StreamRequestHandler, ThreadingMixIn
import os
import re
type Pointer = int
type PointerTo[T] = tuple[Pointer, T]
type Constant = tuple[int, str]
type Flags = tuple[int, list[str]]
class PointerTo[T](NamedTuple):
ptr: Pointer
target: T
class Constant(NamedTuple):
raw: int
name: str
class Flags(NamedTuple):
bitfield: int
flags: list[str]
StructTimeSpec = TypedDict('StructTimeSpec', {'tv_sec': int, 'tv_nsec': int})
StructSigAction = TypedDict('StructSigAction', {'sa_flags': Flags, 'sa_handler': NotRequired[Pointer], 'sa_sigaction': NotRequired[Pointer], 'sa_mask': list[str]})
StructSockAddr = TypedDict('StructSockAddr', {'sa_family': Constant, 'sa_data': NotRequired[bytes],
@@ -166,7 +176,7 @@ class Parser:
if m:
idx = len(m.group(0)) - 1
s, i = Parser.parse_str(argument[idx:])
idx = i
idx += i
if idx < len(argument) and argument[idx] in ',;':
idx += 1
return s, idx
@@ -207,7 +217,7 @@ class Parser:
idx += i
if idx < len(argument) and argument[idx] == ',':
idx += 1
return (val, list(l)), idx
return PointerTo(val, list(l)), idx
elif argument[idx] == '|':
m = re.match(r'^[| A-Za-z0-9_]*', argument[idx:])
flags = m.group(0)
@@ -217,20 +227,20 @@ class Parser:
if idx < len(argument) and argument[idx] == ',':
idx += 1
flags = [f.strip() for f in flags[1:-1].split('|') if len(f.strip()) > 0]
return (val, flags), idx
return Flags(val, flags), idx
elif argument[idx] == '"':
s, i = Parser.parse_str(argument[idx:])
idx += i
if idx < len(argument) and argument[idx] == ',':
idx += 1
return (val, s), idx
return PointerTo(val, s), idx
elif argument[idx] == '{':
idx += 1
l, i = Parser.parse_args(argument[idx:], named=True)
idx += i
if idx < len(argument) and argument[idx] == ',':
idx += 1
return (val, list(l)), idx
return PointerTo(val, l), idx
else:
m = re.match(r'[A-Z0-9_]+', argument[idx:])
if not m:
@@ -239,7 +249,7 @@ class Parser:
idx += len(value)
if idx < len(argument) and argument[idx] == ',':
idx += 1
return (val, value), idx
return Constant(val, value), idx
@staticmethod
def parse_args(arguments: str, named: bool = False, ret: bool = False) -> tuple[tuple or dict, int]:
@@ -594,12 +604,12 @@ class Parser:
def before_sendto(self, sockfd: int, buf: PointerTo[bytes], length: int, flags: Flags, dest_addr: PointerTo[StructSockAddr], addrlen: int) -> str:
raise NotImplementedError()
def after_sendto(self, sockfd: int, buf: PointerTo[bytes], length: int, flags: Flags, dest_addr: PointerTo[StructSockAddr], addrlen: int,
ret_value: int, errno: str = None) -> None:
ret_value: int, errno: str = None) -> None:
raise NotImplementedError()
def before_sendmsg(self, sockfd: int, message: StructMsgHdr, flags: Flags) -> str:
raise NotImplementedError()
def after_sendmsg(self, sockfd: int, message: StructMsgHdr, flags: Flags,
ret_value: int, errno: str = None) -> None:
ret_value: int, errno: str = None) -> None:
raise NotImplementedError()
def before_recv(self, sockfd: int, buf_ptr: Pointer, size: int, flags: Flags) -> str:
raise NotImplementedError()
@@ -609,12 +619,22 @@ class Parser:
def before_recvfrom(self, sockfd: int, buf_ptr: Pointer, size: int, flags: Flags, src_addr_ptr: Pointer, addrlen_ptr: Pointer) -> str:
raise NotImplementedError()
def after_recvfrom(self, sockfd: int, buf_ptr: Pointer, size: int, flags: Flags, src_addr_ptr: Pointer, addrlen_ptr: Pointer,
ret_value: int, errno: str = None, buf: PointerTo[bytes] = None, src_addr: PointerTo[StructSockAddr] = None, addrlen: int = None) -> None:
ret_value: int, errno: str = None, buf: PointerTo[bytes] = None, src_addr: PointerTo[StructSockAddr] = None, addrlen: int = None) -> None:
raise NotImplementedError()
def before_recvmsg(self, sockfd: int, message_ptr: Pointer, flags: Flags) -> str:
raise NotImplementedError()
def after_recvmsg(self, sockfd: int, message_ptr: Pointer, flags: Flags,
ret_value: int, errno: str = None, message: PointerTo[StructMsgHdr] = None) -> None:
ret_value: int, errno: str = None, message: PointerTo[StructMsgHdr] = None) -> None:
raise NotImplementedError()
def before_getline(self, line_ptr: PointerTo[Pointer], n_ptr: PointerTo[int], stream: Pointer) -> str:
raise NotImplementedError()
def after_getline(self, line_ptr: PointerTo[Pointer], n_ptr: PointerTo[int], stream: Pointer,
ret_value: int, errno: str = None, n: int = None, line: PointerTo[bytes] = None) -> None:
raise NotImplementedError()
def before_getdelim(self, line_ptr: PointerTo[Pointer], n_ptr: PointerTo[int], delim: int, stream: Pointer) -> str:
raise NotImplementedError()
def after_getdelim(self, line_ptr: PointerTo[Pointer], n_ptr: PointerTo[int], delim: int, stream: Pointer,
ret_value: int, errno: str = None, n: int = None, line: PointerTo[bytes] = None) -> None:
raise NotImplementedError()

View File

@@ -74,25 +74,25 @@ class MemoryAllocationParser(Parser):
self.max_allocated = total
def after_malloc(self, size, ret_value, errno=None) -> None:
self.num_alloc += 1
if ret_value != 0:
self.num_alloc += 1
self.allocated[ret_value] = (self.get_call_id('malloc'), size)
self.update_max_allocated()
def after_calloc(self, nmemb, size, ret_value, errno=None) -> None:
self.num_alloc += 1
if ret_value != 0:
self.num_alloc += 1
self.allocated[ret_value] = (self.get_call_id('calloc'), nmemb * size)
self.update_max_allocated()
def after_realloc(self, ptr, size, ret_value, errno=None) -> None:
if ptr == 0:
self.num_alloc += 1
if ret_value != 0:
self.num_alloc += 1
self.allocated[ret_value] = (self.get_call_id('realloc'), size)
else:
self.num_realloc += 1
if ret_value != 0 and ptr in self.allocated:
self.num_realloc += 1
v = self.allocated[ptr]
del self.allocated[ptr]
self.allocated[ret_value] = (v[0], size)
@@ -100,22 +100,46 @@ class MemoryAllocationParser(Parser):
def after_reallocarray(self, ptr, nmemb, size, ret_value, errno=None) -> None:
if ptr == 0:
self.num_alloc += 1
if ret_value != 0:
self.num_alloc += 1
self.allocated[ret_value] = (self.get_call_id('reallocarray'), nmemb * size)
else:
self.num_realloc += 1
if ret_value != 0:
self.num_realloc += 1
v = self.allocated[ptr]
del self.allocated[ptr]
self.allocated[ret_value] = (v[0], nmemb * size)
self.update_max_allocated()
def after_getaddrinfo(self, node, service, hints, res_ptr, ret_value, errno=None, res=None) -> None:
self.num_alloc += 1
if ret_value[0] == 0 and res is not None:
size = sum(48 + r['ai_addrlen'] for r in res[1])
self.allocated[res[0]] = (self.get_call_id('getaddrinfo'), size)
if ret_value.raw == 0 and res is not None:
self.num_alloc += 1
size = sum(48 + r['ai_addrlen'] for r in res.target)
self.allocated[res.ptr] = (self.get_call_id('getaddrinfo'), size)
self.update_max_allocated()
def after_getline(self, line_ptr, n_ptr, stream, ret_value, errno=None, n=None, line=None) -> None:
if ret_value >= 0 and n is not None and line is not None:
if line_ptr.target == 0:
self.num_alloc += 1
self.allocated[line.ptr] = (self.get_call_id('getline'), n)
elif line_ptr.target != line.ptr:
self.num_realloc += 1
v = self.allocated[line.ptr]
del self.allocated[line.ptr]
self.allocated[ret_value] = (v[0], n)
self.update_max_allocated()
def after_getdelim(self, line_ptr, n_ptr, delim, stream, ret_value, errno=None, n=None, line=None) -> None:
if ret_value >= 0 and n is not None and line is not None:
if line_ptr.target == 0:
self.num_alloc += 1
self.allocated[line.ptr] = (self.get_call_id('getdelim'), n)
elif line_ptr.target != line.ptr:
self.num_realloc += 1
v = self.allocated[line.ptr]
del self.allocated[line.ptr]
self.allocated[ret_value] = (v[0], n)
self.update_max_allocated()
def after_free(self, ptr) -> None:

View File

@@ -46,7 +46,7 @@ def main() -> None:
'LD_PRELOAD': os.getcwd() + '/../../intercept/intercept.so',
'INTERCEPT': 'file:' + log_file,
'INTERCEPT_VERBOSE': '1',
'INTERCEPT_FUNCTIONS': ','.join(['malloc', 'calloc', 'realloc', 'reallocarray', 'free', 'getaddrinfo', 'freeaddrinfo']),
'INTERCEPT_FUNCTIONS': ','.join(['malloc', 'calloc', 'realloc', 'reallocarray', 'free', 'getaddrinfo', 'freeaddrinfo', 'getline', 'getdelim']),
'INTERCEPT_LIBRARIES': ','.join(['*', '-/lib*', '-/usr/lib*']),
})
finally: