【问题标题】:Leetcode 506:A Problem with heap-buffer-overflow in CLeetcode 506:C 中的堆缓冲区溢出问题
【发布时间】:2021-09-20 12:37:00
【问题描述】:

问题链接:https://leetcode.com/problems/relative-ranks/;

这是我的解决方案:使用二维数组nums[2][scoreSize]nums[0][scoreSize]来记录score[ scoreSzie].nums[1][scoreSize] 记录score[scoreSzie]中每个元素的索引。然后QuickSort对于nums[2][scoreSize]。所以输出为:nums[0][scoreSize]中的元素从大到小排列,nums [1][scoreSize]记录score[scoreSize]中元素对应的索引。最后,使用ret[nums[1][i]]记录排名并返回。代码如下:

void quicksort(int left,int right,int row,int col,int nums[row][col]);
char **findRelativeRanks(int* score, int scoreSize, int* returnSize)
{
    char **ret=(char **)malloc(sizeof(char *)*scoreSize);
    *returnSize=scoreSize;
    int i;
    int nums[2][scoreSize];                               //to record score[scoreSzie] and index
    for(i=0;i<scoreSize;i++)
    {
        nums[0][i]=score[i];
    }
    for(i=0;i<scoreSize;i++)
    {
        nums[1][i]=i;
    }
    quicksort(0,scoreSize-1,2,scoreSize,nums);            //Quicksort for nums[2][scoreSize]
    for(i=0;i<scoreSize;i++)                              //record rank by ret[scoreSize]
    {
        if(i<3)
        {
            switch(i)
            {
                case 0:ret[nums[1][0]]=(char*)malloc(sizeof(char)*15);
                       strcpy(ret[nums[1][0]],"Gold Medal");
                        break;
                case 1:ret[nums[1][1]]=(char*)malloc(sizeof(char)*15);
                        strcpy(ret[nums[1][1]],"Sliver Medal");
                        break;
                case 2:ret[nums[1][2]]=(char*)malloc(sizeof(char)*15);
                        strcpy(ret[nums[1][2]],"Bronze Medal");
                        break;
                default:break;
            }
        }else
        {
            ret[nums[1][i]]=(char*)malloc(sizeof(char)*1);
            ret[nums[1][i]][0]='1'+i;
        }
    }
    return ret;
}
void quicksort(int left,int right,int row,int col,int nums[row][col])
{
    if(left<right)
    {
        int l=left,r=right;
        int pivot=nums[0][left];
        int temp=nums[1][left];
        while(l<r)
        {
            while(r>l&&nums[0][r]<=pivot) r--;
            if(r>l)
            {
                nums[1][l]=nums[1][r];
                nums[0][l++]=nums[0][r];
            }
            while(r>l&&nums[0][l]>pivot) l++;
            if(r>l)
            {
                nums[1][r]=nums[1][l];
                nums[0][r--]=nums[0][l];
            }
        }
        nums[0][l]=pivot;
        nums[1][l]=temp;
        quicksort(left,l-1,row,col,nums);
        quicksort(l+1,right,row,col,nums);
    }else
    {
        return;
    }
}

错误是

=================================================================
==42==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000000072 at pc 0x564293732f0b bp 0x7fffde673830 sp 0x7fffde673820
READ of size 1 at 0x602000000072 thread T0
    #3 0x7fbdea9b60b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
0x602000000072 is located 0 bytes to the right of 2-byte region [0x602000000070,0x602000000072)
allocated by thread T0 here:
    #0 0x7fbdeb5fbbc8 in malloc (/lib/x86_64-linux-gnu/libasan.so.5+0x10dbc8)
    #3 0x7fbdea9b60b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
Shadow bytes around the buggy address:
  0x0c047fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c047fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c047fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c047fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c047fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c047fff8000: fa fa 00 07 fa fa 00 07 fa fa 00 07 fa fa[02]fa
  0x0c047fff8010: fa fa 02 fa fa fa fd fa fa fa fd fd fa fa fa fa
  0x0c047fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==42==ABORTING

作为一个新程序员,我尽力找出问题所在,但我失败了。我真的需要帮助。非常感谢。

【问题讨论】:

  • “作为一名新程序员”,我建议您尽可能远离这些所谓的“竞争”或“在线评委”网站。它们不是学习或教学资源。恰恰相反,因为大多数示例往往是非常糟糕的代码。买书、上课,几乎所有其他东西都比学习编程和你选择的语言更好。
  • 您是否尝试过使用调试器单步执行您的代码?您需要学习如何使用工具链附带的调试器。
  • @Someprogrammerdude,@jwdonahue,非常感谢,我会听取你的建议。

标签: c algorithm


【解决方案1】:

正如 cmets 中的人所指出的,您应该尝试通过使用 gdb 或添加一些打印语句来调试程序中发生的事情。另外,如果你对 C 语言还不是很满意,也许先读点书是件好事。

我查看了这个问题,我认为您不需要为这个问题实现自己的 QuickSort 版本。您可以简单地使用 C 库的 qsort 方法,该方法经过良好测试且更可靠。

  1. 我注意到,这里的这个部分正在处理 (rank &gt; 3) 案例:
ret[nums[1][i]]=(char*)malloc(sizeof(char)*1);
ret[nums[1][i]][0]='1'+i;

您正在分配大小为 1 的字符串数组。即使我们认为排名只是一位数,这是错误的,因为即使对于一位数字符串,您也需要两个字符:一个用于原始字符串,一个用于 \0

如果你仔细阅读问题约束,你会发现数组大小可以达到 10000。所以在这里使用sprintf 可能会更好:

rankStr = malloc(6 * sizeof(char));
sprintf(rankStr, "%d", rank + 1);
  1. 我发现您在排序之前使用int nums[2][scoreSize] 存储分数和原始索引的方法有点过于复杂。我建议为这样的一对创建一个struct
typedef struct ValueToIndexPair {
    int value;
    int index;
} ValueToIndexPair;

您可以轻松使用qsort 提供自定义比较器功能来与值进行比较:

int cmpfunc (const void * a, const void * b) {
   const ValueToIndexPair* i1 = (ValueToIndexPair*) a;
   const ValueToIndexPair* i2 = (ValueToIndexPair*) b; 

   return (i2->value - i1->value );
}

char **findRelativeRanks(int* score, int scoreSize, int* returnSize) {
  // ...
  qsort(scoreToIndexList, scoreSize, sizeof(ValueToIndexPair), cmpfunc);
}

通过稍微清理您的代码版本,我能够接受此解决方案:

typedef struct ValueToIndexPair {
    int value;
    int index;
} ValueToIndexPair;

int cmpfunc (const void * a, const void * b) {
   const ValueToIndexPair* i1 = (ValueToIndexPair*) a;
   const ValueToIndexPair* i2 = (ValueToIndexPair*) b; 

   return (i2->value - i1->value );
}

char **findRelativeRanks(int* score, int scoreSize, int* returnSize) {
  char **ranks = malloc(scoreSize * sizeof(char*));
  *returnSize = scoreSize;
  ValueToIndexPair scoreToIndexList[scoreSize];  
  for (int i = 0; i < scoreSize; i++) {
      scoreToIndexList[i].value = score[i];
      scoreToIndexList[i].index = i;
  }

  qsort(scoreToIndexList, scoreSize, sizeof(ValueToIndexPair), cmpfunc);
  
  for (int i = 0; i < scoreSize; i++) {
      char *rankStr = createRankString(i);
      int currentScoreOrignalIndex = scoreToIndexList[i].index;
      ranks[currentScoreOrignalIndex] = rankStr;
  }

  return ranks;
}

char *createRankString(int rank) {
  char firstRankStr[12] = "Gold Medal";
  char secondRankStr[13] = "Silver Medal";
  char thirdRankStr[15] = "Bronze Medal";

  char *rankStr;
  if (rank == 0) {
      rankStr = malloc(12 * sizeof(char));
      strcpy(rankStr, firstRankStr);
  } else if (rank == 1) {
      rankStr = malloc(13 * sizeof(char));
      strcpy(rankStr, secondRankStr);
  } else if (rank == 2) {
      rankStr = malloc(15 * sizeof(char));
      strcpy(rankStr, thirdRankStr);
  } else {
      rankStr = malloc(6 * sizeof(char));
      sprintf(rankStr, "%d", rank + 1);
  }
  return rankStr;
}

【讨论】:

  • 我阅读了你写的所有内容。这对我很有帮助。非常感谢。祝你有美好的一天。
猜你喜欢
  • 2023-01-25
  • 2022-11-14
  • 2017-06-26
  • 1970-01-01
  • 2010-11-11
  • 2017-02-23
  • 2021-11-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多