aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2016-08-02 21:04:28 -0400
committerPaul Eggert2016-08-02 21:06:02 -0400
commitd98f7834266beed9b1c7b561168570938ec2c6bf (patch)
treee07a19d3702ef4de56c754c7387c3ceeb6a2a790 /src
parent07e9281f7a17f47493a5f611f6c6ea40fa286614 (diff)
downloademacs-d98f7834266beed9b1c7b561168570938ec2c6bf.tar.gz
emacs-d98f7834266beed9b1c7b561168570938ec2c6bf.zip
Fix (mapcar F S) crash when F alters S’s length
* src/fns.c (mapcar1): Return number of elements computed, which can be less than LENI if the function alters the list. All callers changed. (Bug#24118)
Diffstat (limited to 'src')
-rw-r--r--src/fns.c77
1 files changed, 30 insertions, 47 deletions
diff --git a/src/fns.c b/src/fns.c
index c318608e4ce..3895ada325d 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -2517,11 +2517,13 @@ usage: (nconc &rest LISTS) */)
2517} 2517}
2518 2518
2519/* This is the guts of all mapping functions. 2519/* This is the guts of all mapping functions.
2520 Apply FN to each element of SEQ, one by one, 2520 Apply FN to each element of SEQ, one by one, storing the results
2521 storing the results into elements of VALS, a C vector of Lisp_Objects. 2521 into elements of VALS, a C vector of Lisp_Objects. LENI is the
2522 LENI is the length of VALS, which should also be the length of SEQ. */ 2522 length of VALS, which should also be the length of SEQ. Return the
2523 number of results; although this is normally LENI, it can be less
2524 if SEQ is made shorter as a side effect of FN. */
2523 2525
2524static void 2526static EMACS_INT
2525mapcar1 (EMACS_INT leni, Lisp_Object *vals, Lisp_Object fn, Lisp_Object seq) 2527mapcar1 (EMACS_INT leni, Lisp_Object *vals, Lisp_Object fn, Lisp_Object seq)
2526{ 2528{
2527 Lisp_Object tail, dummy; 2529 Lisp_Object tail, dummy;
@@ -2564,14 +2566,18 @@ mapcar1 (EMACS_INT leni, Lisp_Object *vals, Lisp_Object fn, Lisp_Object seq)
2564 else /* Must be a list, since Flength did not get an error */ 2566 else /* Must be a list, since Flength did not get an error */
2565 { 2567 {
2566 tail = seq; 2568 tail = seq;
2567 for (i = 0; i < leni && CONSP (tail); i++) 2569 for (i = 0; i < leni; i++)
2568 { 2570 {
2571 if (! CONSP (tail))
2572 return i;
2569 dummy = call1 (fn, XCAR (tail)); 2573 dummy = call1 (fn, XCAR (tail));
2570 if (vals) 2574 if (vals)
2571 vals[i] = dummy; 2575 vals[i] = dummy;
2572 tail = XCDR (tail); 2576 tail = XCDR (tail);
2573 } 2577 }
2574 } 2578 }
2579
2580 return leni;
2575} 2581}
2576 2582
2577DEFUN ("mapconcat", Fmapconcat, Smapconcat, 3, 3, 0, 2583DEFUN ("mapconcat", Fmapconcat, Smapconcat, 3, 3, 0,
@@ -2581,34 +2587,26 @@ SEPARATOR results in spaces between the values returned by FUNCTION.
2581SEQUENCE may be a list, a vector, a bool-vector, or a string. */) 2587SEQUENCE may be a list, a vector, a bool-vector, or a string. */)
2582 (Lisp_Object function, Lisp_Object sequence, Lisp_Object separator) 2588 (Lisp_Object function, Lisp_Object sequence, Lisp_Object separator)
2583{ 2589{
2584 Lisp_Object len;
2585 EMACS_INT leni;
2586 EMACS_INT nargs;
2587 ptrdiff_t i;
2588 Lisp_Object *args;
2589 Lisp_Object ret;
2590 USE_SAFE_ALLOCA; 2590 USE_SAFE_ALLOCA;
2591 2591 EMACS_INT leni = XFASTINT (Flength (sequence));
2592 len = Flength (sequence);
2593 if (CHAR_TABLE_P (sequence)) 2592 if (CHAR_TABLE_P (sequence))
2594 wrong_type_argument (Qlistp, sequence); 2593 wrong_type_argument (Qlistp, sequence);
2595 leni = XINT (len); 2594 EMACS_INT args_alloc = 2 * leni - 1;
2596 nargs = leni + leni - 1; 2595 if (args_alloc < 0)
2597 if (nargs < 0) return empty_unibyte_string; 2596 return empty_unibyte_string;
2598 2597 Lisp_Object *args;
2599 SAFE_ALLOCA_LISP (args, nargs); 2598 SAFE_ALLOCA_LISP (args, args_alloc);
2600 2599 ptrdiff_t nmapped = mapcar1 (leni, args, function, sequence);
2601 mapcar1 (leni, args, function, sequence); 2600 ptrdiff_t nargs = 2 * nmapped - 1;
2602 2601
2603 for (i = leni - 1; i > 0; i--) 2602 for (ptrdiff_t i = nmapped - 1; i > 0; i--)
2604 args[i + i] = args[i]; 2603 args[i + i] = args[i];
2605 2604
2606 for (i = 1; i < nargs; i += 2) 2605 for (ptrdiff_t i = 1; i < nargs; i += 2)
2607 args[i] = separator; 2606 args[i] = separator;
2608 2607
2609 ret = Fconcat (nargs, args); 2608 Lisp_Object ret = Fconcat (nargs, args);
2610 SAFE_FREE (); 2609 SAFE_FREE ();
2611
2612 return ret; 2610 return ret;
2613} 2611}
2614 2612
@@ -2618,24 +2616,15 @@ The result is a list just as long as SEQUENCE.
2618SEQUENCE may be a list, a vector, a bool-vector, or a string. */) 2616SEQUENCE may be a list, a vector, a bool-vector, or a string. */)
2619 (Lisp_Object function, Lisp_Object sequence) 2617 (Lisp_Object function, Lisp_Object sequence)
2620{ 2618{
2621 register Lisp_Object len;
2622 register EMACS_INT leni;
2623 register Lisp_Object *args;
2624 Lisp_Object ret;
2625 USE_SAFE_ALLOCA; 2619 USE_SAFE_ALLOCA;
2626 2620 EMACS_INT leni = XFASTINT (Flength (sequence));
2627 len = Flength (sequence);
2628 if (CHAR_TABLE_P (sequence)) 2621 if (CHAR_TABLE_P (sequence))
2629 wrong_type_argument (Qlistp, sequence); 2622 wrong_type_argument (Qlistp, sequence);
2630 leni = XFASTINT (len); 2623 Lisp_Object *args;
2631
2632 SAFE_ALLOCA_LISP (args, leni); 2624 SAFE_ALLOCA_LISP (args, leni);
2633 2625 ptrdiff_t nmapped = mapcar1 (leni, args, function, sequence);
2634 mapcar1 (leni, args, function, sequence); 2626 Lisp_Object ret = Flist (nmapped, args);
2635
2636 ret = Flist (leni, args);
2637 SAFE_FREE (); 2627 SAFE_FREE ();
2638
2639 return ret; 2628 return ret;
2640} 2629}
2641 2630
@@ -2661,21 +2650,15 @@ the results by altering them (using `nconc').
2661SEQUENCE may be a list, a vector, a bool-vector, or a string. */) 2650SEQUENCE may be a list, a vector, a bool-vector, or a string. */)
2662 (Lisp_Object function, Lisp_Object sequence) 2651 (Lisp_Object function, Lisp_Object sequence)
2663{ 2652{
2664 register EMACS_INT leni;
2665 register Lisp_Object *args;
2666 Lisp_Object ret;
2667 USE_SAFE_ALLOCA; 2653 USE_SAFE_ALLOCA;
2668 2654 EMACS_INT leni = XFASTINT (Flength (sequence));
2669 if (CHAR_TABLE_P (sequence)) 2655 if (CHAR_TABLE_P (sequence))
2670 wrong_type_argument (Qlistp, sequence); 2656 wrong_type_argument (Qlistp, sequence);
2671 2657 Lisp_Object *args;
2672 leni = XFASTINT (Flength (sequence));
2673 SAFE_ALLOCA_LISP (args, leni); 2658 SAFE_ALLOCA_LISP (args, leni);
2674 mapcar1 (leni, args, function, sequence); 2659 ptrdiff_t nmapped = mapcar1 (leni, args, function, sequence);
2675 ret = Fnconc (leni, args); 2660 Lisp_Object ret = Fnconc (nmapped, args);
2676
2677 SAFE_FREE (); 2661 SAFE_FREE ();
2678
2679 return ret; 2662 return ret;
2680} 2663}
2681 2664