gcc-10.0.1 নির্দিষ্ট সেগফল্ট


23

আমার সি সংকলিত কোড সহ একটি আর প্যাকেজ রয়েছে যা বেশ কিছু সময়ের জন্য তুলনামূলকভাবে স্থিতিশীল ছিল এবং প্রায়শই বিভিন্ন ধরণের প্ল্যাটফর্ম এবং সংকলক (উইন্ডোজ / অক্স / ডেবিয়ান / ফেডোরা জিসিসি / ক্ল্যাং) এর বিপরীতে পরীক্ষা করা হয়।

প্যাকেজটি আবার পরীক্ষা করতে আরও একটি নতুন প্ল্যাটফর্ম যুক্ত হয়েছিল:

Logs from checks with gcc trunk aka 10.0.1 compiled from source
on Fedora 30. (For some archived packages, 10.0.0.)

x86_64 Fedora 30 Linux

FFLAGS="-g -O2 -mtune=native -Wall -fallow-argument-mismatch"
CFLAGS="-g -O2 -Wall -pedantic -mtune=native -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong -fstack-clash-protection -fcf-protection"
CXXFLAGS="-g -O2 -Wall -pedantic -mtune=native -Wno-ignored-attributes -Wno-deprecated-declarations -Wno-parentheses -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong -fstack-clash-protection -fcf-protection"

কোন বিন্দুতে সংকলিত কোডটি এই লাইনগুলি দিয়ে তাত্ক্ষণিকভাবে সেগফল্টিং শুরু করেছে:

 *** caught segfault ***
address 0x1d00000001, cause 'memory not mapped'

আমি অপ্টিমাইজেশন স্তর সহ rocker/r-baseডকার পাত্রে ব্যবহার করে ধারাবাহিকভাবে সেগফল্ট পুনরুত্পাদন করতে সক্ষম হয়েছি । কম অপ্টিমাইজেশান চালানো সমস্যা থেকে মুক্তি পায়। ওয়েলগ্র্রাইন্ড (-O0 এবং -O2 উভয়), ইউবিএসএএন (জিসিসি / কলং) সহ অন্য কোনও সেট আপ চালানো মোটেই কোনও সমস্যা দেখায় না। আমি যুক্তিসঙ্গতভাবে নিশ্চিত যে এটির নীচে চলেছে , তবে ডেটা নেই।gcc-10.0.1-O2gcc-10.0.0

আমি gcc-10.0.1 -O2সংস্করণটি চালিয়েছি gdbএবং এমন কিছু লক্ষ্য করেছি যা আমার কাছে অদ্ভুত বলে মনে হচ্ছে:

জিডিবি বনাম কোড

হাইলাইট করা বিভাগে পা রাখার সময় এটি অ্যারের দ্বিতীয় উপাদানগুলির সূচনাটি এড়িয়ে যায় বলে মনে হয় ( আর-এ নিয়ন্ত্রণ ফিরে আসার সময় স্ব আবর্জনা সংগ্রহ R_allocকরে mallocএমন চারপাশে একটি মোড়ক ; আর-এ ফিরে যাওয়ার আগে সেগফল্ট ঘটে)) পরে, আন-ইনিশিয়েলাইজড উপাদানটি (gcc.10.0.1 -O2 সংস্করণে) অ্যাক্সেস করা হলে প্রোগ্রামটি ক্র্যাশ হয়।

আমি কোডটিতে স্পষ্টতই প্রশ্নটির উপাদানটিকে প্রাথমিকভাবে প্রাথমিকভাবে শুরু করে এটিকে সংশোধন করেছিলাম যা শেষ পর্যন্ত উপাদানটির ব্যবহারের দিকে পরিচালিত করে, তবে এটি সত্যিই একটি খালি স্ট্রিংয়ে সূচনা করা উচিত ছিল, বা কমপক্ষে এটিই আমি ধরে নিয়েছি।

আমি কি স্পষ্ট কিছু মিস করছি বা বোকা কিছু করছি? উভয় যুক্তিসঙ্গতভাবে সম্ভাবনা C দ্বারা আমার দ্বিতীয় ভাষা হয় পর্যন্ত । এটি কেবল আশ্চর্যজনক যে এটি এখনই ক্রপ হয়েছে এবং সংকলকটি কী করার চেষ্টা করছে তা আমি বুঝতে পারি না।


আপডেট : নির্দেশাবলী এই পুনর্গঠন করা, যদিও এই কেবল তাই যতদিন পুনর্গঠন করা হবে debian:testingDocker কন্টেনার রয়েছে gcc-10gcc-10.0.1। এছাড়াও, আপনি যদি আমাকে বিশ্বাস না করেন তবে কেবল এই আদেশগুলি চালাবেন না

দুঃখিত, এটি একটি সর্বনিম্ন পুনরুত্পাদনযোগ্য উদাহরণ নয়।

docker pull rocker/r-base
docker run --rm -ti --security-opt seccomp=unconfined \
  rocker/r-base /bin/bash
apt-get update
apt-get install gcc-10 gdb
gcc-10 --version  # confirm 10.0.1
# gcc-10 (Debian 10-20200222-1) 10.0.1 20200222 (experimental) 
# [master revision 01af7e0a0c2:487fe13f218:e99b18cf7101f205bfdd9f0f29ed51caaec52779]

mkdir ~/.R
touch ~/.R/Makevars
echo "CC = gcc-10
CFLAGS = -g -O2 -Wall -pedantic -mtune=native -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong -fstack-clash-protection -fcf-protection
" >> ~/.R/Makevars

R -d gdb --vanilla

তারপরে আর কনসোলে, প্রোগ্রামটি চালানোর জন্য টাইপ runকরার পরে gdb:

f.dl <- tempfile()
f.uz <- tempfile()

github.url <- 'https://github.com/brodieG/vetr/archive/v0.2.8.zip'

download.file(github.url, f.dl)
unzip(f.dl, exdir=f.uz)
install.packages(
  file.path(f.uz, 'vetr-0.2.8'), repos=NULL,
  INSTALL_opts="--install-tests", type='source'
)
# minimal set of commands to segfault
library(vetr)
alike(pairlist(a=1, b="character"), pairlist(a=1, b=letters))
alike(pairlist(1, "character"), pairlist(1, letters))
alike(NULL, 1:3)                  # not a wild card at top level
alike(list(NULL), list(1:3))      # but yes when nested
alike(list(NULL, NULL), list(list(list(1, 2, 3)), 1:25))
alike(list(NULL), list(1, 2))
alike(list(), list(1, 2))
alike(matrix(integer(), ncol=7), matrix(1:21, nrow=3))
alike(matrix(character(), nrow=3), matrix(1:21, nrow=3))
alike(
  matrix(integer(), ncol=3, dimnames=list(NULL, c("R", "G", "B"))),
  matrix(1:21, ncol=3, dimnames=list(NULL, c("R", "G", "B")))
)

# Adding tests from docs

mx.tpl <- matrix(
  integer(), ncol=3, dimnames=list(row.id=NULL, c("R", "G", "B"))
)
mx.cur <- matrix(
  sample(0:255, 12), ncol=3, dimnames=list(row.id=1:4, rgb=c("R", "G", "B"))
)
mx.cur2 <-
  matrix(sample(0:255, 12), ncol=3, dimnames=list(1:4, c("R", "G", "B")))

alike(mx.tpl, mx.cur2)

জিডিবিতে পরিদর্শন করা খুব দ্রুত দেখায় (যদি আমি সঠিকভাবে বুঝতে পারি) তবে CSR_strmlen_xএটি স্ট্রিংটি অ্যাক্সেস করার চেষ্টা করছে যা শুরু হয়নি that

আপডেট 2 : এটি একটি অত্যন্ত পুনরাবৃত্ত ফাংশন, এবং তারপরে স্ট্রিং ইনিশিয়ালাইজেশন বিটটিকে অনেকগুলি, বহুবার ডাকা হয়। এটি বেশিরভাগ খ / সি আমি অলস হয়ে পড়েছিলাম, আমাদের কেবল একবারে স্ট্রিংগুলি শুরু করার প্রয়োজন হয়েছিল যখন আমরা বাস্তবে আমরা পুনরাবৃত্তিতে রিপোর্ট করতে চাই এমন কিছু মুখের মুখোমুখি হই, তবে প্রতিবারই যখন কোনও কিছুর মুখোমুখি হওয়া সম্ভব হয় তখন এটি আরম্ভ করা সহজ ছিল। আমি এটি উল্লেখ করছি কারণ আপনি পরবর্তীটি যা দেখবেন তা একাধিক সূচনা দেখায় তবে এর মধ্যে কেবলমাত্র একটি (সম্ভবত ঠিকানাটি <0x1400000001> ব্যবহার করা হচ্ছে) ব্যবহার করা হচ্ছে।

আমি গ্যারান্টি দিতে পারি না যে আমি যে জিনিসগুলি এখানে দেখছি সেগুলি সেগফোল্টের কারণে যে উপাদানটির সাথে সরাসরি সম্পর্কিত (যদিও এটি একই অবৈধ ঠিকানার প্রবেশাধিকার) তবে @ ন্যাট-লেদার্ডেজ জিজ্ঞাসা করে এটি দেখায় যে অ্যারে উপাদানটি নেই রিটার্নের ঠিক আগে বা কলিং ফাংশনে ফিরে আসার ঠিক পরে শুরু হয়েছিল। কলিং ফাংশনটি এর মধ্যে 8 টি আরম্ভ করছে এবং নকল আবর্জনা বা অ্যাক্সেস অ্যাক্সেসযোগ্য স্মৃতিতে ভরাট করে আমি সেগুলি সমস্ত দেখাই Note

এখানে চিত্র বর্ণনা লিখুন

আপডেট 3 , প্রশ্নে কার্য বিচ্ছিন্নকরণ:

Breakpoint 1, ALIKEC_res_strings_init () at alike.c:75
75    return res;
(gdb) p res.current[0]
$1 = 0x7ffff46a0aa5 "%s%s%s%s"
(gdb) p res.current[1]
$2 = 0x1400000001 <error: Cannot access memory at address 0x1400000001>
(gdb) disas /m ALIKEC_res_strings_init
Dump of assembler code for function ALIKEC_res_strings_init:
53  struct ALIKEC_res_strings ALIKEC_res_strings_init() {
   0x00007ffff4687fc0 <+0>: endbr64 

54    struct ALIKEC_res_strings res;

55  
56    res.target = (const char **) R_alloc(5, sizeof(const char *));
   0x00007ffff4687fc4 <+4>: push   %r12
   0x00007ffff4687fc6 <+6>: mov    $0x8,%esi
   0x00007ffff4687fcb <+11>:    mov    %rdi,%r12
   0x00007ffff4687fce <+14>:    push   %rbx
   0x00007ffff4687fcf <+15>:    mov    $0x5,%edi
   0x00007ffff4687fd4 <+20>:    sub    $0x8,%rsp
   0x00007ffff4687fd8 <+24>:    callq  0x7ffff4687180 <R_alloc@plt>
   0x00007ffff4687fdd <+29>:    mov    $0x8,%esi
   0x00007ffff4687fe2 <+34>:    mov    $0x5,%edi
   0x00007ffff4687fe7 <+39>:    mov    %rax,%rbx

57    res.current = (const char **) R_alloc(5, sizeof(const char *));
   0x00007ffff4687fea <+42>:    callq  0x7ffff4687180 <R_alloc@plt>

58  
59    res.target[0] = "%s%s%s%s";
   0x00007ffff4687fef <+47>:    lea    0x1764a(%rip),%rdx        # 0x7ffff469f640
   0x00007ffff4687ff6 <+54>:    lea    0x18aa8(%rip),%rcx        # 0x7ffff46a0aa5
   0x00007ffff4687ffd <+61>:    mov    %rcx,(%rbx)

60    res.target[1] = "";

61    res.target[2] = "";
   0x00007ffff4688000 <+64>:    mov    %rdx,0x10(%rbx)

62    res.target[3] = "";
   0x00007ffff4688004 <+68>:    mov    %rdx,0x18(%rbx)

63    res.target[4] = "";
   0x00007ffff4688008 <+72>:    mov    %rdx,0x20(%rbx)

64  
65    res.tar_pre = "be";

66  
67    res.current[0] = "%s%s%s%s";
   0x00007ffff468800c <+76>:    mov    %rax,0x8(%r12)
   0x00007ffff4688011 <+81>:    mov    %rcx,(%rax)

68    res.current[1] = "";

69    res.current[2] = "";
   0x00007ffff4688014 <+84>:    mov    %rdx,0x10(%rax)

70    res.current[3] = "";
   0x00007ffff4688018 <+88>:    mov    %rdx,0x18(%rax)

71    res.current[4] = "";
   0x00007ffff468801c <+92>:    mov    %rdx,0x20(%rax)

72  
73    res.cur_pre = "is";

74  
75    return res;
=> 0x00007ffff4688020 <+96>:    lea    0x14fe0(%rip),%rax        # 0x7ffff469d007
   0x00007ffff4688027 <+103>:   mov    %rax,0x10(%r12)
   0x00007ffff468802c <+108>:   lea    0x14fcd(%rip),%rax        # 0x7ffff469d000
   0x00007ffff4688033 <+115>:   mov    %rbx,(%r12)
   0x00007ffff4688037 <+119>:   mov    %rax,0x18(%r12)
   0x00007ffff468803c <+124>:   add    $0x8,%rsp
   0x00007ffff4688040 <+128>:   pop    %rbx
   0x00007ffff4688041 <+129>:   mov    %r12,%rax
   0x00007ffff4688044 <+132>:   pop    %r12
   0x00007ffff4688046 <+134>:   retq   
   0x00007ffff4688047:  nopw   0x0(%rax,%rax,1)

End of assembler dump.

আপডেট 4 :

সুতরাং, এখানে স্ট্যান্ডার্ডটির মাধ্যমে পার্স করার চেষ্টা করা হচ্ছে এর অংশগুলি যা প্রাসঙ্গিক বলে মনে হচ্ছে ( সি 11 খসড়া ):

.3.৩.২.৩ পার7 রূপান্তর> অন্যান্য অপারেন্ডস> পয়েন্টার

কোনও অবজেক্ট টাইপের একটি পয়েন্টারকে পয়েন্টারটিতে আলাদা আলাদা অবজেক্ট টাইপের রূপান্তর করা যেতে পারে। যদি রেফারেন্সড টাইপের জন্য ফলাফল পয়েন্টারটি সঠিকভাবে সংযুক্ত না হয় তবে আচরণটি অপরিজ্ঞাত।
অন্যথায়, যখন আবার ফিরে রূপান্তরিত হয়, ফলাফলটি মূল পয়েন্টারের সমান তুলনা করে। যখন কোনও অবজেক্টের পয়েন্টারকে পয়েন্টারকে একটি অক্ষর টাইপের রূপান্তর করা হয়, ফলাফলটি বস্তুটির সর্বনিম্ন সম্বোধিত বাইটে নির্দেশ করে। ফলাফলের ক্রমবৃদ্ধি, অবজেক্টের আকার পর্যন্ত অবজেক্টের অবশিষ্ট বাইটগুলিতে পয়েন্টার দেয়।

6.5 পার 6 এক্সপ্রেশন

তার সঞ্চিত মানটিতে অ্যাক্সেসের জন্য কোনও বস্তুর কার্যকর ধরণ হ'ল বস্তুর ঘোষিত প্রকার, যদি থাকে। ৮)) যদি কোনও মান কোনও লভালুতে কোনও অক্ষর প্রকার নয় এমন কোনও প্রকারের মাধ্যমে কোনও ঘোষিত প্রকারের মধ্যে কোনও স্ট্রোক করা থাকে, তবে লভালুর প্রকারটি অ্যাক্সেসের জন্য এবং পরবর্তী অ্যাক্সেসের জন্য অবজেক্টের কার্যকর ধরণের হয়ে যায় সঞ্চিত মানটি পরিবর্তন করুন। মেমকি বা মেমমোভ ব্যবহার করে কোনও ঘোষিত প্রকারবিহীন কোনও বস্তুতে যদি কোনও মান অনুলিপি করা হয়, বা অক্ষর প্রকারের অ্যারে হিসাবে অনুলিপি করা হয়, তবে সেই অ্যাক্সেসের জন্য এবং পরবর্তী পরিবর্তনগুলিতে মানটি সংশোধন না করে পরিবর্তিত অবজেক্টের কার্যকর ধরণটি হ'ল কার্যকর ধরণের বস্তু যা থেকে মানটি অনুলিপি করা হয়, যদি এটির একটি থাকে। কোনও ঘোষিত প্রকার না থাকা কোনও বস্তুর অন্যান্য সমস্ত অ্যাক্সেসের জন্য, অবজেক্টের কার্যকর ধরণটি অ্যাক্সেসের জন্য ব্যবহৃত লভ্যালের ধরণ।

87) বরাদ্দকৃত বস্তুর কোনও ঘোষিত প্রকার নেই।

আইআইইউসি R_allocএকটি mallocএড ব্লকে একটি অফসেট প্রদান করে যা doubleপ্রান্তিককরণের গ্যারান্টিযুক্ত এবং অফসেটের পরে ব্লকের আকারটি অনুরোধ করা আকারের (আর নির্দিষ্ট ডেটার জন্য অফসেটের আগে বরাদ্দও রয়েছে)। প্রত্যাবর্তনের সময় R_allocপয়েন্টার যে কাস্ট (char *)

বিভাগ 6.2.5 পার 29

অকার্যকর করার জন্য একটি পয়েন্টারের একটি চরিত্রের ধরণের পয়েন্টার হিসাবে একই উপস্থাপনা এবং প্রান্তিককরণের প্রয়োজনীয়তা থাকতে হবে। 48) একইভাবে, সামঞ্জস্যপূর্ণ ধরণের যোগ্য বা অযোগ্য সংস্করণের পয়েন্টারগুলির একই প্রতিনিধিত্ব এবং প্রান্তিককরণের প্রয়োজনীয়তা থাকবে। কাঠামোর ধরণের সমস্ত পয়েন্টারের একে অপরের মতো প্রতিনিধিত্ব এবং প্রান্তিককরণের প্রয়োজনীয়তা থাকতে হবে।
ইউনিয়নের ধরণের সমস্ত পয়েন্টারগুলির একে অপরের মতো প্রতিনিধিত্ব এবং প্রান্তিককরণের প্রয়োজনীয়তা থাকতে হবে।
অন্যান্য ধরণের পয়েন্টারগুলির একই প্রতিনিধিত্ব বা প্রান্তিককরণের প্রয়োজনীয়তা থাকা দরকার না।

৪৮) একই প্রতিনিধিত্ব এবং প্রান্তিককরণের প্রয়োজনীয়তাগুলি হ'ল ফাংশনগুলিতে বিনিময়যোগ্যতা হিসাবে চিহ্নিতকরণ, ফাংশন থেকে মূল্যগুলি ফেরত দেওয়া এবং ইউনিয়নের সদস্যদের বোঝানো।

সুতরাং প্রশ্নটি হ'ল "আমাদের কি এটিকে পুনরায় পোস্ট (char *)করার অনুমতি দেওয়া হয়েছে (const char **)এবং এটি লিখতে হবে (const char **)"? উপরের আমার পড়াটি হ'ল এতক্ষণ সিস্টেমে পয়েন্টার হিসাবে কোড চালিত কোডগুলি সারিবদ্ধকরণের সাথে সামঞ্জস্য করে double, তবে ঠিক আছে।

আমরা কি "কঠোর আলিয়াজিং" লঙ্ঘন করছি? অর্থাৎ,

6.5 পার 7

একটি অবজেক্টের তার সঞ্চিত মানটি কেবলমাত্র একটি মূল্যবান এক্সপ্রেশন দ্বারা অ্যাক্সেস করতে হবে যার নিম্নলিখিত ধরণের একটি রয়েছে: ৮৮)

- বস্তুর কার্যকর ধরণের সাথে সামঞ্জস্যপূর্ণ একটি প্রকার ...

৮৮) এই তালিকার উদ্দেশ্যটি হল সেই পরিস্থিতিতে নির্দিষ্ট করা যা কোনও বস্তুর অ্যালাইজড হতে পারে বা নাও হতে পারে।

সুতরাং, সংকলকটি কী (বা ) দ্বারা নির্দেশিত বস্তুর কার্যকর ধরণটি মনে করে ? সম্ভবত ঘোষিত ধরণটি , বা এটি আসলেই অস্পষ্ট? আমার কাছে এটি অনুভূত হয় যে এটি কেবল এই ক্ষেত্রে নয় কারণ একই বস্তুকে অ্যাক্সেস করার সুযোগের অন্য কোনও 'লভ্যালু' নেই।res.targetres.current(const char **)

আমি স্বীকার করব যে আমি স্ট্যান্ডার্ডের এই বিভাগগুলি থেকে জ্ঞান আহরণের জন্য দৃ m়তার সাথে সংগ্রাম করছি।


যদি ইতিমধ্যে পরীক্ষা না করা হয় তবে এটি ঠিক কী করা হচ্ছে তা নির্বিঘ্নে দেখার মতো হতে পারে। এবং জিসিসি সংস্করণগুলির মধ্যে বিযুক্তির তুলনা করতে।
কায়লুম

2
আমি জিসিসির ট্রাঙ্ক সংস্করণটি নিয়ে গণ্ডগোল করার চেষ্টা করব না। এটি মজা করা ভাল, কিন্তু এটি কারণ হিসাবে ট্রাঙ্ক বলা হয়। দুর্ভাগ্যক্রমে (1) আপনার কোড এবং সঠিক কনফিগারেশন (2) একই আর্কিটেকচারে একই জিসিসি সংস্করণ (3) না থাকলে কী হয়েছে তা বলা প্রায় অসম্ভব। আমি যদি 10.0.1 ট্রাঙ্ক থেকে স্থিতিশীল দিকে চলে যায় তখন এটি স্থির থাকে কিনা তা পরীক্ষা করার পরামর্শ দেব suggest
মার্কো বোনেলি

1
আরও একটি মন্তব্য: -mtune=nativeআপনার মেশিনের নির্দিষ্ট সিপিইউর জন্য অনুকূলিত izes এটি বিভিন্ন পরীক্ষার্থীর জন্য আলাদা হবে এবং এটি ইস্যুটির অংশ হতে পারে। আপনি যদি সংকলনটি চালনা করেন তবে -vআপনার কম্পিউটারে কোন সিপিইউ পরিবার রয়েছে তা দেখতে সক্ষম হওয়া উচিত (যেমন -mtune=skylakeআমার কম্পিউটারে)।
ন্যাট এলেডারেজ

1
ডিবাগ রান থেকে এখনও বলা শক্ত। বিচ্ছিন্নতা চূড়ান্ত হওয়া উচিত। আপনার কোনও কিছুই বের করার দরকার নেই, আপনি প্রকল্পটি সংকলন করার সময় উত্পাদিত .o ফাইলটি সন্ধান করুন এবং এটিকে বিচ্ছিন্ন করে দিন। আপনি disassembleজিডিবির ভিতরে নির্দেশিকাটিও ব্যবহার করতে পারেন ।
ন্যাট এল্ডারেজ

5
যাইহোক, অভিনন্দন, আপনি বিরল কয়েকের একজন যার সমস্যাটি আসলে একটি সংকলক বাগ ছিল।
ন্যাট এল্ডারেজ

উত্তর:


22

সংক্ষিপ্তসার: এটি স্ট্রিং অপ্টিমাইজেশনের সাথে সম্পর্কিত, গিসি-তে একটি বাগ হিসাবে দেখা যাচ্ছে। একটি স্ব-অন্তর্ভুক্ত টেস্টকেস নীচে। কোডটি সঠিক কিনা তা নিয়ে প্রাথমিকভাবে কিছু সন্দেহ ছিল, তবে আমি মনে করি এটি ঠিক।

আমি PR 93982 হিসাবে বাগটি জানিয়েছিপ্রস্তাবিত ফিক্স প্রতিশ্রুতিবদ্ধ হয়েছিল তবে এটি সব ক্ষেত্রেই এটি ঠিক করে না, ফলে পিআরও 94015 ( গডবোল্ট লিঙ্ক ) হয়।

পতাকাটি সংকলন করে আপনার বাগের চারপাশে কাজ করতে সক্ষম হওয়া উচিত -fno-optimize-strlen


আমি আপনার পরীক্ষার কেসটি নিম্নলিখিত সর্বনিম্ন উদাহরণে ( গডবোল্টেও ) হ্রাস করতে সক্ষম হয়েছি :

struct a {
    const char ** target;
};

char* R_alloc(void);

struct a foo(void) {
    struct a res;
    res.target = (const char **) R_alloc();
    res.target[0] = "12345678";
    res.target[1] = "";
    res.target[2] = "";
    res.target[3] = "";
    res.target[4] = "";
    return res;
}

জিসিসি ট্রাঙ্ক (জিসিসি সংস্করণ 10.0.1 20200225 (পরীক্ষামূলক)) এবং -O2(অন্যান্য সমস্ত বিকল্প অপ্রয়োজনীয় বলে প্রমাণিত হয়েছে) সহ, amd64 এ উত্পন্ন সমাবেশটি নিম্নরূপ:

.LC0:
        .string "12345678"
.LC1:
        .string ""
foo:
        subq    $8, %rsp
        call    R_alloc
        movq    $.LC0, (%rax)
        movq    $.LC1, 16(%rax)
        movq    $.LC1, 24(%rax)
        movq    $.LC1, 32(%rax)
        addq    $8, %rsp
        ret

সুতরাং আপনি একদম ঠিক বলেছেন যে সংকলকটি আরম্ভ করতে ব্যর্থ হচ্ছে res.target[1](এর স্পষ্টত অনুপস্থিতিতে নোট করুন movq $.LC1, 8(%rax))।

কোডটি বাজানো এবং "বাগ" কে কী প্রভাবিত করে তা দেখতে আকর্ষণীয়। সম্ভবত উল্লেখযোগ্যভাবে এর রিটার্ন টাইপ পরিবর্তন R_allocকরার void *তোলে যাচ্ছি, আর আপনি "সঠিক" সমাবেশ আউটপুট দেয়। সম্ভবত কম তাৎপর্যযুক্ত তবে আরও মজাদারভাবে, স্ট্রিংটি "12345678"দীর্ঘতর বা সংক্ষিপ্ত আকারে পরিবর্তন করা এটিকে দূরে সরিয়ে দেয়।


পূর্ববর্তী আলোচনা, এখন সমাধান - কোড স্পষ্টতই আইনী legal

আমার প্রশ্নটি আপনার কোডটি আসলে আইনী কিনা। সত্য যে আপনি নিতে char *দ্বারা ফিরে R_alloc()এবং সামনে ছুঁড়ে const char **, এবং তারপর সংরক্ষণ একটি const char *দেখে মনে হচ্ছে এটা লঙ্ঘন পারে কঠোর এলিয়াসিং নিয়ম , যেমন charএবং const char *সামঞ্জস্যপূর্ণ ধরনের নয়। একটি ব্যতিক্রম রয়েছে যা আপনাকে char( যেমন জিনিস বাস্তবায়নের জন্য memcpy) হিসাবে কোনও বস্তু অ্যাক্সেস করার অনুমতি দেয় তবে এটি অন্য উপায়, এবং সর্বোপরি আমি এটি বুঝতে পারি, এটি অনুমোদিত নয়। এটি আপনার কোডকে অপরিবর্তিত আচরণ তৈরি করে এবং তাই সংকলক আইন অনুযায়ী আইনী যা করতে পারেন তা হ্যাক যা চান তা করতে পারে।

এটি যদি হয় তবে সঠিক ফিক্সটি আর এর কোড পরিবর্তন করার জন্য হবে যাতে পরিবর্তে R_alloc()ফিরে আসে । তাহলে কোনও এলিয়াসিং সমস্যা হবে না। দুর্ভাগ্যক্রমে, এই কোডটি আপনার নিয়ন্ত্রণের বাইরে, এবং আপনি কীভাবে কঠোর অ্যালাইজিং লঙ্ঘন না করে এই ফাংশনটি কীভাবে ব্যবহার করতে পারবেন তা আমার কাছে স্পষ্ট নয়। একটি কাজের অস্তিত্ব হতে পারে একটি অস্থায়ী পরিবর্তনশীলকে অন্তর্ভুক্ত করা, উদাহরণস্বরূপ যা পরীক্ষার ক্ষেত্রে সমস্যাটি সমাধান করে তবে আমি আইনী কিনা তা এখনও নিশ্চিত নই।void *char *void *tmp = R_alloc(); res.target = tmp;

তবে, আমি এই "কঠোর আলিয়াজিং" হাইপোথিসিস সম্পর্কে নিশ্চিত নই, কারণ সংকলন -fno-strict-aliasing, যা এএফএআইসির দ্বারা জিসিসি যেমন নির্মাণের অনুমতি দেয়, সমস্যাটি দূরে সরিয়ে দেয় না !


হালনাগাদ. কিছু ভিন্ন বিকল্প চেষ্টা করে, আমি দেখতে পেয়েছি যে হয় -fno-optimize-strlenবা -fno-tree-forwprop"সঠিক" কোড তৈরির ফলস্বরূপ। এছাড়াও, ব্যবহার -O1 -foptimize-strlenকরে ভুল কোড দেয় (তবে -O1 -ftree-forwpropতা দেয় না)।

কিছুটা git bisectঅনুশীলন করার পরে , ত্রুটিটি প্রতিশ্রুতিবদ্ধভাবে 34fcf41e30ff56155e996f5e04 তে প্রবর্তিত হয়েছে বলে মনে হয় ।


আপডেট ২. আমি কী শিখতে পারি তা দেখার জন্য আমি জিসিসি উত্সটিতে কিছুটা খনন করার চেষ্টা করেছি। (আমি কোনও ধরণের সংকলক বিশেষজ্ঞ হিসাবে দাবি করি না!)

দেখে মনে হচ্ছে কোডটি কোডটি tree-ssa-strlen.cপ্রোগ্রামে উপস্থিত স্ট্রিংগুলির ট্র্যাক রাখা। আমি যতটুকু বলতে পারি, ত্রুটিটি হল যে বিবৃতিটি দেখে res.target[0] = "12345678";সংকলক স্ট্রিংয়ের ঠিকানাটি স্ট্রিংয়ের "12345678"সাথেই সংযুক্ত করে। (এটি এই সন্দেহজনক কোডের সাথে সম্পর্কিত বলে মনে হচ্ছে যা পূর্বোক্ত প্রতিশ্রুতিতে যুক্ত হয়েছিল, যেখানে যদি এটি "স্ট্রিং" এর বাইটগুলি প্রকৃতপক্ষে কোনও ঠিকানা হিসাবে গণনা করার চেষ্টা করে, তবে পরিবর্তে সেই ঠিকানাটি কী নির্দেশ করে সে দিকে এটি লক্ষ্য করে))

সুতরাং এটি মনে করেন যে বিবৃতি res.target[0] = "12345678", পরিবর্তে জমা করার ঠিকানা এর "12345678"ঠিকানায় res.target, স্ট্রিং, যাতে ঠিকানায় সঞ্চয় করছে খোদ যেন বিবৃতি ছিল strcpy(res.target, "12345678")। সামনে কী আছে তার জন্য দ্রষ্টব্য যে এর ফলাফলের পিছনে নুলটি ঠিকানায় সংরক্ষণ করা হবে res.target+8(সংকলকের এই পর্যায়ে, সমস্ত অফসেট বাইটে রয়েছে)।

সংকলকটি যখন দেখে res.target[1] = "", এটি একইভাবে এটির মতো আচরণ করে তবে এটি strcpy(res.target+8, "")8 এর আকার থেকে আসছে char *। এটি, যেন এটি কেবল ঠিকানায় কোনও নুল বাইট সংরক্ষণ করে res.target+8। তবে, সংকলকটি "জানে" যে পূর্ববর্তী বিবৃতি ইতিমধ্যে সেই ঠিকানায় একটি নুল বাইট সংরক্ষণ করেছিল! এই হিসাবে, এই বিবৃতিটি "রিডানডান্ট" এবং এটি বাতিল করতে পারেন ( এখানে )।

এটি ব্যাখ্যা করে যে বাগটি ট্রিগার করতে কেন স্ট্রিংটি হ'ল 8 অক্ষর দীর্ঘ হতে হবে। (যদিও 8 এর অন্যান্য গুণক অন্যান্য পরিস্থিতিতেও বাগটি ট্রিগার করতে পারে))


বিভিন্ন ধরণের পয়েন্টারের কাছে FWIW পুনরায় কাটা নথিভুক্ত করা হয় । পুনরায় আবৃত্তি করা ঠিক আছে কি না তা জানার জন্য আমি আলিয়াসিং সম্পর্কে জানি int*না const char**
ব্রোডিজি

যদি কড়া আলিয়াজিং সম্পর্কে আমার ধারণাটি সঠিক হয় তবে কাস্ট করাটিও int *অবৈধ (বা বরং আসলে intসেখানে সংরক্ষণ করা অবৈধ)।
নাট এল্ডারেজ

1
কড়া আলিয়াজিং নিয়মের সাথে এর কোনও যোগসূত্র নেই। কঠোর অ্যালাইজিং নিয়মটি আপনি ইতিমধ্যে বিভিন্ন হ্যান্ডেল ব্যবহার করে সঞ্চয় করা ডেটা অ্যাক্সেস সম্পর্কে । আপনি কেবল এখানে নিয়োগ হিসাবে, এটি কঠোর aliasing নিয়ম স্পর্শ করে না। উভয় পয়েন্টার ধরণের একই প্রান্তিককরণের প্রয়োজনীয়তা থাকলে কাস্টিং পয়েন্টারগুলি বৈধ, তবে এখানে আপনি x86_64 থেকে কাস্ট করছেন এবং কাজ করছেন ... আমি এখানে কোনও ইউবি দেখছি না, এটি জিসিসি বাগ। char*
কামিলকুক

1
হ্যাঁ এবং না, @ কামিলকুক। স্ট্যান্ডার্ডের পরিভাষায়, "অ্যাক্সেসিং" কোনও অবজেক্টের মান পড়া এবং পরিবর্তন করা উভয়কেই অন্তর্ভুক্ত করে। কঠোর আলিয়াজিং বিধি "স্টোরিং" এর সাথে কথা বলে। এটি রিড-ব্যাক অপারেশনগুলির মধ্যে সীমাবদ্ধ নয়। কিন্তু কোন ঘোষিত ধরন, আসলে যে যেমন একটি বস্তু লিখিতভাবে স্বয়ংক্রিয়ভাবে দ্বারা আলোচিত হয় অবজেক্টের জন্য পরিবর্তন কি লেখা ছিল মিলা তার কার্যকর প্রকার। ঘোষিত প্রকারবিহীন অবজেক্টগুলি হ'ল গতিশীলভাবে বরাদ্দকৃত (পয়েন্টার যে ধরণের দ্বারা তারা অ্যাক্সেস করে তা নির্বিশেষে), সুতরাং এখানে কোনও এসএ লঙ্ঘন নেই।
জন বলিঞ্জার

2
হ্যাঁ, @ নেটে, সেই সংজ্ঞার সাথে R_alloc()প্রোগ্রামটি অনুবাদ R_alloc()করছে, অনুবাদ ইউনিট নির্ধারণ না করেই । এটি সংকলক যা এখানে মেনে চলতে ব্যর্থ।
জন বলিঞ্জার
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.