Subject: repack: fix uninitialized DecodingWorkerShared.initialized

From: Chao Li <[email-masked]>
Date: Wed, 15 Apr 2026 18:22:44 +0800

Hi,

I have not reviewed the repack-related patches before. Recently, I started trying to understand how repack works and trace through the code.

While tracing start_repack_decoding_worker(), I noticed something suspicious:

```
	seg = dsm_create(size, 0);
	shared = (DecodingWorkerShared *) dsm_segment_address(seg);
	shared->lsn_upto = InvalidXLogRecPtr;
	shared->done = false;
	SharedFileSetInit(&shared->sfs, seg);
	shared->last_exported = -1;
	SpinLockInit(&shared->mutex);
	shared->dbid = MyDatabaseId;
```

Here, the code creates a shared-memory segment and lets “shared" point to that memory. It then initializes some fields of “shared". However, later code reads shared->initialized, but this field was not initialized:
```
	for (;;)
	{
		bool		initialized;

		SpinLockAcquire(&shared->mutex);
		initialized = shared->initialized;
		SpinLockRelease(&shared->mutex);

		if (initialized)
			break;

		ConditionVariableSleep(&shared->cv, WAIT_EVENT_REPACK_WORKER_EXPORT);
	}
```

I checked the code of dsm_create(), and I did not see anything showing that the created shared-memory segment is zeroed.

This is actually just an eyeball finding. From my tracing on my MacBook, after shared = (DecodingWorkerShared *) dsm_segment_address(seg);, the memory always seemed to be zeroed, so I may have missed something. But given that the code explicitly initializes several other fields, it seems better not to rely on that implicitly.

For the fix, since start_repack_decoding_worker() is not on a hot path, I think it is fine to zero the whole shared struct explicitly, and then initialize the non-zero fields afterwards.

Best regards,
--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/

---

From: Antonin Houska <[email-masked]>
Date: Wed, 15 Apr 2026 17:07:32 +0200

> I have not reviewed the repack-related patches before. Recently, I started trying to understand how repack works and trace through the code.

Thanks, I appreciate that!

> Here, the code creates a shared-memory segment and lets “shared" point to that memory. It then initializes some fields of “shared". However, later code reads shared->initialized, but this field was…

The problem was noticed earlier this week and I already posted a fix [1].

> For the fix, since start_repack_decoding_worker() is not on a hot path, I think it is fine to zero the whole shared struct explicitly, and then initialize the non-zero fields afterwards.

Although not strongly, I prefer setting individual fields explicitly.

[1] https://www.postgresql.org/message-id/182883.1776073323%40localhost

-- 
Antonin Houska
Web: https://www.cybertec-postgresql.com

---

From: Chao Li <[email-masked]>
Date: Fri, 17 Apr 2026 11:41:37 +0800

> On Apr 15, 2026, at 23:07, Antonin Houska <[email-masked]> wrote:
> 

I saw 05c401d5786a05ea630e884ffa492aa01683d15b has fixed this issue, so this patch is no longer needed.

Best regards,

---

From: Thomas Munro <[email-masked]>
Date: Fri, 17 Apr 2026 22:27:19 +1200

> This is actually just an eyeball finding. From my tracing on my MacBook, after shared = (DecodingWorkerShared *) dsm_segment_address(seg);, the memory always seemed to be zeroed, so I may have miss…

For the record, that depends on whether you get a newly allocated
shared memory segment from the operating system, or recycled shared
memory reserved at startup with the min_dynamic_shared_memory setting
(as shown in Alexander Lakhin's reproducer).