Repository: AlistGo/alist (language: go)

Issue:
Alist v3.43.0 , 百度网盘上传程序闪退，回滚到 v3.42.0 后正常
### Please make sure of the following things

- [x] I have read the [documentation](https://alist.nn.ci).
我已经阅读了[文档](https://alist.nn.ci)。

- [x] I'm sure there are no duplicate issues or discussions.
我确定没有重复的issue或讨论。

- [x] I'm sure it's due to `AList` and not something else(such as [Network](https://alist.nn.ci/faq/howto.html#tls-handshake-timeout-read-connection-reset-by-peer-dns-lookup-failed-connect-connection-refused-client-timeout-exceeded-while-awaiting-headers-no-such-host) ,`Dependencies` or `Operational`).
我确定是`AList`的问题，而不是其他原因（例如[网络](https://alist.nn.ci/zh/faq/howto.html#tls-handshake-timeout-read-connection-reset-by-peer-dns-lookup-failed-connect-connection-refused-client-timeout-exceeded-while-awaiting-headers-no-such-host)，`依赖`或`操作`）。

- [x] I'm sure this issue is not fixed in the latest version.
我确定这个问题在最新版本中没有被修复。


### AList Version / AList 版本

v3.43.0

### Driver used / 使用的存储驱动

百度网盘

### Describe the bug / 问题描述

Alist v3.43.0 , 百度网盘上传程序闪退，回滚到 v3.42.0 后正常。提示如图示

![Image](https://github.com/user-attachments/assets/a29e769e-0734-4769-bad8-b20d4c0be910)

### Reproduction / 复现链接

随时随地复现

### Config / 配置

不会提供

### Logs / 日志

_No response_


Discussion / hints:
感谢您提供详细的信息。根据您的描述，Alist v3.43.0 在使用百度网盘上传时出现了程序闪退的问题，而回滚到 v3.42.0 后问题消失。这可能是由于新版本中的某些更改导致的兼容性问题。

为了帮助解决这个问题，您可以尝试以下步骤：

1. **检查更新日志**：查看 v3.43.0 的更新日志，看看是否有关于百度网盘或上传功能的更改。

2. **提供更多日志信息**：如果可能，请尝试获取更多的日志信息，这将有助于开发者更好地诊断问题。

3. **测试其他驱动**：如果您有其他存储驱动可用，尝试使用其他驱动进行上传，看看是否也会出现类似的问题。

4. **反馈给开发者**：如果问题持续存在，建议将此问题反馈给开发者，以便他们进行修复。

如果您愿意，我可以帮助您在 GitHub 上创建一个问题报告，以便开发者能够更快地看到并解决这个问题。请告诉我您的决定。

<details>
<summary>🪧 Tips</summary>
For further assistance, please describe your question in the comments and @petercat-assistant to start a conversation with me.
</details>
看一下日志或者命令行跑起来看一下报错在哪，3.43 baidu_netdisk 应该只有我交的的两个pr有改动，但是我（包括我周围一圈）用起来都没问题
另外问几个最基本的问题：上传文件大小，挂载百度网盘的参数，你账号的vip级别

参数可以把这块截图看看

![Image](https://github.com/user-attachments/assets/5b03319b-ba93-44de-ac54-97427711ed18)
> 另外问几个最基本的问题：上传文件大小，挂载百度网盘的参数，你账号的vip级别
> 
> 参数可以把这块截图看看
> 
> ![Image](https://github.com/user-attachments/assets/5b03319b-ba93-44de-ac54-97427711ed18)

![Image](https://github.com/user-attachments/assets/3bdb24d3-bcf9-4c57-a39f-800773723a5c)

![Image](https://github.com/user-attachments/assets/b56de7fe-1843-4edd-bcaf-040b7fce2ca6)

![Image](https://github.com/user-attachments/assets/e0858d9d-68e2-44b9-84a7-360ebf54c54a)
如图，每次都是在一个文件要上传完的时候报错，我没有VIP，文件4G左右，之前的版本就没有这个问题，参数对比之前的版本也没有任何的变动
> 普通用户单个上传文件大小上限为4GB

你可能要严格确定一下文件大小有没有超。图上warn里的分片号可以一起给一下吗

崩溃看样子是个信号量重复释放的问题，在 #7972 的改动重试逻辑覆盖应该会涉及这段代码，但是没有实质性更改。
> > 普通用户单个上传文件大小上限为4GB
> 
> 你可能要严格确定一下文件大小有没有超。图上warn里的分片号可以一起给一下吗
> 
> 崩溃看样子是个信号量重复释放的问题，在 [#7972](https://github.com/AlistGo/alist/pull/7972) 的改动重试逻辑覆盖应该会涉及这段代码，但是没有实质性更改。

2025/03/23 10:12:10.357571 WARN RESTY Post "https://d.pcs.baidu.com/rest/2.0/pcs/superfile2?access_token=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&method=upload&partseq=1&path=%2F141+%E5%8E%BB%E6%A8%AA%E7%BA%B9.mp4.z01&type=tmpfile&uploadid=P1-MTAuMTQ2LjE2Mi4yNzoxNzQyNzI0NzAwOjg4MTM3MzAxMjY2ODcxNDkzOTY%3D": context deadline exceeded (Client.Timeout exceeded while awaiting headers), Attempt 1
panic: semaphore: released more than held
#7948 @KirCute 看看

> [#7948](https://github.com/AlistGo/alist/pull/7948) [@KirCute](https://github.com/KirCute) 看看

看起来确实是我的问题，但我没看懂为什么会出这个问题，semaphore 是在 L269 获取的，在 L278 释放的，按理来说每获取一个就会创建一个上传线程，每个上传线程结束时一定会释放一个，应该不会出现释放比获取多的问题。会不会是这个 errgroup 有什么我不知道的重试机制。
https://github.com/AlistGo/alist/blob/32890da29f72e380ffd6e64df4a693e5cd4f3baa/drivers/baidu_netdisk/driver.go#L263-L281
> > [#7948](https://github.com/AlistGo/alist/pull/7948) [@KirCute](https://github.com/KirCute) 看看
> 
> 看起来确实是我的问题，但我没看懂为什么会出这个问题，semaphore 是在 L269 获取的，在 L278 释放的，按理来说每获取一个就会创建一个上传线程，每个上传线程结束时一定会释放一个，应该不会出现释放比获取多的问题。会不会是这个 errgroup 有什么我不知道的重试机制。
> 
> [alist/drivers/baidu_netdisk/driver.go](https://github.com/AlistGo/alist/blob/32890da29f72e380ffd6e64df4a693e5cd4f3baa/drivers/baidu_netdisk/driver.go#L263-L281)
> 
> Lines 263 to 281 in [32890da](/AlistGo/alist/commit/32890da29f72e380ffd6e64df4a693e5cd4f3baa)
> 
>  threadG, upCtx := errgroup.NewGroupWithContext(ctx, d.uploadThread) 
>  sem := semaphore.NewWeighted(3) 
>  for i, partseq := range precreateResp.BlockList { 
>  	if utils.IsCanceled(upCtx) { 
>  		break 
>  	} 
>  	if err = sem.Acquire(ctx, 1); err != nil { 
>  		break 
>  	} 
>   
>  	i, partseq, offset, byteSize := i, partseq, int64(partseq)*sliceSize, sliceSize 
>  	if partseq+1 == count { 
>  		byteSize = lastBlockSize 
>  	} 
>  	threadG.Go(func(ctx context.Context) error { 
>  		defer sem.Release(1) 
>  		params := map[string]string{ 
>  			"method":       "upload", 
>  			"access_token": d.AccessToken,

#7972 里我把 errgroup 的重试给撤了的，现在应该只靠 RestyClient 重试

（没撤掉的话好像炸的更严重，已经是歪打正着修了一波了）
> （没撤掉的话好像炸的更严重，已经是歪打正着修了一波了）

要不我把获取信号量放到线程函数里面算了，大不了就是有一堆线程在空等待，总比直接炸了好
```go
	DefaultAttempts      = uint(10)
	DefaultDelay         = 100 * time.Millisecond
	DefaultMaxJitter     = 100 * time.Millisecond
	DefaultOnRetry       = func(n uint, err error) {}
	DefaultRetryIf       = IsRecoverable
	DefaultDelayType     = CombineDelay(BackOffDelay, RandomDelay)
	DefaultLastErrorOnly = false
	DefaultContext       = context.Background()
```

认真看了一下，是我改动造成的问题。

可能要考虑一下在 `pkg/errgroup` 覆盖一下 `retry` 的默认值
应该说改不改都会有问题，只是改了放大了问题
> 应该说改不改都会有问题，只是改了放大了问题

我觉得还是应该让分片上传可以重试比较好，要不我还是把获取信号量放到线程里吧
> > 应该说改不改都会有问题，只是改了放大了问题
> 
> 我觉得还是应该让分片上传可以重试比较好，要不我还是把获取信号量放到线程里吧

我改是因为有两层重试，一层 `RestyClient` 一层 `errgroup` 这样看日志的时候报错会有点懵。

两层都留的话，外层丢异步重试可能是合理的。

我的pr肯定是要改一下的了，你看看你的是不是用到信号量的地方也要检查一下从重试。

Fix patch:
diff --git a/drivers/189pc/utils.go b/drivers/189pc/utils.go
index 290d2e568aa..fb1a183ab38 100644
--- a/drivers/189pc/utils.go
+++ b/drivers/189pc/utils.go
@@ -520,9 +520,6 @@ func (y *Cloud189PC) StreamUpload(ctx context.Context, dstDir model.Obj, file mo
 		if utils.IsCanceled(upCtx) {
 			break
 		}
-		if err = sem.Acquire(ctx, 1); err != nil {
-			break
-		}
 		byteData := make([]byte, sliceSize)
 		if i == count {
 			byteData = byteData[:lastPartSize]
@@ -541,6 +538,9 @@ func (y *Cloud189PC) StreamUpload(ctx context.Context, dstDir model.Obj, file mo
 		partInfo := fmt.Sprintf("%d-%s", i, base64.StdEncoding.EncodeToString(md5Bytes))
 
 		threadG.Go(func(ctx context.Context) error {
+			if err = sem.Acquire(ctx, 1); err != nil {
+				return err
+			}
 			defer sem.Release(1)
 			uploadUrls, err := y.GetMultiUploadUrls(ctx, isFamily, initMultiUpload.Data.UploadFileID, partInfo)
 			if err != nil {
diff --git a/drivers/baidu_netdisk/driver.go b/drivers/baidu_netdisk/driver.go
index 264f3b0225f..6ea62197b70 100644
--- a/drivers/baidu_netdisk/driver.go
+++ b/drivers/baidu_netdisk/driver.go
@@ -266,15 +266,15 @@ func (d *BaiduNetdisk) Put(ctx context.Context, dstDir model.Obj, stream model.F
 		if utils.IsCanceled(upCtx) {
 			break
 		}
-		if err = sem.Acquire(ctx, 1); err != nil {
-			break
-		}
 
 		i, partseq, offset, byteSize := i, partseq, int64(partseq)*sliceSize, sliceSize
 		if partseq+1 == count {
 			byteSize = lastBlockSize
 		}
 		threadG.Go(func(ctx context.Context) error {
+			if err = sem.Acquire(ctx, 1); err != nil {
+				return err
+			}
 			defer sem.Release(1)
 			params := map[string]string{
 				"method":       "upload",
diff --git a/drivers/baidu_photo/driver.go b/drivers/baidu_photo/driver.go
index 9ee0a7ae860..eeee746f71d 100644
--- a/drivers/baidu_photo/driver.go
+++ b/drivers/baidu_photo/driver.go
@@ -321,9 +321,6 @@ func (d *BaiduPhoto) Put(ctx context.Context, dstDir model.Obj, stream model.Fil
 			if utils.IsCanceled(upCtx) {
 				break
 			}
-			if err = sem.Acquire(ctx, 1); err != nil {
-				break
-			}
 
 			i, partseq, offset, byteSize := i, partseq, int64(partseq)*DEFAULT, DEFAULT
 			if partseq+1 == count {
@@ -331,6 +328,9 @@ func (d *BaiduPhoto) Put(ctx context.Context, dstDir model.Obj, stream model.Fil
 			}
 
 			threadG.Go(func(ctx context.Context) error {
+				if err = sem.Acquire(ctx, 1); err != nil {
+					return err
+				}
 				defer sem.Release(1)
 				uploadParams := map[string]string{
 					"method":   "upload",
diff --git a/drivers/mopan/driver.go b/drivers/mopan/driver.go
index 2cbabe46b36..736d612a96b 100644
--- a/drivers/mopan/driver.go
+++ b/drivers/mopan/driver.go
@@ -315,9 +315,6 @@ func (d *MoPan) Put(ctx context.Context, dstDir model.Obj, stream model.FileStre
 			if utils.IsCanceled(upCtx) {
 				break
 			}
-			if err = sem.Acquire(ctx, 1); err != nil {
-				break
-			}
 			i, part, byteSize := i, part, initUpdload.PartSize
 			if part.PartNumber == uploadPartData.PartTotal {
 				byteSize = initUpdload.LastPartSize
@@ -325,6 +322,9 @@ func (d *MoPan) Put(ctx context.Context, dstDir model.Obj, stream model.FileStre
 
 			// step.4
 			threadG.Go(func(ctx context.Context) error {
+				if err = sem.Acquire(ctx, 1); err != nil {
+					return err
+				}
 				defer sem.Release(1)
 				reader := io.NewSectionReader(file, int64(part.PartNumber-1)*initUpdload.PartSize, byteSize)
 				req, err := part.NewRequest(ctx, driver.NewLimitedUploadStream(ctx, reader))


Test patch: