Hi Evan, And thanks for getting back to me. I found another problem related to memory corruption and I've been digging around. I have patches for that too, but I don't know if they suffice. They sort of break existing conventions of everything in libgit2 being foreigners and c-pointers.
I'm attaching my patches here in case you have time to look into this. The attachments here include the fixes in the previous mail too, so please ignore that one. >From what I gather, there is no way to allocate memory and return a pointer to it, safely, in CHICKEN. Won't the garbage collector potentially overwrite whatever region was allocated since it has no way of knowing it? That's why I made (make-oid) and friends return chicken blobs instead. Let me know if there's a better way! K. On Sun, Jun 13, 2021 at 11:19 PM Evan Hanson <ev...@foldling.org> wrote: > Hi Kristian, > > On 2021-06-12 15:36, Kristian Lein-Mathisen wrote: > > I think I may have come across a bug in the git egg. > > You're right! THanks for pointing this out, I guess you must be the > first person to use that `frombuffer` procedure. > > Everything you've said looks correct to me, I'll try to publish a fix > for this soon. > > Evan >
From 602f415a5fe769b786efb2abd03a480661b6e0c4 Mon Sep 17 00:00:00 2001 From: Kristian Lein-Mathisen <kristianl...@gmail.com> Date: Sun, 13 Jun 2021 22:56:18 +0200 Subject: [PATCH 1/3] Fix mismatched blob-create-frombuffer signature Before this patch, the new test case would produce an error like this: Error: bad argument count - received 2 but expected 3: #<procedure> --- git.scm | 2 +- libgit2.scm | 2 +- tests/run.scm | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/git.scm b/git.scm index b33cd45..c8762d1 100644 --- a/git.scm +++ b/git.scm @@ -785,7 +785,7 @@ (git-blob-lookup repo* (cond ((chicken-blob? source) - (git-blob-create-frombuffer repo* source)) + (git-blob-create-frombuffer repo* source (number-of-bytes source))) ((string? source) (if (regular-file? source) (git-blob-create-fromdisk repo* source) diff --git a/libgit2.scm b/libgit2.scm index a1e095c..83334c3 100644 --- a/libgit2.scm +++ b/libgit2.scm @@ -295,7 +295,7 @@ (define blob-lookup-prefix (foreign-lambda/allocate blob* git_blob_lookup_prefix repository oid unsigned-int)) (define blob-create-fromdisk (foreign-lambda/allocate oid git_blob_create_fromdisk repository nonnull-c-string)) (define blob-create-fromworkdir (foreign-lambda/allocate oid git_blob_create_fromworkdir repository nonnull-c-string)) -(define blob-create-frombuffer (foreign-lambda/allocate oid git_blob_create_frombuffer repository nonnull-c-string unsigned-int)) +(define blob-create-frombuffer (foreign-lambda/allocate oid git_blob_create_frombuffer repository nonnull-scheme-pointer size_t)) (define blob-id (foreign-lambda/copy oid git_blob_id blob*)) (define blob-free (foreign-lambda void git_blob_free blob*)) (define blob-rawcontent (foreign-lambda c-pointer git_blob_rawcontent blob*)) diff --git a/tests/run.scm b/tests/run.scm index b73e97f..7ede8da 100644 --- a/tests/run.scm +++ b/tests/run.scm @@ -393,6 +393,7 @@ (test-group "blob" (test-error "blob with nonexistent sha" (blob repo (make-string 40 #\a))) + (test "create-blob from memory source" 4 (blob-length (create-blob repo #${41424344}))) (let ((t (commit-tree commit))) (with-current-directory repo-path (lambda () -- 2.31.1
From 621f8a0178d2f66470ca978716b4a62f33f2dd90 Mon Sep 17 00:00:00 2001 From: Kristian Lein-Mathisen <kristianl...@gmail.com> Date: Mon, 14 Jun 2021 01:17:20 +0200 Subject: [PATCH 3/3] Fix for memory corruption There seems to be a problem with foreign-primitive related allocations. If the garbage collector runs right after (make-oid) and friends, the returned pointer is no longer valid. ~/p/chicken-git (master)> cat stress.scm (import git) (define repo (create-repository "tmp" #t)) (let loop () (create-blob repo #${4142}) (loop)) ~/p/chicken-git (master)> valgrind csi -s stress.scm ... ==56676== Invalid read of size 1 ==56676== at 0x5479264: git_oid_is_zero (in /usr/lib/libgit2.so.1.1.0) ==56676== by 0x5474509: git_odb_read (in /usr/lib/libgit2.so.1.1.0) ==56676== by 0x547154A: git_object_lookup_prefix (in /usr/lib/libgit2.so.1.1.0) ==56676== by 0x53DF95E: f_12197 (in /usr/lib/chicken/11/git.libgit2.so) ==56676== by 0x48F4FF0: ??? (in /usr/lib/libchicken.so.11) ==56676== by 0x491900A: ??? (in /usr/lib/libchicken.so.11) ==56676== by 0x49267B4: ??? (in /usr/lib/libchicken.so.11) ==56676== by 0x4B012B7: CHICKEN_run (in /usr/lib/libchicken.so.11) ==56676== by 0x4B02813: CHICKEN_main (in /usr/lib/libchicken.so.11) ==56676== by 0x4D7BB24: (below main) (in /usr/lib/libc-2.33.so) ==56676== Address 0x1ffef00514 is on thread 1's stack ==56676== 1046996 bytes below stack pointer ==56676== ==56676== Invalid read of size 1 ==56676== at 0x4843C77: bcmp (vg_replace_strmem.c:1111) ==56676== by 0x5472D2F: ??? (in /usr/lib/libgit2.so.1.1.0) ==56676== by 0x547456F: git_odb_read (in /usr/lib/libgit2.so.1.1.0) ==56676== by 0x547154A: git_object_lookup_prefix (in /usr/lib/libgit2.so.1.1.0) ==56676== by 0x53DF95E: f_12197 (in /usr/lib/chicken/11/git.libgit2.so) ==56676== by 0x48F4FF0: ??? (in /usr/lib/libchicken.so.11) This patch tries to address that. --- libgit2.scm | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/libgit2.scm b/libgit2.scm index f4e1518..06d3abe 100644 --- a/libgit2.scm +++ b/libgit2.scm @@ -17,6 +17,7 @@ (strict-types)) (import (scheme) + (only srfi-4 make-u8vector u8vector->blob/shared) (chicken base) (chicken bitwise) (chicken blob) @@ -196,8 +197,13 @@ (c-string email signature-email) ((struct time) when signature-time)) -(define-foreign-record-type (oid git_oid) - (unsigned-char (id (foreign-value GIT_OID_RAWSZ int)) oid-id)) +;; allow using both blobs and pointer as foreign oid argument types. +;; this lets us allocate space for an oid with make-blob. +;; unfortunately, it breaks the foreigners conventions of always using +;; c-pointers, so it can make things more confusing. revspec and buf +;; also follow this (mis)convention. +(define-foreign-type oid (c-pointer (struct "git_oid")) + (lambda (b) (if (blob? b) (location b) b))) (define-foreign-record-type (index-time git_index_time) (time-t seconds index-time-seconds) @@ -264,7 +270,8 @@ (define-foreign-type push (c-pointer "git_push")) (define-foreign-type note (c-pointer "git_note")) (define-foreign-type reference (c-pointer "git_reference")) -(define-foreign-type refspec (c-pointer "git_refspec")) +(define-foreign-type refspec (c-pointer "git_refspec") + (lambda (x) (if (blob? x) (location x) x))) ;; see make-revspec (define-foreign-type remote (c-pointer "git_remote")) (define-foreign-type remote-callbacks (c-pointer "git_remote_callbacks")) (define-foreign-type remote-head (c-pointer "git_remote_head")) @@ -280,12 +287,15 @@ ;;; buffer.h ;;; -(define-foreign-record-type (buf git_buf) - (c-string ptr buf-pointer buf-pointer-set!) - (size_t asize buf-asize buf-asize-set!) - (size_t size buf-size buf-size-set!)) +(define-foreign-type buf (c-pointer "git_buf") + (lambda (x) (if (blob? x) (location x) x))) -(define make-buf (foreign-primitive buf () "git_buf buf = {0}; C_return(&buf);")) +;; the buf-pointer that would have been generated by foreigners +;; doesn't respect our foreign buf type above as it's used in syntax. +(define buf-pointer (foreign-lambda* c-string ((buf buf)) "C_return(buf->ptr);")) + +;; note that buf must be 0-initialized (unlike oid and revspec) +(define (make-buf) (u8vector->blob/shared (make-u8vector (foreign-value "sizeof(git_buf)" int) 0))) (define buf-free (foreign-lambda void git_buf_free buf)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -891,7 +901,7 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; oid.h -(define make-oid (foreign-primitive oid () "git_oid oid; C_return(&oid);")) +(define (make-oid) (make-blob (foreign-value "sizeof(git_oid)" int))) (define oid-fromstr (foreign-lambda/allocate oid git_oid_fromstr nonnull-c-string)) (define oid-shorten-add (foreign-lambda/retval git_oid_shorten_add oid-shorten nonnull-c-string)) (define oid-cmp (foreign-lambda int git_oid_cmp oid oid)) @@ -1151,12 +1161,15 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; revparse.h -(define-foreign-record-type (revspec git_revspec) - (object from revspec-from) - (object to revspec-to) - (unsigned-int flags revspec-flags)) +;; as with oid and buf, we can't use foreigners do generate getters +;; for the revspec struct. +(define-foreign-type revspec (c-pointer "git_revspec") + (lambda (b) (if (blob? b) (location b) b))) + +(define revspec-from (foreign-lambda* object ((revspec r)) "C_return(r->from);")) +(define revspec-to (foreign-lambda* object ((revspec r)) "C_return(r->to);")) -(define make-revspec (foreign-primitive revspec () "git_revspec rev; C_return(&rev);")) +(define (make-revspec) (make-blob (foreign-value "sizeof(git_revspec)" int))) (define revparse-single (foreign-lambda/allocate object git_revparse_single repository nonnull-c-string)) (define revparse (foreign-lambda/allocate revspec git_revparse repository nonnull-c-string)) -- 2.31.1
From 9f11e4929b357866bc6fba8972888071686a2c97 Mon Sep 17 00:00:00 2001 From: Kristian Lein-Mathisen <kristianl...@gmail.com> Date: Sun, 13 Jun 2021 22:58:08 +0200 Subject: [PATCH 2/3] Fix blob function reference typo I can't figure out where these are used, but this is certainly better. --- libgit2.scm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libgit2.scm b/libgit2.scm index 83334c3..f4e1518 100644 --- a/libgit2.scm +++ b/libgit2.scm @@ -303,9 +303,9 @@ (define blob-is-binary (foreign-lambda bool git_blob_is_binary blob*)) (define blob*-lookup blob-lookup) -(define blob*-create-frombuffer blob-create-fromdisk) -(define blob*-create-fromdisk blob-create-fromworkdir) -(define blob*-create-fromworkdir blob-create-frombuffer) +(define blob*-create-frombuffer blob-create-frombuffer) +(define blob*-create-fromdisk blob-create-fromdisk) +(define blob*-create-fromworkdir blob-create-fromworkdir) (define blob*-free blob-free) (define blob*-id blob-id) (define blob*-is-binary blob-is-binary) -- 2.31.1