기본 콘텐츠로 건너뛰기

bytes.hex bytes_per_sep range

CPython: bytes.hex(bytes_per_sep) 허용 범위가 커졌다 — sys.maxsize도 이제 OK(gh-147944) meta_description: Python 3.15에서 bytes.hex/bytearray.hex/memoryview.hex 및 binascii.b2a_hex의 bytes_per_sep 인자 허용 범위가 확대되어 sys.maxsize와 -sys.maxsize가 유효해졌다(gh-147944). 겉보기엔 테스트 한 줄 바뀐 수준이지만, 실제로는 Argument Clinic 변환(int→Py_ssize_t)과 정수 변환 경로가 정리되면서 “경계값에서의 Overflow/TypeError”가 더 일관되게 동작한다. 이 글은 무엇이 바뀌었는지, 실무에서 어디에 도움이 되는지(로그/헥스 덤프/프로토콜 디버깅), 그리고 안전한 사용 패턴을 정리한다. meta_keywords: python,bytes,bytearray,memoryview,hex,bytes_per_sep,binascii,b2a_hex,Py_ssize_t,sys.maxsize,OverflowError,Argument Clinic,debugging,hexdump,logging,protocol,binary,호환성,경계값,테스트 meta_robots: index,follow 바이너리 로그를 남기거나(패킷/토큰/압축 데이터), 디버깅용으로 bytes.hex() 를 쓰다 보면 이런 걸 해본 적이 있을 거다. “너무 길어서 보기 힘드니, 구분자(sep)를 넣어서 그룹으로 끊자” 예: payload.hex(':', 2) # b9:01ef 처럼 2바이트마다 구분 payload.hex(' ', -2) # 반대 방향(왼쪽부터)으로 2바이트마다 이때 bytes_per_sep 에 “엄청 큰 값”을 넣으면, 사실상 구분자를 넣지 않는 효과가 난다. bytes_per_sep 가 길이보다 크면 → 구분자 없음 그런데 C...
최근 글

bytes.replace count as keyword

CPython: 이제 bytes.replace()의 count를 키워드로 쓸 수 있다 — 그런데 이 변화가 실무에 주는 이득은? meta_description: CPython에서 bytes.replace()/bytearray.replace()의 count 인자가 키워드 인자로도 지원된다(gh-147856). 겉보기엔 사소한 문법 변화지만, 래퍼 함수/타입 힌트/리팩터링 안정성, 그리고 바이너리 프로토콜 처리 코드의 가독성에 꽤 도움이 된다. 이 글은 무엇이 바뀌었는지, 기존 코드와 호환성은 어떤지, 실무에서 어떻게 써야 이득이 되는지(예시 포함) 정리한다. meta_keywords: python,bytes,bytearray,replace,count,keyword argument,stdlib,cpython,argument clinic,METH_KEYWORDS,refactor,typing,protocol,binary,text processing,호환성,가독성,리팩터링,테스트 meta_robots: index,follow 파이썬 표준 라이브러리/빌트인에 들어가는 변화는 가끔 ‘한 줄짜리 편의’처럼 보이는데, 실제로는 코드베이스 전체의 유지보수 비용을 조금씩 깎는 역할을 한다. 이번 CPython PR(gh-147856)이 딱 그 케이스다. 이제 bytes.replace() 와 bytearray.replace() 에서 count 를 키워드 인자 로 줄 수 있다. 예전에는 이렇게만 됐다. b"aa".replace(b"a", b"b", 1) 이제는 이렇게도 된다. b"aa".replace(b"a", b"b", count=1) “그래서 뭐?” 싶을 수 있는데, 실무에서 특히 바이너리 처리 코드 를 많이 만지는 팀에겐 의외로 이득이 있다. 1) 정확히 무엇이 바뀌었나: 시그니처가 ‘positional-only...

Avoiding a Leak on Allocation Failure

CPython: 서브인터프리터 데이터 공유에서 ‘할당 실패’ 한 번이 누적 메모리 누수로 이어질 수 있던 경로(gh-147960) meta_description: CPython의 cross-interpreter data 공유 코드에서 튜플을 공유 데이터로 바꾸는 과정(_tuple_shared) 중 메모리 할당이 실패하면, 에러는 MemoryError로 떨어지지만 일부 구조체가 해제되지 않아 누수가 생길 수 있었다. gh-147960은 실패 경로에서 shared 구조체를 RawFree 해 누수를 막는다. 이 글은 “왜 이런 한 줄이 중요해지는지”, 서브인터프리터/임베딩/확장모듈 개발자가 놓치기 쉬운 실패 경로 설계, 테스트/관측 포인트를 실무 관점으로 정리한다. meta_keywords: python,cpython,subinterpreters,cross-interpreter data,_tuple_shared,MemoryError,allocation failure,memory leak,PyMem_RawFree,PyMem_Calloc,error path,임베딩,확장모듈,안정성,회귀,테스트,관측,메모리 meta_robots: index,follow CPython PR 하나가 병합됐다. 제목은 소박하다: “할당 실패 시 _tuple_shared()에서 메모리 누수 방지” diff는 더 소박하다: 한 줄 하지만 이런 종류의 패치는, 특정 환경에서는 체감 임팩트가 크다. 서버가 오래 떠 있고 서브인터프리터(subinterpreters)를 많이 돌리거나 임베딩/확장 모듈이 많고 메모리 압박 상황(컨테이너 제한/스파이크)이 가끔 생기는 곳 여기서는 “드물게 한 번 터지는 할당 실패”가 누적으로 번지는 문제가 되기 쉽다. 1) 무엇이 바뀌었나: 실패 경로에서 구조체를 하나 더 해제한다 PR에서 바뀐 코드는 이거다. 튜플 공유 데이터를 만들면서 shared->items 배열을 PyMem_Calloc()...

sqlite3 Collation Busy Crash Fix

CPython sqlite3: create_collation 중 SQLITE_BUSY가 터질 때 크래시하던 경로가 막혔다(gh-146090) meta_description: CPython sqlite3 모듈에서 Connection.create_collation()이 실행 중인 statement 때문에 SQLITE_BUSY로 실패하는 경우, 특정 참조/해제 경로에서 크래시가 날 수 있던 버그가 수정됐다(gh-146090). 이 글은 왜 BUSY가 나오는지, 애플리케이션/라이브러리에서 재현을 줄이는 패턴, 회귀 테스트 아이디어, 그리고 업그레이드 우선순위를 정리한다. meta_keywords: python,sqlite3,cpython,create_collation,SQLITE_BUSY,OperationalError,collation,statement,커서,트랜잭션,MemoryError,SystemError,callback context,레퍼런스카운트,회귀테스트,업그레이드,안정성,크래시 meta_robots: index,follow SQLite는 “가볍고 빠른 내장 DB”라는 이미지가 강하지만, 파이썬에서 sqlite3를 조금만 깊게 쓰기 시작하면 ‘DB가 바쁜 상태(BUSY)’ 를 마주칠 때가 있다. 대표적으로 이런 케이스다. 같은 연결에서 커서를 열어 SELECT ... ORDER BY ... COLLATE mycoll 을 실행 중인데 그 와중에 create_collation("mycoll", ...) 로 같은 이름의 collation을 교체하려고 한다 이때 SQLite는 자연스럽게 SQLITE_BUSY 를 반환한다. (실행 중인 statement가 collation을 쓰고 있으니 “지금은 바꾸지 마”라는 뜻) 문제는 예전의 CPython sqlite3 구현에서 이 실패 경로가 파이썬 예외(OperationalError)로 끝나지 않고, 특정 조건에서 크래시까지 이어질 수 있는 모서리 가 있었다는 점이다...

Fixing a Crash in SNI Callbacks

CPython: SNI 콜백에서 ‘죽은 SSL 객체’ 참조로 크래시 나던 케이스가 고쳐졌다(gh-146080) meta_description: CPython에서 SNI(server_name) 콜백이 호출되는 타이밍에 SSLSocket/SSLObject가 이미 GC로 사라진 경우, 내부 C 콜백이 NULL을 DECREF 하며 크래시할 수 있던 버그가 수정됐다(gh-146080). 이 글은 어떤 상황에서 발생하는지, 파이썬 코드 레벨에서 무엇을 조심해야 하는지, 그리고 라이브러리 작성자가 테스트로 재현/회귀 방지하는 방법을 정리한다. meta_keywords: python,cpython,ssl,sni,servername callback,wrap_bio,MemoryBIO,garbage collection,crash,segfault,SSLSocket,SSLObject,OpenSSL,AWS-LC,핸드셰이크,약한참조,콜백,테스트,회귀 meta_robots: index,follow SNI(Server Name Indication) 콜백은 “TLS 핸드셰이크 도중, 클라이언트가 보낸 server name(hostname)에 따라 인증서/컨텍스트를 바꾸고 싶다” 같은 고급 케이스에서 사용된다. 문제는 이 콜백이 엄청 이른 시점(핸드셰이크 중간) 에 실행되고, 구현 실수로 SSLSocket / SSLObject 의 생명주기를 잘못 다루면 “파이썬 예외”가 아니라 프로세스 크래시 로 튈 수 있다는 점이다. 지난 72시간 내 merged 된 CPython 변경(gh-146080)은 딱 그 모서리를 하나 메운다. SNI 콜백이 호출되려는 순간 콜백의 소유자(SSLSocket/SSLObject)가 이미 GC로 사라져 내부 포인터가 NULL이 될 수 있는 상황에서 NULL을 Py_DECREF() 하며 크래시할 수 있던 부분을 Py_XDECREF() 로 바꿔서 “정상적인 SSL 에러”로 처리하게 했다. 1) 무엇이 고쳐졌나: 한 줄이...

Propagate -X to child processes

`multiprocessing` 자식 프로세스에서만 -X 옵션이 사라진다면: PR #146005가 정리한 “인터프리터 플래그 전달” meta_description: CPython PR #146005는 subprocess/multiprocessing이 자식 파이썬 프로세스를 띄울 때 -X 옵션을 누락 없이 전달하도록 수정한다. dev/tracemalloc/importtime 등 런타임 디버그 옵션이 부모에서는 켜졌는데 자식에서만 꺼지는 문제를 줄인다. 운영/디버깅 관점에서 어떤 증상이 사라지는지, 어떤 -X 옵션이 특히 중요하며, 호환성/주의점은 무엇인지 정리한다. meta_keywords: python, multiprocessing, subprocess, -X, xoptions, dev mode, tracemalloc, importtime, faulthandler, debugging, child process, CI, production, practical meta_robots: index,follow 운영 디버깅에서 제일 짜증나는 버그 유형이 있다. 부모 프로세스에서는 디버그 옵션이 켜져 있는데 자식 프로세스(특히 multiprocessing 으로 띄운)에서는 꺼져 있다 그래서 로그가 갈라지고, 재현이 흐려진다. -X tracemalloc 은 켰는데, 자식에서 스냅샷이 없다 -X importtime 켰는데, 자식 프로세스의 import 시간은 안 찍힌다 -X dev 켰는데, 자식에서만 경고가 안 뜬다 PR #146005(gh-146004)는 이 ‘갈라짐’을 줄이는 방향으로 subprocess 쪽 플래그 전달을 정리한다. 핵심은 간단하다. 부모 인터프리터에 설정된 -X 옵션(xoptions)을, 자식 파이썬 프로세스 실행 인자에 일관되게 전달한다. 1) PR #146005가 바꾼 것: “일부만 전달” → “전부 전달(정렬해서)” diff의 핵심은 Lib/subprocess.py ...

OrderedDict popitem leak fix

`OrderedDict.popitem()`을 돌렸는데 메모리가 내려오지 않는다: PR #146537이 손본 ‘가능한 누수’의 실전 증상 meta_description: CPython PR #146537은 OrderedDict의 popitem() 경로에서 발생할 수 있는 메모리 누수 가능성을 수정한다. 반복 popitem을 쓰는 캐시/큐/스케줄러에서 “요소는 지웠는데 RSS가 안 내려가는” 현상이 왜 나올 수 있는지, 어떤 버전에서 조심해야 하는지, 그리고 운영 코드에서 진단(tracemalloc/heap snapshot)과 완화(업그레이드, 패턴 변경)를 실무적으로 정리한다. meta_keywords: python, OrderedDict, popitem, memory leak, RSS, tracemalloc, CPython, cache, queue, eviction, dict, reference, practical, 운영, 진단 meta_robots: index,follow 운영에서 메모리 이슈는 늘 불쾌하다. 특히 더 불쾌한 건 이런 형태다. 캐시에서 항목을 “계속 지운다” 모니터링 그래프에서 객체 개수도 줄어든다 그런데 RSS가 안 내려온다(혹은 아주 천천히만) 이때 팀은 서로 다른 결론으로 갈라진다. “파이썬은 원래 메모리 반환을 안 해” “어딘가 참조가 남았어(진짜 leak)” “컨테이너가 찢어져서 조각난 거야(fragmentation)” 정답은 케이스 바이 케이스인데, 이런 논쟁의 바닥엔 늘 같은 질문이 있다. “내 코드가 지운 게 진짜로 지워졌나?” CPython PR #146537은 이 질문에 직접 연결되는 작은 수정이다. [3.14] Fix possible memory leak in OrderedDict popitem 이 글은 PR을 곧이곧대로 요약하기보다, “운영에서 popitem이 등장하는 상황”에 맞춰서 설명한다. 1) 왜 popitem() 이 실무에서 중요하...