Changeset 29936 in project


Ignore:
Timestamp:
10/17/13 23:54:46 (8 years ago)
Author:
Jim Ursetto
Message:

sql-de-lite: Protect against access to busy handler after handler object freed

Location:
release/4/sql-de-lite/trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • release/4/sql-de-lite/trunk/sql-de-lite.scm

    r26389 r29936  
    158158  (filename db-filename)
    159159  (busy-handler db-busy-handler set-db-busy-handler!)
    160   (invoked-busy-handler? db-invoked-busy-handler?)
     160  (invoked-busy-handler? db-invoked-busy-handler? set-db-invoked-busy-handler?!)
    161161  (safe-step? db-safe-step? set-db-safe-step!)  ;; global flag indicating step needs safe-lambda
    162162  (statement-cache db-statement-cache))
     
    400400  (let-location ((stmt (c-pointer "sqlite3_stmt")))
    401401    (let retry ((times 0))
    402       (reset-busy! db)
    403       (let ((rv (sqlite3_prepare_v2 (nonnull-db-ptr db)
    404                                     sql
    405                                     (string-length sql)
    406                                     (location stmt)
    407                                     #f)))
    408         (cond ((= rv status/ok)
    409                (if stmt
    410                    (let* ((nparam (sqlite3_bind_parameter_count stmt)))
    411                      (make-handle stmt
    412                                   #f ; names
    413                                   nparam
    414                                   #f 0)) ; cached? run-state
    415                    ;; Not strictly an error, but to handle it properly we must
    416                    ;; create a dummy statement and change all statement interfaces
    417                    ;; to respect it; until then, we'll make it illegal.
    418                    (database-error db rv 'prepare sql     ;; FIXME: This will show "not an error" error.
    419                                    "attempted to prepare whitespace or comment SQL")))
    420               ((= rv status/busy)
    421                (let ((bh (db-busy-handler db)))
    422                  (if (and bh
    423                           (retry-busy? db)
    424                           (bh db times))
    425                      (retry (+ times 1))
    426                      (database-error db rv 'prepare sql))))
    427               (else
    428                (database-error db rv 'prepare sql)))))))
     402      (let ((dbptr (nonnull-db-ptr db)))
     403        (reset-busy! db)
     404        (let ((rv (sqlite3_prepare_v2 dbptr
     405                                      sql
     406                                      (string-length sql)
     407                                      (location stmt)
     408                                      #f)))
     409          (cond ((= rv status/ok)
     410                 (if stmt
     411                     (let* ((nparam (sqlite3_bind_parameter_count stmt)))
     412                       (make-handle stmt
     413                                    #f  ; names
     414                                    nparam
     415                                    #f 0)) ; cached? run-state
     416                     ;; Not strictly an error, but to handle it properly we must
     417                     ;; create a dummy statement and change all statement interfaces
     418                     ;; to respect it; until then, we'll make it illegal.
     419                     (database-error db rv 'prepare sql ;; FIXME: This will show "not an error" error.
     420                                     "attempted to prepare whitespace or comment SQL")))
     421                ((= rv status/busy)
     422                 (let ((bh (db-busy-handler db)))
     423                   (if (and bh
     424                            (retry-busy? db)
     425                            (bh db times))
     426                       (retry (+ times 1))
     427                       (database-error db rv 'prepare sql))))
     428                (else
     429                 (database-error db rv 'prepare sql))))))))
    429430
    430431;; Looks up a prepared statement in the statement cache.  If not
     
    488489(define (step stmt)
    489490  (let ((db (statement-db stmt))
     491        (sptr (nonnull-statement-ptr stmt))
    490492        (step/safe (if (statement-safe-step? stmt)
    491493                       sqlite3_step_safe
     
    493495    (let retry ((times 0))
    494496      (reset-busy! db)
    495       (let ((rv (step/safe (nonnull-statement-ptr stmt))))
     497      (let ((rv (step/safe sptr)))
    496498        (cond ((= rv status/row)
    497499               (set-statement-running! stmt)
     
    825827           (set-db-ptr! db #f)
    826828           (object-release (db-invoked-busy-handler? db))
     829           (set-db-invoked-busy-handler?! db 'database-closed)
    827830           #t)
    828831          (else #f))))
     
    975978  (vector-set! (db-invoked-busy-handler? db) 0 #f))
    976979(define (set-busy-handler! db proc)
    977   (set-db-busy-handler! db proc)
    978   (if proc
    979       (sqlite3_busy_handler (nonnull-db-ptr db)
    980                             (foreign-value "busy_notification_handler"
    981                                            c-pointer)
    982                             (object->pointer
    983                              (db-invoked-busy-handler? db)))
    984       (sqlite3_busy_handler (nonnull-db-ptr db) #f #f))
    985   (void))
     980  (let ((dbptr (nonnull-db-ptr db)))
     981    (set-db-busy-handler! db proc)
     982    (if proc
     983        (sqlite3_busy_handler dbptr
     984                              (foreign-value "busy_notification_handler"
     985                                             c-pointer)
     986                              (object->pointer
     987                               (db-invoked-busy-handler? db)))
     988        (sqlite3_busy_handler dbptr #f #f))
     989    (void)))
    986990(define (thread-sleep!/ms ms)
    987991  (thread-sleep! (/ ms 1000)))
  • release/4/sql-de-lite/trunk/tests/run.scm

    r26389 r29936  
    262262          (let ((rv (list (fetch s1)
    263263                          (fetch s2))))
    264             (close-database db)
     264            (close-database db)         ;; warning: database doesn't get closed here anymore
    265265            (finalize s1)
    266266            (finalize s2)
    267267            rv))))
     268
     269(test-error "step after db closed raises exception"
     270            (let ((db (open-database ":memory:")))
     271              (let ((s1 (prepare-transient db "select 1;")))
     272                (and (eqv? 'row (step s1))
     273                     (eqv? 'done (step s1))
     274                     (finalize s1)
     275                     (close-database db)      ;; returns #f if statements still open
     276                     (step s1)))))
    268277
    269278;; This is not "good" behavior, but expected.
Note: See TracChangeset for help on using the changeset viewer.