Skip to content

Commit 7486c47

Browse files
authored
Merge pull request #10 from kolesa-team/fix-prevent-cleanup-gc
Enhance image handling with nil checks and memory management improvements
2 parents 162de2f + 08eae54 commit 7486c47

File tree

4 files changed

+79
-14
lines changed

4 files changed

+79
-14
lines changed

Makefile

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.PHONY: test test-concurrent-3 test-concurrent-10 test-concurrent-100
2+
3+
test:
4+
go test -v ./...
5+
6+
test-concurrent-3:
7+
go test -run Test_GetBytes_Goroutine -count=3 -v
8+
9+
test-concurrent-10:
10+
go test -run Test_GetBytes_Goroutine -count=10 -v
11+
12+
test-concurrent-100:
13+
go test -run Test_GetBytes_Goroutine -count=100 -v

exiv.go

Lines changed: 66 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,15 @@ func makeImage(cimg *C.Exiv2Image, bytesPtr unsafe.Pointer) *Image {
5656
img: cimg,
5757
}
5858

59-
runtime.SetFinalizer(img, func(x *Image) {
60-
C.exiv2_image_free(x.img)
61-
62-
if x.bytesArrayPtr != nil {
63-
C.free(x.bytesArrayPtr)
64-
}
65-
})
59+
runtime.SetFinalizer(
60+
img, func(x *Image) {
61+
C.exiv2_image_free(x.img)
62+
63+
if x.bytesArrayPtr != nil {
64+
C.free(x.bytesArrayPtr)
65+
}
66+
},
67+
)
6668

6769
return img
6870
}
@@ -130,6 +132,10 @@ func SetLogMsgLevel(level LogMsgLevel) {
130132

131133
// ReadMetadata reads the metadata of an Image
132134
func (i *Image) ReadMetadata() error {
135+
if i.img == nil {
136+
return errors.New("image instance is not initialized: underlying C structure is nil")
137+
}
138+
133139
var cerr *C.Exiv2Error
134140

135141
C.exiv2_image_read_metadata(i.img, &cerr)
@@ -143,36 +149,74 @@ func (i *Image) ReadMetadata() error {
143149
return nil
144150
}
145151

146-
// Returns an image contents.
152+
// GetBytes returns an image contents.
147153
// If its metadata has been changed, the changes are reflected here.
148154
func (i *Image) GetBytes() []byte {
155+
if i.img == nil {
156+
return nil
157+
}
158+
149159
size := C.exiv_image_get_size(i.img)
150160
ptr := C.exiv_image_get_bytes_ptr(i.img)
151161

152-
return C.GoBytes(unsafe.Pointer(ptr), C.int(size))
162+
if ptr == nil || size <= 0 {
163+
return nil
164+
}
165+
166+
result := C.GoBytes(unsafe.Pointer(ptr), C.int(size))
167+
168+
runtime.KeepAlive(i) // Prevent GC from freeing the C structure prematurely
169+
170+
return result
153171
}
154172

155173
// PixelWidth returns the width of the image in pixels
156174
func (i *Image) PixelWidth() int64 {
157-
return int64(C.exiv2_image_get_pixel_width(i.img))
175+
if i.img == nil {
176+
return 0
177+
}
178+
result := int64(C.exiv2_image_get_pixel_width(i.img))
179+
180+
runtime.KeepAlive(i)
181+
182+
return result
158183
}
159184

160185
// PixelHeight returns the height of the image in pixels
161186
func (i *Image) PixelHeight() int64 {
162-
return int64(C.exiv2_image_get_pixel_height(i.img))
187+
if i.img == nil {
188+
return 0
189+
}
190+
result := int64(C.exiv2_image_get_pixel_height(i.img))
191+
192+
runtime.KeepAlive(i)
193+
194+
return result
163195
}
164196

165197
// ICCProfile returns the ICC profile or nil if the image doesn't has one.
166198
func (i *Image) ICCProfile() []byte {
199+
if i.img == nil {
200+
return nil
201+
}
202+
167203
size := C.int(C.exiv2_image_icc_profile_size(i.img))
168204
if size <= 0 {
169205
return nil
170206
}
171-
return C.GoBytes(unsafe.Pointer(C.exiv2_image_icc_profile(i.img)), size)
207+
result := C.GoBytes(unsafe.Pointer(C.exiv2_image_icc_profile(i.img)), size)
208+
209+
runtime.KeepAlive(i)
210+
211+
return result
172212
}
173213

174-
// Sets an exif or iptc key with a given string value
214+
// SetMetadataString sets an exif or iptc key with a given string value
175215
func (i *Image) SetMetadataString(format, key, value string) error {
216+
if i.img == nil {
217+
return errors.New("image instance is not initialized: underlying C structure is nil")
218+
}
219+
176220
if format != "iptc" && format != "exif" {
177221
return errors.New("invalid metadata type: " + format)
178222
}
@@ -202,8 +246,12 @@ func (i *Image) SetMetadataString(format, key, value string) error {
202246
return nil
203247
}
204248

205-
// Sets an exif or iptc key with a given short value
249+
// SetMetadataShort sets an exif or iptc key with a given short value
206250
func (i *Image) SetMetadataShort(format, key, value string) error {
251+
if i.img == nil {
252+
return errors.New("image instance is not initialized: underlying C structure is nil")
253+
}
254+
207255
if format != "iptc" && format != "exif" {
208256
return errors.New("invalid metadata type: " + format)
209257
}
@@ -234,6 +282,10 @@ func (i *Image) SetMetadataShort(format, key, value string) error {
234282
}
235283

236284
func (i *Image) StripKey(f MetadataFormat, key string) error {
285+
if i.img == nil {
286+
return errors.New("image instance is not initialized: underlying C structure is nil")
287+
}
288+
237289
ckey := C.CString(key)
238290
defer C.free(unsafe.Pointer(ckey))
239291

testdata/pixel.jpg

-70 Bytes
Loading

testdata/pixel.webp

-36 Bytes
Loading

0 commit comments

Comments
 (0)